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

Valgrind: Invalid read when using JSON Schema validation, only with "dependencies" feature #2298

Open
davidbisegna opened this issue Aug 13, 2024 · 0 comments

Comments

@davidbisegna
Copy link

davidbisegna commented Aug 13, 2024

Hello,

I am currently working with RapidJSON, in a private company, hence I cannot share too much details.
Before starting, i'll let you know that we bumped from using 1.1.0 release (7 years ago), to commit hash f9d5341, which is 1 year old.

Still, we have a bunch of test that are testing different schema feature ("testMultipleOf", "testMinMax", "testExclusiveMinMax", "testPatternProperties", and so on ...)
All of these are fine, apart from one that is :

"testDependencies": {
        "type": "object",
        "properties": {
            "first": {"type": "integer"},
            "second": {"type": "integer"}
        },
        "dependencies": {
        "first": ["second"]
    }
}

As soon the "dependencies" key is there, we are getting some invalid reads as output of Valgrind.
C++ Version: C++23
Valgrind version: 3.23.0
Checking with the following stack trace (in which I replaced the library name):

==120993== Invalid read of size 4
==120993==    at 0x49D902D: rapidjson::GenericPointer<rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >::CopyFromRaw(rapidjson::GenericPointer<rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> > const&, unsigned long, unsigned long) (pointer.h:881)
==120993==    by 0x49EA73C: rapidjson::GenericPointer<rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >::Append(rapidjson::GenericPointer<rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >::Token const&, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>*) const (pointer.h:238)
==120993==    by 0x49EA425: rapidjson::GenericPointer<rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >::Append(char const*, unsigned int, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>*) const (pointer.h:255)
==120993==    by 0x49F2053: rapidjson::GenericSchemaValidator<rapidjson::GenericSchemaDocument<rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >, rapidjson::BaseReaderHandler<rapidjson::UTF8<char>, void>, rapidjson::CrtAllocator>::EndMissingDependentProperties(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> > const&) (schema.h:2708)
==120993==    by 0x49C742F: rapidjson::internal::Schema<rapidjson::GenericSchemaDocument<rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> > >::EndObject(rapidjson::internal::SchemaValidationContext<rapidjson::GenericSchemaDocument<rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> > >&, unsigned int) const (schema.h:1193)
==120993==    by 0x49C2F87: rapidjson::GenericSchemaValidator<rapidjson::GenericSchemaDocument<rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >, rapidjson::BaseReaderHandler<rapidjson::UTF8<char>, void>, rapidjson::CrtAllocator>::EndObject(unsigned int) (schema.h:2868)
==120993==    by 0x49BE30F: xxx::validation::JsonSchemaValidatorVisitor::visitContainer(xxx::PrivateLib const&) (JsonSchemaValidator.cpp:197)
==120993==    by 0x49C071F: xxx::validation::JsonSchemaValidatorVisitor::visitEntry(xxx::PrivateLib::Entry const&, bool) (JsonSchemaValidator.cpp:266)
....
==120993==  Address 0x9607e50 is 96 bytes inside a block of size 65,560 free'd
==120993==    at 0x484186B: free (in /opt/1A/toolchain/x86_64-v23.0.25/build-pack/23.0.25.2/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==120993==    by 0x49A3CA1: rapidjson::CrtAllocator::Free(void*) (allocators.h:100)
==120993==    by 0x49CF07A: rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>::Clear() (allocators.h:285)
==120993==    by 0x49C8AC0: rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>::~MemoryPoolAllocator() (allocators.h:268)
==120993==    by 0x49C4B4E: rapidjson::GenericPointer<rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >::~GenericPointer() (pointer.h:170)
==120993==    by 0x49F1FE1: rapidjson::GenericSchemaValidator<rapidjson::GenericSchemaDocument<rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >, rapidjson::BaseReaderHandler<rapidjson::UTF8<char>, void>, rapidjson::CrtAllocator>::EndMissingDependentProperties(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> > const&) (schema.h:2707)
==120993==    by 0x49C742F: rapidjson::internal::Schema<rapidjson::GenericSchemaDocument<rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> > >::EndObject(rapidjson::internal::SchemaValidationContext<rapidjson::GenericSchemaDocument<rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> > >&, unsigned int) const (schema.h:1193)
==120993==    by 0x49C2F87: rapidjson::GenericSchemaValidator<rapidjson::GenericSchemaDocument<rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >, rapidjson::BaseReaderHandler<rapidjson::UTF8<char>, void>, rapidjson::CrtAllocator>::EndObject(unsigned int) (schema.h:2868)
==120993==    by 0x49BE30F: xxx::validation::JsonSchemaValidatorVisitor::visitContainer(xxx::PrivateLib const&) (JsonSchemaValidator.cpp:197)
==120993==    by 0x49C071F: xxx::validation::JsonSchemaValidatorVisitor::visitEntry(xxx::PrivateLib::Entry const&, bool) (JsonSchemaValidator.cpp:266)
....
==120993==  Block was alloc'd at
==120993==    at 0x483E744: malloc (in /opt/1A/toolchain/x86_64-v23.0.25/build-pack/23.0.25.2/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==120993==    by 0x49BC26D: rapidjson::CrtAllocator::Malloc(unsigned long) (allocators.h:88)
==120993==    by 0x49D43E9: rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>::AddChunk(unsigned long) (allocators.h:393)
==120993==    by 0x49CFA2B: rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>::Malloc(unsigned long) (allocators.h:328)
==120993==    by 0x49D909D: rapidjson::GenericPointer<rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >::CopyFromRaw(rapidjson::GenericPointer<rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> > const&, unsigned long, unsigned long) (pointer.h:884)
==120993==    by 0x49D62EB: rapidjson::GenericPointer<rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >::operator=(rapidjson::GenericPointer<rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> > const&) (pointer.h:185)
==120993==    by 0x49D3020: rapidjson::GenericPointer<rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >::GenericPointer(rapidjson::GenericPointer<rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> > const&) (pointer.h:158)
==120993==    by 0x49D9636: rapidjson::GenericSchemaValidator<rapidjson::GenericSchemaDocument<rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >, rapidjson::BaseReaderHandler<rapidjson::UTF8<char>, void>, rapidjson::CrtAllocator>::GetInvalidSchemaPointer() const (schema.h:2556)
==120993==    by 0x49F1F9A: rapidjson::GenericSchemaValidator<rapidjson::GenericSchemaDocument<rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >, rapidjson::BaseReaderHandler<rapidjson::UTF8<char>, void>, rapidjson::CrtAllocator>::EndMissingDependentProperties(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> > const&) (schema.h:2707)
==120993==    by 0x49C742F: rapidjson::internal::Schema<rapidjson::GenericSchemaDocument<rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> > >::EndObject(rapidjson::internal::SchemaValidationContext<rapidjson::GenericSchemaDocument<rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> > >&, unsigned int) const (schema.h:1193)
==120993==    by 0x49C2F87: rapidjson::GenericSchemaValidator<rapidjson::GenericSchemaDocument<rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >, rapidjson::BaseReaderHandler<rapidjson::UTF8<char>, void>, rapidjson::CrtAllocator>::EndObject(unsigned int) (schema.h:2868)
==120993==    by 0x49BE30F: xxx::validation::JsonSchemaValidatorVisitor::visitContainer(xxx::PrivateLib const&) (JsonSchemaValidator.cpp:197)
==120993==    by 0x49C071F: xxx::validation::JsonSchemaValidatorVisitor::visitEntry(xxx::PrivateLib::Entry const&, bool) (JsonSchemaValidator.cpp:266)
....

We can see that malloc, free, and the read are all happening inside RapidJSON's flow, but I'd like to have your thoughts on this, because I saw in the diff between the 2 commits that we bumped from/to (diff here: https://github.com/Tencent/rapidjson/compare/f54b0e4..f9d5341), that there was some changes in the way GenericSchemaDocument is built, and how pointers are handled internally.
So I was wondering if we don't provide the right inputs, but on the other hand, it doesn't work well only for that "dependencies" feature.

Any help on that would be welcome,
Thanks !

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