aboutsummaryrefslogtreecommitdiff
path: root/src/serialize.h
diff options
context:
space:
mode:
authorWladimir J. van der Laan <laanwj@gmail.com>2014-06-05 10:10:52 +0200
committerWladimir J. van der Laan <laanwj@gmail.com>2014-06-23 10:38:15 +0200
commitfa126effc2a03e22708960344e62fc21259deb23 (patch)
treebb21fb6b131efe0dd5448765c5240ba208d54945 /src/serialize.h
parent52d4abfdef93cd622b297a092eb6639e678bcb9d (diff)
Avoid undefined behavior using CFlatData in CScript serialization
`&vch[vch.size()]` and even `&vch[0]` on vectors can cause assertion errors with VC in debug mode. This is the problem mentioned in #4239. The deeper problem with this is that we rely on undefined behavior. - Add `begin_ptr` and `end_ptr` functions that get the beginning and end pointer of vector in a reliable way that copes with empty vectors and doesn't reference outside the vector (see https://stackoverflow.com/questions/1339470/how-to-get-the-address-of-the-stdvector-buffer-start-most-elegantly/1339767#1339767). - Add a convenience constructor to CFlatData that wraps a vector. I added `begin_ptr` and `end_ptr` as separate functions as I imagine they will be useful in more places.
Diffstat (limited to 'src/serialize.h')
-rw-r--r--src/serialize.h34
1 files changed, 34 insertions, 0 deletions
diff --git a/src/serialize.h b/src/serialize.h
index 1341746592..5ac85554c6 100644
--- a/src/serialize.h
+++ b/src/serialize.h
@@ -37,6 +37,34 @@ inline T& REF(const T& val)
return const_cast<T&>(val);
}
+/** Get begin pointer of vector (non-const version).
+ * @note These functions avoid the undefined case of indexing into an empty
+ * vector, as well as that of indexing after the end of the vector.
+ */
+template <class T, class TAl>
+inline T* begin_ptr(std::vector<T,TAl>& v)
+{
+ return v.empty() ? NULL : &v[0];
+}
+/** Get begin pointer of vector (const version) */
+template <class T, class TAl>
+inline const T* begin_ptr(const std::vector<T,TAl>& v)
+{
+ return v.empty() ? NULL : &v[0];
+}
+/** Get end pointer of vector (non-const version) */
+template <class T, class TAl>
+inline T* end_ptr(std::vector<T,TAl>& v)
+{
+ return v.empty() ? NULL : (&v[0] + v.size());
+}
+/** Get end pointer of vector (const version) */
+template <class T, class TAl>
+inline const T* end_ptr(const std::vector<T,TAl>& v)
+{
+ return v.empty() ? NULL : (&v[0] + v.size());
+}
+
/////////////////////////////////////////////////////////////////
//
// Templates for serializing to anything that looks like a stream,
@@ -318,6 +346,12 @@ protected:
char* pend;
public:
CFlatData(void* pbeginIn, void* pendIn) : pbegin((char*)pbeginIn), pend((char*)pendIn) { }
+ template <class T, class TAl>
+ explicit CFlatData(std::vector<T,TAl> &v)
+ {
+ pbegin = (char*)begin_ptr(v);
+ pend = (char*)end_ptr(v);
+ }
char* begin() { return pbegin; }
const char* begin() const { return pbegin; }
char* end() { return pend; }