From c8a1d51753c603c7bbea7dba791a8124a909c813 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Tue, 19 Apr 2016 15:05:15 +0800 Subject: [PATCH 1/4] Add reproduction test case --- test/unittest/schematest.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/unittest/schematest.cpp b/test/unittest/schematest.cpp index ff8b5d6..d1027ad 100644 --- a/test/unittest/schematest.cpp +++ b/test/unittest/schematest.cpp @@ -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 From f586edd33d5b201b1b640da924904ba360a06e58 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Tue, 19 Apr 2016 15:06:41 +0800 Subject: [PATCH 2/4] Fix required for duplicated keys Fix #608 --- include/rapidjson/schema.h | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/include/rapidjson/schema.h b/include/rapidjson/schema.h index 33b6a10..45bcebf 100644 --- a/include/rapidjson/schema.h +++ b/include/rapidjson/schema.h @@ -290,6 +290,7 @@ struct SchemaValidationContext { patternPropertiesSchemaCount(), valuePatternValidatorType(kPatternValidatorOnly), objectDependencies(), + objectRequired(), inArray(false), valueUniqueness(false), arrayUniqueness(false) @@ -313,6 +314,8 @@ struct SchemaValidationContext { factory.FreeState(patternPropertiesSchemas); if (objectDependencies) factory.FreeState(objectDependencies); + if (objectRequired) + factory.FreeState(objectRequired); } SchemaValidatorFactoryType& factory; @@ -329,9 +332,9 @@ struct SchemaValidationContext { SizeType patternPropertiesSchemaCount; PatternValidatorType valuePatternValidatorType; PatternValidatorType objectPatternValidatorType; - SizeType objectRequiredCount; SizeType arrayElementIndex; bool* objectDependencies; + bool* objectRequired; bool inArray; bool valueUniqueness; bool arrayUniqueness; @@ -365,11 +368,11 @@ public: patternProperties_(), patternPropertyCount_(), propertyCount_(), - requiredCount_(), minProperties_(), maxProperties_(SizeType(~0)), additionalProperties_(true), hasDependencies_(), + hasRequired_(), hasSchemaDependencies_(), additionalItemsSchema_(), itemsList_(), @@ -490,7 +493,7 @@ public: SizeType index; if (FindPropertyIndex(*itr, &index)) { properties_[index].required = true; - requiredCount_++; + hasRequired_ = true; } } @@ -767,7 +770,11 @@ public: if (!(type_ & (1 << kObjectSchemaType))) RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); - context.objectRequiredCount = 0; + if (hasRequired_) { + context.objectRequired = static_cast(context.factory.MallocState(sizeof(bool) * propertyCount_)); + std::memset(context.objectRequired, 0, sizeof(bool) * propertyCount_); + } + if (hasDependencies_) { context.objectDependencies = static_cast(context.factory.MallocState(sizeof(bool) * propertyCount_)); std::memset(context.objectDependencies, 0, sizeof(bool) * propertyCount_); @@ -801,8 +808,8 @@ public: else context.valueSchema = properties_[index].schema; - if (properties_[index].required) - context.objectRequiredCount++; + if (hasRequired_) + context.objectRequired[index] = true; if (hasDependencies_) context.objectDependencies[index] = true; @@ -832,8 +839,12 @@ public: } 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.objectRequired[index]) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetRequiredString()); + } if (memberCount < minProperties_) RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinPropertiesString()); @@ -1236,11 +1247,11 @@ private: PatternProperty* patternProperties_; SizeType patternPropertyCount_; SizeType propertyCount_; - SizeType requiredCount_; SizeType minProperties_; SizeType maxProperties_; bool additionalProperties_; bool hasDependencies_; + bool hasRequired_; bool hasSchemaDependencies_; const SchemaType* additionalItemsSchema_; From a6571d504aeccf819af919e653361d1ad5fd7065 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Tue, 19 Apr 2016 15:10:28 +0800 Subject: [PATCH 3/4] Combine objectDependices and objectRequired into propertyExist array --- include/rapidjson/schema.h | 39 +++++++++++++------------------------- 1 file changed, 13 insertions(+), 26 deletions(-) diff --git a/include/rapidjson/schema.h b/include/rapidjson/schema.h index 45bcebf..0a8bb7c 100644 --- a/include/rapidjson/schema.h +++ b/include/rapidjson/schema.h @@ -289,8 +289,7 @@ struct SchemaValidationContext { patternPropertiesSchemas(), patternPropertiesSchemaCount(), valuePatternValidatorType(kPatternValidatorOnly), - objectDependencies(), - objectRequired(), + propertyExist(), inArray(false), valueUniqueness(false), arrayUniqueness(false) @@ -312,10 +311,8 @@ struct SchemaValidationContext { } if (patternPropertiesSchemas) factory.FreeState(patternPropertiesSchemas); - if (objectDependencies) - factory.FreeState(objectDependencies); - if (objectRequired) - factory.FreeState(objectRequired); + if (propertyExist) + factory.FreeState(propertyExist); } SchemaValidatorFactoryType& factory; @@ -333,8 +330,7 @@ struct SchemaValidationContext { PatternValidatorType valuePatternValidatorType; PatternValidatorType objectPatternValidatorType; SizeType arrayElementIndex; - bool* objectDependencies; - bool* objectRequired; + bool* propertyExist; bool inArray; bool valueUniqueness; bool arrayUniqueness; @@ -770,14 +766,9 @@ public: if (!(type_ & (1 << kObjectSchemaType))) RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); - if (hasRequired_) { - context.objectRequired = static_cast(context.factory.MallocState(sizeof(bool) * propertyCount_)); - std::memset(context.objectRequired, 0, sizeof(bool) * propertyCount_); - } - - if (hasDependencies_) { - context.objectDependencies = static_cast(context.factory.MallocState(sizeof(bool) * propertyCount_)); - std::memset(context.objectDependencies, 0, sizeof(bool) * propertyCount_); + if (hasDependencies_ || hasRequired_) { + context.propertyExist = static_cast(context.factory.MallocState(sizeof(bool) * propertyCount_)); + std::memset(context.propertyExist, 0, sizeof(bool) * propertyCount_); } if (patternProperties_) { // pre-allocate schema array @@ -808,11 +799,8 @@ public: else context.valueSchema = properties_[index].schema; - if (hasRequired_) - context.objectRequired[index] = true; - - if (hasDependencies_) - context.objectDependencies[index] = true; + if (context.propertyExist) + context.propertyExist[index] = true; return true; } @@ -840,11 +828,10 @@ public: bool EndObject(Context& context, SizeType memberCount) const { if (hasRequired_) - for (SizeType index = 0; index < propertyCount_; index++) { + for (SizeType index = 0; index < propertyCount_; index++) if (properties_[index].required) - if (!context.objectRequired[index]) + if (!context.propertyExist[index]) RAPIDJSON_INVALID_KEYWORD_RETURN(GetRequiredString()); - } if (memberCount < minProperties_) RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinPropertiesString()); @@ -854,10 +841,10 @@ public: 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) From bbcdb8b574b4098f95d95efda046705a39f888c9 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Tue, 19 Apr 2016 15:44:50 +0800 Subject: [PATCH 4/4] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ed193b..6de511e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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)