Skip to content

Commit

Permalink
Merge pull request #609 from miloyip/issue608_required
Browse files Browse the repository at this point in the history
Fix schema "required" keyword cannot handle duplicated keys
  • Loading branch information
miloyip committed Apr 19, 2016
2 parents 07343d5 + bbcdb8b commit 8821797
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 21 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
* Fix memory leak for invalid regex (26e69ffde95ba4773ab06db6457b78f308716f4b)
* Fix a bug in schema minimum/maximum keywords for 64-bit integer (e7149d665941068ccf8c565e77495521331cf390)
* Fix a crash bug in regex (#605)
* Fix schema "required" keyword cannot handle duplicated keys (#609)

### Changed
* Clarify problematic JSON license (#392)
Expand Down
40 changes: 19 additions & 21 deletions include/rapidjson/schema.h
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ struct SchemaValidationContext {
patternPropertiesSchemas(),
patternPropertiesSchemaCount(),
valuePatternValidatorType(kPatternValidatorOnly),
objectDependencies(),
propertyExist(),
inArray(false),
valueUniqueness(false),
arrayUniqueness(false)
Expand All @@ -311,8 +311,8 @@ struct SchemaValidationContext {
}
if (patternPropertiesSchemas)
factory.FreeState(patternPropertiesSchemas);
if (objectDependencies)
factory.FreeState(objectDependencies);
if (propertyExist)
factory.FreeState(propertyExist);
}

SchemaValidatorFactoryType& factory;
Expand All @@ -329,9 +329,8 @@ struct SchemaValidationContext {
SizeType patternPropertiesSchemaCount;
PatternValidatorType valuePatternValidatorType;
PatternValidatorType objectPatternValidatorType;
SizeType objectRequiredCount;
SizeType arrayElementIndex;
bool* objectDependencies;
bool* propertyExist;
bool inArray;
bool valueUniqueness;
bool arrayUniqueness;
Expand Down Expand Up @@ -365,11 +364,11 @@ class Schema {
patternProperties_(),
patternPropertyCount_(),
propertyCount_(),
requiredCount_(),
minProperties_(),
maxProperties_(SizeType(~0)),
additionalProperties_(true),
hasDependencies_(),
hasRequired_(),
hasSchemaDependencies_(),
additionalItemsSchema_(),
itemsList_(),
Expand Down Expand Up @@ -490,7 +489,7 @@ class Schema {
SizeType index;
if (FindPropertyIndex(*itr, &index)) {
properties_[index].required = true;
requiredCount_++;
hasRequired_ = true;
}
}

Expand Down Expand Up @@ -767,10 +766,9 @@ class Schema {
if (!(type_ & (1 << kObjectSchemaType)))
RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());

context.objectRequiredCount = 0;
if (hasDependencies_) {
context.objectDependencies = static_cast<bool*>(context.factory.MallocState(sizeof(bool) * propertyCount_));
std::memset(context.objectDependencies, 0, sizeof(bool) * propertyCount_);
if (hasDependencies_ || hasRequired_) {
context.propertyExist = static_cast<bool*>(context.factory.MallocState(sizeof(bool) * propertyCount_));
std::memset(context.propertyExist, 0, sizeof(bool) * propertyCount_);
}

if (patternProperties_) { // pre-allocate schema array
Expand Down Expand Up @@ -801,11 +799,8 @@ class Schema {
else
context.valueSchema = properties_[index].schema;

if (properties_[index].required)
context.objectRequiredCount++;

if (hasDependencies_)
context.objectDependencies[index] = true;
if (context.propertyExist)
context.propertyExist[index] = true;

return true;
}
Expand All @@ -832,8 +827,11 @@ class Schema {
}

bool EndObject(Context& context, SizeType memberCount) const {
if (context.objectRequiredCount != requiredCount_)
RAPIDJSON_INVALID_KEYWORD_RETURN(GetRequiredString());
if (hasRequired_)
for (SizeType index = 0; index < propertyCount_; index++)
if (properties_[index].required)
if (!context.propertyExist[index])
RAPIDJSON_INVALID_KEYWORD_RETURN(GetRequiredString());

if (memberCount < minProperties_)
RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinPropertiesString());
Expand All @@ -843,10 +841,10 @@ class Schema {

if (hasDependencies_) {
for (SizeType sourceIndex = 0; sourceIndex < propertyCount_; sourceIndex++)
if (context.objectDependencies[sourceIndex]) {
if (context.propertyExist[sourceIndex]) {
if (properties_[sourceIndex].dependencies) {
for (SizeType targetIndex = 0; targetIndex < propertyCount_; targetIndex++)
if (properties_[sourceIndex].dependencies[targetIndex] && !context.objectDependencies[targetIndex])
if (properties_[sourceIndex].dependencies[targetIndex] && !context.propertyExist[targetIndex])
RAPIDJSON_INVALID_KEYWORD_RETURN(GetDependenciesString());
}
else if (properties_[sourceIndex].dependenciesSchema)
Expand Down Expand Up @@ -1236,11 +1234,11 @@ class Schema {
PatternProperty* patternProperties_;
SizeType patternPropertyCount_;
SizeType propertyCount_;
SizeType requiredCount_;
SizeType minProperties_;
SizeType maxProperties_;
bool additionalProperties_;
bool hasDependencies_;
bool hasRequired_;
bool hasSchemaDependencies_;

const SchemaType* additionalItemsSchema_;
Expand Down
9 changes: 9 additions & 0 deletions test/unittest/schematest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1299,6 +1299,15 @@ TEST(Schema, Issue552) {

#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS

TEST(SchemaValidator, Issue608) {
Document sd;
sd.Parse("{\"required\": [\"a\", \"b\"] }");
SchemaDocument s(sd);

VALIDATE(s, "{\"a\" : null, \"b\": null}", true);
INVALIDATE(s, "{\"a\" : null, \"a\" : null}", "", "required", "");
}

#ifdef __clang__
RAPIDJSON_DIAG_POP
#endif

0 comments on commit 8821797

Please sign in to comment.