From a06fb311c23284a1de1fddedf63f673941bfeda1 Mon Sep 17 00:00:00 2001 From: 1000TurquoisePogs Date: Thu, 9 May 2024 04:33:28 -0400 Subject: [PATCH 1/2] Allow strings to be null for backward compat on recent bugfix Signed-off-by: 1000TurquoisePogs --- c/jsonschema.c | 24 +++++++++++++++++++++++- h/jsonschema.h | 1 + 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/c/jsonschema.c b/c/jsonschema.c index 525ac1653..60448870c 100644 --- a/c/jsonschema.c +++ b/c/jsonschema.c @@ -1108,7 +1108,27 @@ static JSValueSpec *resolveRef(JsonValidator *validator, ValidityException *pend static VResult validateJSONSimple(JsonValidator *validator, Json *value, JSValueSpec *valueSpec, int depth, EvalSet *evalSetList){ if (jsonIsNull(value)){ - return validateType(validator,JSTYPE_NULL,valueSpec,depth+1); + VResult typeResult = validateType(validator,JSTYPE_NULL,valueSpec,depth+1); + if (vStatusValid(typeResult.status)) { + return typeResult; + } else if (validator->allowStringToBeNull) { + // FIXME: Some users were relying upon a bug we fixed, where an empty value would be treated as a string. + // TODO: Remove this in v3, we should not keep this bug compatability forever. + if (((1 << JSTYPE_STRING) & valueSpec->typeMask) != 0){ + Json *emptyStringJson = (Json*)safeMalloc(sizeof(Json), "Empty String JSON"); + emptyStringJson->type = JSON_TYPE_STRING; + char emptyString[1] = {0}; + emptyStringJson->data.string = emptyString; + // Check if schema is okay with an "empty string" as the previous bug had null be empty string. + VResult stringResult = validateJSONString(validator,emptyStringJson,valueSpec,depth+1); + safeFree((char*)emptyStringJson, sizeof(Json)); + return stringResult; + } else{ + return simpleFailure(validator, "string cannot be null for %s\n", validatorAccessPath(validator)); + } + } else { + return typeResult; + } } else if (jsonIsBoolean(value)){ return validateType(validator,JSTYPE_BOOLEAN,valueSpec,depth+1); } else if (jsonIsObject(value)){ @@ -1420,6 +1440,8 @@ static VResult validateJSON(JsonValidator *validator, int jsonValidateSchema(JsonValidator *validator, Json *value, JsonSchema *topSchema, JsonSchema **otherSchemas, int otherSchemaCount){ int result = 0; + validator->allowStringToBeNull = true; + if (setjmp(validator->recoveryData) == 0) { /* normal execution */ validator->topSchema = topSchema; validator->otherSchemas = otherSchemas; diff --git a/h/jsonschema.h b/h/jsonschema.h index 4b8543334..0bf703e31 100644 --- a/h/jsonschema.h +++ b/h/jsonschema.h @@ -117,6 +117,7 @@ typedef struct JsonValidator_tag { int fileRegexError; jmp_buf recoveryData; ShortLivedHeap *evalHeap; + bool allowStringToBeNull; } JsonValidator; #define JSON_SCHEMA_DRAFT_4 400 From c2c74e3b5def494c4296618b027d9d80b8686009 Mon Sep 17 00:00:00 2001 From: 1000TurquoisePogs Date: Mon, 20 May 2024 12:33:08 -0400 Subject: [PATCH 2/2] Add same null-to-string fix for enum case as well Signed-off-by: 1000TurquoisePogs --- c/jsonschema.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/c/jsonschema.c b/c/jsonschema.c index 60448870c..b5e23fadf 100644 --- a/c/jsonschema.c +++ b/c/jsonschema.c @@ -1326,14 +1326,34 @@ static VResult validateJSON(JsonValidator *validator, /* As we go through the valid enum values, record them in comma separated * form for displaying at the tail end of the error message. */ + + bool nullToString = false; + Json *emptyStringJson; + if (jsonIsNull(value)) { + VResult typeResult = validateType(validator,JSTYPE_NULL,valueSpec,depth+1); + if ((!vStatusValid(typeResult.status)) && (validator->allowStringToBeNull)) { + // FIXME: Some users were relying upon a bug we fixed, where an empty value would be treated as a string. + // TODO: Remove this in v3, we should not keep this bug compatability forever. + if (((1 << JSTYPE_STRING) & valueSpec->typeMask) != 0){ + emptyStringJson = (Json*)safeMalloc(sizeof(Json), "Empty String JSON"); + emptyStringJson->type = JSON_TYPE_STRING; + char emptyString[1] = {0}; + emptyStringJson->data.string = emptyString; + nullToString = true; + } + } + } + unsigned int validValuesMaxSize = (valueSpec->enumeratedValuesCount * (sizeof(Json*) + 3)) + 1; char *validValues = SLHAlloc(validator->evalHeap, validValuesMaxSize); if (validValues) { memset(validValues, 0, validValuesMaxSize); } + + Json *whichValue = nullToString == true ? emptyStringJson : value; for (int ee=0; eeenumeratedValuesCount; ee++){ Json *enumValue = valueSpec->enumeratedValues[ee]; - if (jsonEquals(value,enumValue)){ + if (jsonEquals(whichValue,enumValue)){ matched = true; break; } @@ -1357,6 +1377,9 @@ static VResult validateJSON(JsonValidator *validator, strcat(validValues, ", "); } } + if (nullToString) { + safeFree((char*)emptyStringJson, sizeof(Json)); + } if (!matched){ if (validValues && strlen(validValues) > 0) { return simpleFailure(validator,"no matching enum value at %s; expecting one of values '[%s]' of type '%s'",