Avoid calling memcpy with NULL pointers
According to the C/C++ standards, calling `memcpy(NULL, NULL, 0)` is undefined behaviour. Recent GCC versions may rely on this by optimizing NULL pointer checks more aggressively, see [1]. This patch tries to avoid calling std::memcpy with zero elements. As a side effect, explicitly return NULL when requesting an empty block from MemoryPoolAllocator::Malloc. This may be related to #301. [1] https://gcc.gnu.org/gcc-4.9/porting_to.html
This commit is contained in:
parent
94c0082e38
commit
0c5c1538dc
@ -160,6 +160,9 @@ public:
|
|||||||
|
|
||||||
//! Allocates a memory block. (concept Allocator)
|
//! Allocates a memory block. (concept Allocator)
|
||||||
void* Malloc(size_t size) {
|
void* Malloc(size_t size) {
|
||||||
|
if (!size)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
size = RAPIDJSON_ALIGN(size);
|
size = RAPIDJSON_ALIGN(size);
|
||||||
if (chunkHead_ == 0 || chunkHead_->size + size > chunkHead_->capacity)
|
if (chunkHead_ == 0 || chunkHead_->size + size > chunkHead_->capacity)
|
||||||
AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size);
|
AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size);
|
||||||
@ -191,7 +194,9 @@ public:
|
|||||||
// Realloc process: allocate and copy memory, do not free original buffer.
|
// Realloc process: allocate and copy memory, do not free original buffer.
|
||||||
void* newBuffer = Malloc(newSize);
|
void* newBuffer = Malloc(newSize);
|
||||||
RAPIDJSON_ASSERT(newBuffer != 0); // Do not handle out-of-memory explicitly.
|
RAPIDJSON_ASSERT(newBuffer != 0); // Do not handle out-of-memory explicitly.
|
||||||
return std::memcpy(newBuffer, originalPtr, originalSize);
|
if (originalSize)
|
||||||
|
std::memcpy(newBuffer, originalPtr, originalSize);
|
||||||
|
return newBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Frees a memory block (concept Allocator)
|
//! Frees a memory block (concept Allocator)
|
||||||
|
@ -1582,16 +1582,24 @@ private:
|
|||||||
// Initialize this value as array with initial data, without calling destructor.
|
// Initialize this value as array with initial data, without calling destructor.
|
||||||
void SetArrayRaw(GenericValue* values, SizeType count, Allocator& allocator) {
|
void SetArrayRaw(GenericValue* values, SizeType count, Allocator& allocator) {
|
||||||
flags_ = kArrayFlag;
|
flags_ = kArrayFlag;
|
||||||
data_.a.elements = (GenericValue*)allocator.Malloc(count * sizeof(GenericValue));
|
if (count) {
|
||||||
std::memcpy(data_.a.elements, values, count * sizeof(GenericValue));
|
data_.a.elements = (GenericValue*)allocator.Malloc(count * sizeof(GenericValue));
|
||||||
|
std::memcpy(data_.a.elements, values, count * sizeof(GenericValue));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
data_.a.elements = NULL;
|
||||||
data_.a.size = data_.a.capacity = count;
|
data_.a.size = data_.a.capacity = count;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Initialize this value as object with initial data, without calling destructor.
|
//! Initialize this value as object with initial data, without calling destructor.
|
||||||
void SetObjectRaw(Member* members, SizeType count, Allocator& allocator) {
|
void SetObjectRaw(Member* members, SizeType count, Allocator& allocator) {
|
||||||
flags_ = kObjectFlag;
|
flags_ = kObjectFlag;
|
||||||
data_.o.members = (Member*)allocator.Malloc(count * sizeof(Member));
|
if (count) {
|
||||||
std::memcpy(data_.o.members, members, count * sizeof(Member));
|
data_.o.members = (Member*)allocator.Malloc(count * sizeof(Member));
|
||||||
|
std::memcpy(data_.o.members, members, count * sizeof(Member));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
data_.o.members = NULL;
|
||||||
data_.o.size = data_.o.capacity = count;
|
data_.o.size = data_.o.capacity = count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user