From 9fa866a8d9573cb6613cdac00100e24697f43e49 Mon Sep 17 00:00:00 2001 From: drh Date: Sat, 8 Apr 2017 18:18:22 +0000 Subject: [PATCH] Disallow leading zeros on numeric constants in JSON. Fix for ticket [b93be8729a895a528e2] FossilOrigin-Name: 204e72f0080e8f08f99978870bd3cb9d59b068ecffee82192d707c650548b43b --- ext/misc/json1.c | 60 ++++++++++++++++++++++++++--------------------- manifest | 16 ++++++------- manifest.uuid | 2 +- test/json102.test | 21 +++++++++++++++++ 4 files changed, 63 insertions(+), 36 deletions(-) diff --git a/ext/misc/json1.c b/ext/misc/json1.c index bad5cd9b53..b12964ba4d 100644 --- a/ext/misc/json1.c +++ b/ext/misc/json1.c @@ -727,13 +727,14 @@ static int jsonParseValue(JsonParse *pParse, u32 i){ int iThis; int x; JsonNode *pNode; - while( safe_isspace(pParse->zJson[i]) ){ i++; } - if( (c = pParse->zJson[i])=='{' ){ + const char *z = pParse->zJson; + while( safe_isspace(z[i]) ){ i++; } + if( (c = z[i])=='{' ){ /* Parse object */ iThis = jsonParseAddNode(pParse, JSON_OBJECT, 0, 0); if( iThis<0 ) return -1; for(j=i+1;;j++){ - while( safe_isspace(pParse->zJson[j]) ){ j++; } + while( safe_isspace(z[j]) ){ j++; } x = jsonParseValue(pParse, j); if( x<0 ){ if( x==(-2) && pParse->nNode==(u32)iThis+1 ) return j+1; @@ -744,14 +745,14 @@ static int jsonParseValue(JsonParse *pParse, u32 i){ if( pNode->eType!=JSON_STRING ) return -1; pNode->jnFlags |= JNODE_LABEL; j = x; - while( safe_isspace(pParse->zJson[j]) ){ j++; } - if( pParse->zJson[j]!=':' ) return -1; + while( safe_isspace(z[j]) ){ j++; } + if( z[j]!=':' ) return -1; j++; x = jsonParseValue(pParse, j); if( x<0 ) return -1; j = x; - while( safe_isspace(pParse->zJson[j]) ){ j++; } - c = pParse->zJson[j]; + while( safe_isspace(z[j]) ){ j++; } + c = z[j]; if( c==',' ) continue; if( c!='}' ) return -1; break; @@ -763,15 +764,15 @@ static int jsonParseValue(JsonParse *pParse, u32 i){ iThis = jsonParseAddNode(pParse, JSON_ARRAY, 0, 0); if( iThis<0 ) return -1; for(j=i+1;;j++){ - while( safe_isspace(pParse->zJson[j]) ){ j++; } + while( safe_isspace(z[j]) ){ j++; } x = jsonParseValue(pParse, j); if( x<0 ){ if( x==(-3) && pParse->nNode==(u32)iThis+1 ) return j+1; return -1; } j = x; - while( safe_isspace(pParse->zJson[j]) ){ j++; } - c = pParse->zJson[j]; + while( safe_isspace(z[j]) ){ j++; } + c = z[j]; if( c==',' ) continue; if( c!=']' ) return -1; break; @@ -783,13 +784,13 @@ static int jsonParseValue(JsonParse *pParse, u32 i){ u8 jnFlags = 0; j = i+1; for(;;){ - c = pParse->zJson[j]; + c = z[j]; if( c==0 ) return -1; if( c=='\\' ){ - c = pParse->zJson[++j]; + c = z[++j]; if( c=='"' || c=='\\' || c=='/' || c=='b' || c=='f' || c=='n' || c=='r' || c=='t' - || (c=='u' && jsonIs4Hex(pParse->zJson+j+1)) ){ + || (c=='u' && jsonIs4Hex(z+j+1)) ){ jnFlags = JNODE_ESCAPE; }else{ return -1; @@ -799,55 +800,60 @@ static int jsonParseValue(JsonParse *pParse, u32 i){ } j++; } - jsonParseAddNode(pParse, JSON_STRING, j+1-i, &pParse->zJson[i]); + jsonParseAddNode(pParse, JSON_STRING, j+1-i, &z[i]); if( !pParse->oom ) pParse->aNode[pParse->nNode-1].jnFlags = jnFlags; return j+1; }else if( c=='n' - && strncmp(pParse->zJson+i,"null",4)==0 - && !safe_isalnum(pParse->zJson[i+4]) ){ + && strncmp(z+i,"null",4)==0 + && !safe_isalnum(z[i+4]) ){ jsonParseAddNode(pParse, JSON_NULL, 0, 0); return i+4; }else if( c=='t' - && strncmp(pParse->zJson+i,"true",4)==0 - && !safe_isalnum(pParse->zJson[i+4]) ){ + && strncmp(z+i,"true",4)==0 + && !safe_isalnum(z[i+4]) ){ jsonParseAddNode(pParse, JSON_TRUE, 0, 0); return i+4; }else if( c=='f' - && strncmp(pParse->zJson+i,"false",5)==0 - && !safe_isalnum(pParse->zJson[i+5]) ){ + && strncmp(z+i,"false",5)==0 + && !safe_isalnum(z[i+5]) ){ jsonParseAddNode(pParse, JSON_FALSE, 0, 0); return i+5; }else if( c=='-' || (c>='0' && c<='9') ){ /* Parse number */ u8 seenDP = 0; u8 seenE = 0; + assert( '-' < '0' ); + if( c<='0' ){ + j = c=='-' ? i+1 : i; + if( z[j]=='0' && z[j+1]>='0' && z[j+1]<='9' ) return -1; + } j = i+1; for(;; j++){ - c = pParse->zJson[j]; + c = z[j]; if( c>='0' && c<='9' ) continue; if( c=='.' ){ - if( pParse->zJson[j-1]=='-' ) return -1; + if( z[j-1]=='-' ) return -1; if( seenDP ) return -1; seenDP = 1; continue; } if( c=='e' || c=='E' ){ - if( pParse->zJson[j-1]<'0' ) return -1; + if( z[j-1]<'0' ) return -1; if( seenE ) return -1; seenDP = seenE = 1; - c = pParse->zJson[j+1]; + c = z[j+1]; if( c=='+' || c=='-' ){ j++; - c = pParse->zJson[j+1]; + c = z[j+1]; } if( c<'0' || c>'9' ) return -1; continue; } break; } - if( pParse->zJson[j-1]<'0' ) return -1; + if( z[j-1]<'0' ) return -1; jsonParseAddNode(pParse, seenDP ? JSON_REAL : JSON_INT, - j - i, &pParse->zJson[i]); + j - i, &z[i]); return j; }else if( c=='}' ){ return -2; /* End of {...} */ diff --git a/manifest b/manifest index e3f79625e8..2b13eab25a 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Expand\son\sthe\scomment\sabove\sOP_Destroy\sto\sexplain\swhy\sit\sthrows\san\serror\sif\nthere\sare\sany\sactive\sreader\sVMs. -D 2017-04-08T14:11:47.626 +C Disallow\sleading\szeros\son\snumeric\sconstants\sin\sJSON.\nFix\sfor\sticket\s[b93be8729a895a528e2] +D 2017-04-08T18:18:22.572 F Makefile.in 1cc758ce3374a32425e4d130c2fe7b026b20de5b8843243de75f087c0a2661fb F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434 F Makefile.msc a4c0613a18663bda56d8cf76079ab6590a7c3602e54befb4bbdef76bcaa38b6a @@ -218,7 +218,7 @@ F ext/misc/eval.c f971962e92ebb8b0a4e6b62949463ee454d88fa2 F ext/misc/fileio.c d4171c815d6543a9edef8308aab2951413cd8d0f F ext/misc/fuzzer.c 7c64b8197bb77b7d64eff7cac7848870235d4c25 F ext/misc/ieee754.c f190d0cc5182529acb15babd177781be1ac1718c -F ext/misc/json1.c 92b9e404bd79cc76d3ef2b3a9e37bf775700f7d645466fd41d2e8742e3fa16fb +F ext/misc/json1.c 312b4ddf4c7399dcbd2189f492e8ca92a872c2df7347473bfb38854f9d60c06a F ext/misc/memvfs.c e5225bc22e79dde6b28380f3a068ddf600683a33 F ext/misc/nextchar.c 35c8b8baacb96d92abbb34a83a997b797075b342 F ext/misc/percentile.c 92699c8cd7d517ff610e6037e56506f8904dae2e @@ -911,7 +911,7 @@ F test/jrnlmode.test 7864d59cf7f6e552b9b99ba0f38acd167edc10fa F test/jrnlmode2.test 81610545a4e6ed239ea8fa661891893385e23a1d F test/jrnlmode3.test 556b447a05be0e0963f4311e95ab1632b11c9eaa F test/json101.test c0897616f32d95431f37fd291cb78742181980ac -F test/json102.test bf3fe7a706d30936a76a0f7a0375e1e8e73aff5a +F test/json102.test de1728e8ffde4a57cbc77b6815a60ccb82a6c759967be44e71952757e7d7947b F test/json103.test c5f6b85e69de05f6b3195f9f9d5ce9cd179099a0 F test/json104.test 877d5845f6303899b7889ea5dd1bea99076e3100574d5c536082245c5805dcaa F test/keyword1.test 37ef6bba5d2ed5b07ecdd6810571de2956599dff @@ -1570,7 +1570,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P fa4416adc2a9a3a80db1d5befc0b95c3d0fc41affe38f7f2f45cdfae3f1b49eb -R a9817579cdde3e2d07834f7afee2d7a0 -U dan -Z aefe60bc1892ed67bf5beab6d8c742fc +P b9a8c2b9bec9f537b2d5aff6659a5748b1f70b53519a1f9dfceb5209154eca8e +R 670b9d233206c31ff293234250b6b1b3 +U drh +Z 7379463864511f4d80e83d3921199e22 diff --git a/manifest.uuid b/manifest.uuid index 737a0a72a7..149c2506cf 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -b9a8c2b9bec9f537b2d5aff6659a5748b1f70b53519a1f9dfceb5209154eca8e \ No newline at end of file +204e72f0080e8f08f99978870bd3cb9d59b068ecffee82192d707c650548b43b \ No newline at end of file diff --git a/test/json102.test b/test/json102.test index a4d88dbeaa..d1f2a4d36d 100644 --- a/test/json102.test +++ b/test/json102.test @@ -298,4 +298,25 @@ for {set i 0} {$i<100} {incr i} { } {1} } +#------------------------------------------------------------------------- +# 2017-04-08 ticket b93be8729a895a528e2849fca99f7 +# JSON extension accepts invalid numeric values +# +# JSON does not allow leading zeros. But the JSON extension was +# allowing them. The following tests verify that the problem is now +# fixed. +# +do_execsql_test json102-1401 { SELECT json_valid('{"x":01}') } 0 +do_execsql_test json102-1402 { SELECT json_valid('{"x":-01}') } 0 +do_execsql_test json102-1403 { SELECT json_valid('{"x":0}') } 1 +do_execsql_test json102-1404 { SELECT json_valid('{"x":-0}') } 1 +do_execsql_test json102-1405 { SELECT json_valid('{"x":0.1}') } 1 +do_execsql_test json102-1406 { SELECT json_valid('{"x":-0.1}') } 1 +do_execsql_test json102-1407 { SELECT json_valid('{"x":0.0000}') } 1 +do_execsql_test json102-1408 { SELECT json_valid('{"x":-0.0000}') } 1 +do_execsql_test json102-1409 { SELECT json_valid('{"x":01.5}') } 0 +do_execsql_test json102-1410 { SELECT json_valid('{"x":-01.5}') } 0 +do_execsql_test json102-1411 { SELECT json_valid('{"x":00}') } 0 +do_execsql_test json102-1412 { SELECT json_valid('{"x":-00}') } 0 + finish_test -- 2.47.2