Hi, I found a use-after-free bug in the unit test whose root cause can be critical.
Description
The problem is that PushUnsafe in include/rapidjson/internal/stack.h doesn't flush the remained data before it pushes and allocate the new region to the class T.
As you named it PushUnsafe, it could be okay to remain this function as unsafe, but RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) also calls this function without flushing the data.
Thus, any class using this class Stack with Push and Pop will suffer from use-after-free.
Patch
We can patch this by flushing the data with memset before Push.
Detailed Information
OS: Ubuntu 22.04
build command: mkdir build && cd build && cmake ../ && make -j$(nproc)
Inside the constructor of the SchemaDocumentType -> Schema, the SchemaEntry instance is created by the Push method of the class Stack. At the destructor of the SchemaDocumentType, the SchemaEntry instance is freed with the Pop method of the class Stack.
The problem occurs here, because at the second loop, the other SchemaEntry instance is constructed on the lastly popped SchemaEntry instance without flushing. Thus, there occurs use-after-free during the construction of the SchemaEntry from the second loop of the for.
Thank you for investing your valuable time in reviewing this Pull Request! :)
Hi, I found a use-after-free bug in the unit test whose root cause can be critical.
Description
The problem is that PushUnsafe in
include/rapidjson/internal/stack.h
doesn't flush the remained data before it pushes and allocate the new region to the class T.As you named it PushUnsafe, it could be okay to remain this function as unsafe, but RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) also calls this function without flushing the data. Thus, any class using this class Stack with Push and Pop will suffer from use-after-free.
Patch
We can patch this by flushing the data with memset before Push.
Detailed Information
mkdir build && cd build && cmake ../ && make -j$(nproc)
./bin/unittest --gtest_filter=SchemaValidator.TestSuite
At schematest.cpp:2256, the SchemaDocumentType is defined, which ends its lifetime at the end of the current for loop (schematest.cpp:2278).
Inside the constructor of the SchemaDocumentType -> Schema, the SchemaEntry instance is created by the Push method of the class Stack. At the destructor of the SchemaDocumentType, the SchemaEntry instance is freed with the Pop method of the class Stack.
The problem occurs here, because at the second loop, the other SchemaEntry instance is constructed on the lastly popped SchemaEntry instance without flushing. Thus, there occurs use-after-free during the construction of the SchemaEntry from the second loop of the for.
Thank you for investing your valuable time in reviewing this Pull Request! :)