diff --git a/src/evhelper.cpp b/src/evhelper.cpp index 335a9e9..21dc010 100644 --- a/src/evhelper.cpp +++ b/src/evhelper.cpp @@ -337,6 +337,7 @@ bool EvOutBuf::refill(size_t more) bool EvInBuf::refill(size_t more) { if(err) return false; + size_t len = size(); // unconsumed before request if(base && evbuffer_drain(backing, pos-base)) throw std::bad_alloc(); @@ -344,8 +345,13 @@ bool EvInBuf::refill(size_t more) limit = base = pos = nullptr; if(more) { + // ensure new segment contains at least the requested size (one element) + // (we hope this is mostly a no-op) + (void)evbuffer_pullup(backing, len+more); + evbuffer_iovec vec; + // peek at the next segment auto n = evbuffer_peek(backing, -1, nullptr, &vec, 1); if(n<=0) { // current (2.1) impl never returns negative return false; @@ -353,6 +359,10 @@ bool EvInBuf::refill(size_t more) base = pos = (uint8_t*)vec.iov_base; limit = base+vec.iov_len; + + if(size() < len+more) { + return false; // pullup didn't work. + } } return true; } diff --git a/src/pvaproto.h b/src/pvaproto.h index 91731fc..8fcf2b0 100644 --- a/src/pvaproto.h +++ b/src/pvaproto.h @@ -59,6 +59,7 @@ public: pos = limit; i -= size(); } while(static_cast(this)->refill(i)); + fault(); } EPICS_ALWAYS_INLINE bool empty() const { return limit==pos; } @@ -305,7 +306,7 @@ inline void _to_wire(Buf& buf, const uint8_t *mem, bool reverse) * @param buf output buffer. buf[0] through buf[sizeof(T)-1] must be valid. * @param val input variable */ -template::value, int>::type =0> +template=2 && std::is_scalar{} && !std::is_pointer{}, int>::type =0> inline void to_wire(Buf& buf, const T& val) { union { @@ -316,6 +317,16 @@ inline void to_wire(Buf& buf, const T& val) _to_wire(buf, pun.b, buf.be ^ (EPICS_BYTE_ORDER==EPICS_ENDIAN_BIG)); } +template{}, int>::type =0> +inline void to_wire(Buf& buf, const T& val) +{ + if(!buf.ensure(1)) { + buf.fault(); + } else { + buf.push(val); + } +} + template void to_wire(Buf& buf, const Size& size) { @@ -349,6 +360,12 @@ void to_wire(Buf& buf, const char *s) } +template +inline void to_wire(Buf& buf, const std::string& s) +{ + to_wire(buf, s.c_str()); +} + template void to_wire(Buf& buf, std::initializer_list bytes) { diff --git a/src/pvxs/unittest.h b/src/pvxs/unittest.h index 1daae32..33ca6a8 100644 --- a/src/pvxs/unittest.h +++ b/src/pvxs/unittest.h @@ -13,7 +13,9 @@ */ #include +#include #include +#include #include #include @@ -57,7 +59,7 @@ public: namespace detail { // control how testEq() and testNotEq() print things -template +template struct test_print { template static inline void op(C& strm, const T& v) { @@ -78,6 +80,13 @@ struct test_print { strm<<'"'< +struct test_print, typename std::enable_if::type> { + template + static inline void op(C& strm, const std::vector& v) { + strm<<'"'< testCase testEq(const char *sLHS, const LHS& lhs, const char *sRHS, const RHS& rhs) diff --git a/src/pvxs/util.h b/src/pvxs/util.h index e441094..7fdb04c 100644 --- a/src/pvxs/util.h +++ b/src/pvxs/util.h @@ -26,9 +26,11 @@ namespace detail { class Escaper { const char* val; + size_t count; friend std::ostream& operator<<(std::ostream& strm, const Escaper& esc); public: - constexpr explicit Escaper(const char* v) :val(v) {} + PVXS_API explicit Escaper(const char* v); + constexpr explicit Escaper(const char* v, size_t l) :val(v),count(l) {} }; PVXS_API @@ -42,7 +44,7 @@ std::ostream& operator<<(std::ostream& strm, const Escaper& esc); //! std::cout<"; } else { - for(; *s; s++) { + for(size_t n=0; n