mirror of
https://github.com/bitcoin/bitcoin.git
synced 2024-11-20 10:38:42 +01:00
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.
This commit is contained in:
parent
52d4abfdef
commit
fa126effc2
@ -770,12 +770,12 @@ public:
|
|||||||
void Serialize(Stream &s, int nType, int nVersion) const {
|
void Serialize(Stream &s, int nType, int nVersion) const {
|
||||||
std::vector<unsigned char> compr;
|
std::vector<unsigned char> compr;
|
||||||
if (Compress(compr)) {
|
if (Compress(compr)) {
|
||||||
s << CFlatData(&compr[0], &compr[compr.size()]);
|
s << CFlatData(compr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
unsigned int nSize = script.size() + nSpecialScripts;
|
unsigned int nSize = script.size() + nSpecialScripts;
|
||||||
s << VARINT(nSize);
|
s << VARINT(nSize);
|
||||||
s << CFlatData(&script[0], &script[script.size()]);
|
s << CFlatData(script);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Stream>
|
template<typename Stream>
|
||||||
@ -784,13 +784,13 @@ public:
|
|||||||
s >> VARINT(nSize);
|
s >> VARINT(nSize);
|
||||||
if (nSize < nSpecialScripts) {
|
if (nSize < nSpecialScripts) {
|
||||||
std::vector<unsigned char> vch(GetSpecialSize(nSize), 0x00);
|
std::vector<unsigned char> vch(GetSpecialSize(nSize), 0x00);
|
||||||
s >> REF(CFlatData(&vch[0], &vch[vch.size()]));
|
s >> REF(CFlatData(vch));
|
||||||
Decompress(nSize, vch);
|
Decompress(nSize, vch);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
nSize -= nSpecialScripts;
|
nSize -= nSpecialScripts;
|
||||||
script.resize(nSize);
|
script.resize(nSize);
|
||||||
s >> REF(CFlatData(&script[0], &script[script.size()]));
|
s >> REF(CFlatData(script));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -37,6 +37,34 @@ inline T& REF(const T& val)
|
|||||||
return const_cast<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,
|
// Templates for serializing to anything that looks like a stream,
|
||||||
@ -318,6 +346,12 @@ protected:
|
|||||||
char* pend;
|
char* pend;
|
||||||
public:
|
public:
|
||||||
CFlatData(void* pbeginIn, void* pendIn) : pbegin((char*)pbeginIn), pend((char*)pendIn) { }
|
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; }
|
char* begin() { return pbegin; }
|
||||||
const char* begin() const { return pbegin; }
|
const char* begin() const { return pbegin; }
|
||||||
char* end() { return pend; }
|
char* end() { return pend; }
|
||||||
|
Loading…
Reference in New Issue
Block a user