Skip to content

Commit 0c5c153

Browse files
committed
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
1 parent 94c0082 commit 0c5c153

File tree

2 files changed

+18
-5
lines changed

2 files changed

+18
-5
lines changed

include/rapidjson/allocators.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,9 @@ class MemoryPoolAllocator {
160160

161161
//! Allocates a memory block. (concept Allocator)
162162
void* Malloc(size_t size) {
163+
if (!size)
164+
return NULL;
165+
163166
size = RAPIDJSON_ALIGN(size);
164167
if (chunkHead_ == 0 || chunkHead_->size + size > chunkHead_->capacity)
165168
AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size);
@@ -191,7 +194,9 @@ class MemoryPoolAllocator {
191194
// Realloc process: allocate and copy memory, do not free original buffer.
192195
void* newBuffer = Malloc(newSize);
193196
RAPIDJSON_ASSERT(newBuffer != 0); // Do not handle out-of-memory explicitly.
194-
return std::memcpy(newBuffer, originalPtr, originalSize);
197+
if (originalSize)
198+
std::memcpy(newBuffer, originalPtr, originalSize);
199+
return newBuffer;
195200
}
196201

197202
//! Frees a memory block (concept Allocator)

include/rapidjson/document.h

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1582,16 +1582,24 @@ class GenericValue {
15821582
// Initialize this value as array with initial data, without calling destructor.
15831583
void SetArrayRaw(GenericValue* values, SizeType count, Allocator& allocator) {
15841584
flags_ = kArrayFlag;
1585-
data_.a.elements = (GenericValue*)allocator.Malloc(count * sizeof(GenericValue));
1586-
std::memcpy(data_.a.elements, values, count * sizeof(GenericValue));
1585+
if (count) {
1586+
data_.a.elements = (GenericValue*)allocator.Malloc(count * sizeof(GenericValue));
1587+
std::memcpy(data_.a.elements, values, count * sizeof(GenericValue));
1588+
}
1589+
else
1590+
data_.a.elements = NULL;
15871591
data_.a.size = data_.a.capacity = count;
15881592
}
15891593

15901594
//! Initialize this value as object with initial data, without calling destructor.
15911595
void SetObjectRaw(Member* members, SizeType count, Allocator& allocator) {
15921596
flags_ = kObjectFlag;
1593-
data_.o.members = (Member*)allocator.Malloc(count * sizeof(Member));
1594-
std::memcpy(data_.o.members, members, count * sizeof(Member));
1597+
if (count) {
1598+
data_.o.members = (Member*)allocator.Malloc(count * sizeof(Member));
1599+
std::memcpy(data_.o.members, members, count * sizeof(Member));
1600+
}
1601+
else
1602+
data_.o.members = NULL;
15951603
data_.o.size = data_.o.capacity = count;
15961604
}
15971605

0 commit comments

Comments
 (0)