Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clang Static Analyzer complain about null pointer dereference #1651

Open
reddwarf69 opened this issue Feb 28, 2020 · 1 comment
Open

Clang Static Analyzer complain about null pointer dereference #1651

reddwarf69 opened this issue Feb 28, 2020 · 1 comment

Comments

@reddwarf69
Copy link

Using the latest master with

#include <rapidjson/document.h>

int main() {
    auto json = rapidjson::Document{ rapidjson::kObjectType };
    json.AddMember("a", "b", json.GetAllocator());
}

results in the following warning from Clang Static Analyzer

/home/reddwarf/tmp/rapidjson_test/rapidjson/include/rapidjson/internal/../allocators.h:219:106: warning: Access to field 'size' results in a dereference of a null pointer (loaded from field 'chunkHead_') [clang-analyzer-core.NullDereference]
        if (originalPtr == reinterpret_cast<char *>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size - originalSize) {
                                                                                                         ^
main.cpp:4:17: note: Calling constructor for 'GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>'
    auto json = rapidjson::Document{ rapidjson::kObjectType };
                ^
/home/reddwarf/tmp/rapidjson_test/rapidjson/include/rapidjson/document.h:2212:13: note: Field 'allocator_' is null
        if (!allocator_)
            ^
/home/reddwarf/tmp/rapidjson_test/rapidjson/include/rapidjson/document.h:2212:9: note: Taking true branch
        if (!allocator_)
        ^
/home/reddwarf/tmp/rapidjson_test/rapidjson/include/rapidjson/document.h:2213:56: note: Calling default constructor for 'MemoryPoolAllocator<rapidjson::CrtAllocator>'
            ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();
                                                       ^
/home/reddwarf/tmp/rapidjson_test/rapidjson/include/rapidjson/error/../rapidjson.h:647:37: note: expanded from macro 'RAPIDJSON_NEW'
#define RAPIDJSON_NEW(TypeName) new TypeName
                                    ^
/home/reddwarf/tmp/rapidjson_test/rapidjson/include/rapidjson/internal/../allocators.h:124:9: note: Null pointer value stored to field 'chunkHead_'
        chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
        ^
/home/reddwarf/tmp/rapidjson_test/rapidjson/include/rapidjson/document.h:2213:56: note: Returning from default constructor for 'MemoryPoolAllocator<rapidjson::CrtAllocator>'
            ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();
                                                       ^
/home/reddwarf/tmp/rapidjson_test/rapidjson/include/rapidjson/error/../rapidjson.h:647:37: note: expanded from macro 'RAPIDJSON_NEW'
#define RAPIDJSON_NEW(TypeName) new TypeName
                                    ^
main.cpp:4:17: note: Returning from constructor for 'GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>'
    auto json = rapidjson::Document{ rapidjson::kObjectType };
                ^
main.cpp:5:5: note: Calling 'GenericValue::AddMember'
    json.AddMember("a", "b", json.GetAllocator());
    ^
/home/reddwarf/tmp/rapidjson_test/rapidjson/include/rapidjson/document.h:1470:16: note: Calling 'GenericValue::AddMember'
        return AddMember(name, v, allocator);
               ^
/home/reddwarf/tmp/rapidjson_test/rapidjson/include/rapidjson/document.h:1456:16: note: Calling 'GenericValue::AddMember'
        return AddMember(n, value, allocator);
               ^
/home/reddwarf/tmp/rapidjson_test/rapidjson/include/rapidjson/document.h:1360:9: note: '?' condition is true
        RAPIDJSON_ASSERT(IsObject());
        ^
/home/reddwarf/tmp/rapidjson_test/rapidjson/include/rapidjson/error/../rapidjson.h:406:29: note: expanded from macro 'RAPIDJSON_ASSERT'
#define RAPIDJSON_ASSERT(x) assert(x)
                            ^
/usr/include/assert.h:90:7: note: expanded from macro 'assert'
     (static_cast <bool> (expr)                                         \
      ^
/home/reddwarf/tmp/rapidjson_test/rapidjson/include/rapidjson/document.h:1361:9: note: '?' condition is true
        RAPIDJSON_ASSERT(name.IsString());
        ^
/home/reddwarf/tmp/rapidjson_test/rapidjson/include/rapidjson/error/../rapidjson.h:406:29: note: expanded from macro 'RAPIDJSON_ASSERT'
#define RAPIDJSON_ASSERT(x) assert(x)
                            ^
/usr/include/assert.h:90:7: note: expanded from macro 'assert'
     (static_cast <bool> (expr)                                         \
      ^
/home/reddwarf/tmp/rapidjson_test/rapidjson/include/rapidjson/document.h:1364:13: note: Assuming field 'size' is >= field 'capacity'
        if (o.size >= o.capacity)
            ^
/home/reddwarf/tmp/rapidjson_test/rapidjson/include/rapidjson/document.h:1364:9: note: Taking true branch
        if (o.size >= o.capacity)
        ^
/home/reddwarf/tmp/rapidjson_test/rapidjson/include/rapidjson/document.h:1365:27: note: Assuming field 'capacity' is equal to 0
            MemberReserve(o.capacity == 0 ? kDefaultObjectCapacity : (o.capacity + (o.capacity + 1) / 2), allocator);
                          ^
/home/reddwarf/tmp/rapidjson_test/rapidjson/include/rapidjson/document.h:1365:27: note: '?' condition is true
/home/reddwarf/tmp/rapidjson_test/rapidjson/include/rapidjson/document.h:1365:13: note: Calling 'GenericValue::MemberReserve'
            MemberReserve(o.capacity == 0 ? kDefaultObjectCapacity : (o.capacity + (o.capacity + 1) / 2), allocator);
            ^
/home/reddwarf/tmp/rapidjson_test/rapidjson/include/rapidjson/document.h:1251:9: note: '?' condition is true
        RAPIDJSON_ASSERT(IsObject());
        ^
/home/reddwarf/tmp/rapidjson_test/rapidjson/include/rapidjson/error/../rapidjson.h:406:29: note: expanded from macro 'RAPIDJSON_ASSERT'
#define RAPIDJSON_ASSERT(x) assert(x)
                            ^
/usr/include/assert.h:90:7: note: expanded from macro 'assert'
     (static_cast <bool> (expr)                                         \
      ^
/home/reddwarf/tmp/rapidjson_test/rapidjson/include/rapidjson/document.h:1252:13: note: Assuming 'newCapacity' is > field 'capacity'
        if (newCapacity > data_.o.capacity) {
            ^
/home/reddwarf/tmp/rapidjson_test/rapidjson/include/rapidjson/document.h:1252:9: note: Taking true branch
        if (newCapacity > data_.o.capacity) {
        ^
/home/reddwarf/tmp/rapidjson_test/rapidjson/include/rapidjson/document.h:1253:57: note: Calling 'MemoryPoolAllocator::Realloc'
            SetMembersPointer(reinterpret_cast<Member*>(allocator.Realloc(GetMembersPointer(), data_.o.capacity * sizeof(Member), newCapacity * sizeof(Member))));
                                                        ^
/home/reddwarf/tmp/rapidjson_test/rapidjson/include/rapidjson/internal/../allocators.h:205:13: note: Assuming 'originalPtr' is not equal to null
        if (originalPtr == 0)
            ^
/home/reddwarf/tmp/rapidjson_test/rapidjson/include/rapidjson/internal/../allocators.h:205:9: note: Taking false branch
        if (originalPtr == 0)
        ^
/home/reddwarf/tmp/rapidjson_test/rapidjson/include/rapidjson/internal/../allocators.h:208:13: note: 'newSize' is not equal to 0
        if (newSize == 0)
            ^
/home/reddwarf/tmp/rapidjson_test/rapidjson/include/rapidjson/internal/../allocators.h:208:9: note: Taking false branch
        if (newSize == 0)
        ^
/home/reddwarf/tmp/rapidjson_test/rapidjson/include/rapidjson/internal/../allocators.h:215:13: note: Assuming 'originalSize' is < 'newSize'
        if (originalSize >= newSize)
            ^
/home/reddwarf/tmp/rapidjson_test/rapidjson/include/rapidjson/internal/../allocators.h:215:9: note: Taking false branch
        if (originalSize >= newSize)
        ^
/home/reddwarf/tmp/rapidjson_test/rapidjson/include/rapidjson/internal/../allocators.h:219:106: note: Access to field 'size' results in a dereference of a null pointer (loaded from field 'chunkHead_')
        if (originalPtr == reinterpret_cast<char *>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size - originalSize) {

Not sure if if has found any actual error. But if it isn't real, being a popular tool, it may make sense to try to silence the warning.

@reddwarf69
Copy link
Author

reddwarf69 commented Feb 28, 2020

FWIW AFAIK the error is not real. The issue is reported in https://bugs.llvm.org/show_bug.cgi?id=45059.

This still affects anybody using the latest clang version with either RapidJSON 1.1.0 or master, though. It can be silenced with:

diff --git a/include/rapidjson/allocators.h b/include/rapidjson/allocators.h
index cc67c897..e02a59d7 100644
--- a/include/rapidjson/allocators.h
+++ b/include/rapidjson/allocators.h
@@ -205,6 +205,8 @@ public:
         if (originalPtr == 0)
             return Malloc(newSize);
 
+        RAPIDJSON_ASSERT(chunkHead_ != 0);
+
         if (newSize == 0)
             return NULL;
 

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant