mirror of
https://github.com/sqlite/sqlite.git
synced 2025-11-09 14:21:03 +03:00
Work toward enhanced functionality for json_valid() with deep checking
of the JSONB (second argument has bit 0x08). FossilOrigin-Name: c370d573198b151767f04e91bf8baa4ae0076751ae468c5709742a0b0ed16770
This commit is contained in:
15
manifest
15
manifest
@@ -1,5 +1,5 @@
|
|||||||
C Fix\sa\spotential\suse\sof\suninitialized\svalue\sin\sjson_valid()\swith\s2nd\nargument\sof\s8.
|
C Work\stoward\senhanced\sfunctionality\sfor\sjson_valid()\swith\sdeep\schecking\nof\sthe\sJSONB\s(second\sargument\shas\sbit\s0x08).
|
||||||
D 2023-12-11T02:39:11.053
|
D 2023-12-11T14:01:38.458
|
||||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||||
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
||||||
@@ -696,7 +696,7 @@ F src/hash.h 3340ab6e1d13e725571d7cee6d3e3135f0779a7d8e76a9ce0a85971fa3953c51
|
|||||||
F src/hwtime.h f9c2dfb84dce7acf95ce6d289e46f5f9d3d1afd328e53da8f8e9008e3b3caae6
|
F src/hwtime.h f9c2dfb84dce7acf95ce6d289e46f5f9d3d1afd328e53da8f8e9008e3b3caae6
|
||||||
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
|
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
|
||||||
F src/insert.c 3f0a94082d978bbdd33c38fefea15346c6c6bffb70bc645a71dc0f1f87dd3276
|
F src/insert.c 3f0a94082d978bbdd33c38fefea15346c6c6bffb70bc645a71dc0f1f87dd3276
|
||||||
F src/json.c 022548736478f10bec4f2766f2c9fe1cc25c06b14cabb0ca64b4a1beb83fbf16
|
F src/json.c 683a85f8b35a79c817b05723cee14ce7281a9f76e78d64950cfb50be10caf6d0
|
||||||
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
|
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
|
||||||
F src/loadext.c 7432c944ff197046d67a1207790a1b13eec4548c85a9457eb0896bb3641dfb36
|
F src/loadext.c 7432c944ff197046d67a1207790a1b13eec4548c85a9457eb0896bb3641dfb36
|
||||||
F src/main.c 1b89f3de98d1b59fec5bac1d66d6ece21f703821b8eaa0d53d9604c35309f6f9
|
F src/main.c 1b89f3de98d1b59fec5bac1d66d6ece21f703821b8eaa0d53d9604c35309f6f9
|
||||||
@@ -2153,8 +2153,11 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
|||||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||||
P 1503cba6d17e9bade7a5c103ddd23241ff4741f9a2e3032ffe2987af243dae65
|
P fa102036fe46eeb71b7df3e265be1935ae5c78e0b939b08841bcfb8abadbc77a
|
||||||
R 10c5202c73d5a29cc977b618b1930c91
|
R d66c4373e6cbfb5a424f82330e7184cd
|
||||||
|
T *branch * jsonb-valid
|
||||||
|
T *sym-jsonb-valid *
|
||||||
|
T -sym-trunk *
|
||||||
U drh
|
U drh
|
||||||
Z 03628577bea44fb563932e72818a5e19
|
Z 18d49697fdb46dc3745b2a8b7db33d7b
|
||||||
# Remove this line to create a well-formed Fossil manifest.
|
# Remove this line to create a well-formed Fossil manifest.
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
fa102036fe46eeb71b7df3e265be1935ae5c78e0b939b08841bcfb8abadbc77a
|
c370d573198b151767f04e91bf8baa4ae0076751ae468c5709742a0b0ed16770
|
||||||
149
src/json.c
149
src/json.c
@@ -3869,6 +3869,128 @@ json_type_done:
|
|||||||
jsonParseFree(p);
|
jsonParseFree(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Check a single element of the JSONB in pParse for validity.
|
||||||
|
**
|
||||||
|
** The element to be checked starts at offset i and must end at on the
|
||||||
|
** last byte before iEnd.
|
||||||
|
**
|
||||||
|
** Return 0 if everything is correct. Return the 1-based byte offset of the
|
||||||
|
** error if a problem is detected. (In other words, if the error is at offset
|
||||||
|
** 0, return 1).
|
||||||
|
*/
|
||||||
|
static u32 jsonbValidityCheck(JsonParse *pParse, u32 i, u32 iEnd, u32 iDepth){
|
||||||
|
u32 n, sz, j, k;
|
||||||
|
const u8 *z;
|
||||||
|
u8 x;
|
||||||
|
if( iDepth>JSON_MAX_DEPTH ) return i+1;
|
||||||
|
sz = 0;
|
||||||
|
n = jsonbPayloadSize(pParse, i, &sz);
|
||||||
|
if( n==0 ) return i+1;
|
||||||
|
if( i+n+sz!=iEnd ) return i+1;
|
||||||
|
z = pParse->aBlob;
|
||||||
|
x = z[i] & 0x0f;
|
||||||
|
switch( x ){
|
||||||
|
case JSONB_NULL:
|
||||||
|
case JSONB_TRUE:
|
||||||
|
case JSONB_FALSE: {
|
||||||
|
return n+sz==1 ? 0 : i+1;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
return i+1;
|
||||||
|
}
|
||||||
|
case JSONB_INT: {
|
||||||
|
if( sz<1 ) return i+1;
|
||||||
|
j = i+n;
|
||||||
|
if( z[j]=='-' ){
|
||||||
|
j++;
|
||||||
|
if( sz<2 ) return j;
|
||||||
|
}
|
||||||
|
k = i+n+sz;
|
||||||
|
while( j<k ){
|
||||||
|
if( sqlite3Isdigit(z[j]) ){
|
||||||
|
j++;
|
||||||
|
}else{
|
||||||
|
return j+1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
case JSONB_INT5: {
|
||||||
|
if( sz<3 ) return i+1;
|
||||||
|
j = i+n;
|
||||||
|
if( z[j]!='0' ) return j+1;
|
||||||
|
if( z[j+1]!='x' && z[j+1]!='X' ) return j+2;
|
||||||
|
j += 2;
|
||||||
|
k = i+n+sz;
|
||||||
|
while( j<k ){
|
||||||
|
if( sqlite3Isxdigit(z[j]) ){
|
||||||
|
j++;
|
||||||
|
}else{
|
||||||
|
return j+1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
case JSONB_FLOAT:
|
||||||
|
case JSONB_FLOAT5: {
|
||||||
|
if( sz<2 ) return i+1;
|
||||||
|
j = i+n;
|
||||||
|
k = j+sz;
|
||||||
|
if( z[j]=='-' ){
|
||||||
|
j++;
|
||||||
|
if( sz<3 ) return i+1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
case JSONB_TEXT:
|
||||||
|
case JSONB_TEXTJ:
|
||||||
|
case JSONB_TEXT5:
|
||||||
|
case JSONB_TEXTRAW: {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
case JSONB_ARRAY: {
|
||||||
|
u32 sub;
|
||||||
|
j = i+n;
|
||||||
|
k = j+sz;
|
||||||
|
while( j<k ){
|
||||||
|
sz = 0;
|
||||||
|
n = jsonbPayloadSize(pParse, j, &sz);
|
||||||
|
if( n==0 ) return j+1;
|
||||||
|
if( j+n+sz>k ) return j+1;
|
||||||
|
sub = jsonbValidityCheck(pParse, j, k, iDepth+1);
|
||||||
|
if( sub ) return sub;
|
||||||
|
j += n + sz;
|
||||||
|
}
|
||||||
|
assert( j==k );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
case JSONB_OBJECT: {
|
||||||
|
u32 cnt = 0;
|
||||||
|
u32 sub;
|
||||||
|
j = i+n;
|
||||||
|
k = j+sz;
|
||||||
|
while( j<k ){
|
||||||
|
sz = 0;
|
||||||
|
n = jsonbPayloadSize(pParse, j, &sz);
|
||||||
|
if( n==0 ) return j+1;
|
||||||
|
if( j+n+sz>k ) return j+1;
|
||||||
|
if( (cnt & 1)==0 ){
|
||||||
|
x = z[j] & 0x0f;
|
||||||
|
if( x<JSONB_TEXT || x>JSONB_TEXTRAW ) return j+1;
|
||||||
|
}
|
||||||
|
sub = jsonbValidityCheck(pParse, j, k, iDepth+1);
|
||||||
|
if( sub ) return sub;
|
||||||
|
cnt++;
|
||||||
|
j += n + sz;
|
||||||
|
}
|
||||||
|
assert( j==k );
|
||||||
|
if( (cnt & 1)!=0 ) return j+1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** json_valid(JSON)
|
** json_valid(JSON)
|
||||||
** json_valid(JSON, FLAGS)
|
** json_valid(JSON, FLAGS)
|
||||||
@@ -3954,38 +4076,19 @@ static void jsonValidFunc(
|
|||||||
case SQLITE_BLOB: {
|
case SQLITE_BLOB: {
|
||||||
if( (flags & 0x0c)!=0 && jsonFuncArgMightBeBinary(argv[0]) ){
|
if( (flags & 0x0c)!=0 && jsonFuncArgMightBeBinary(argv[0]) ){
|
||||||
if( flags & 0x04 ){
|
if( flags & 0x04 ){
|
||||||
/* Superficial checking only - accomplisehd by the
|
/* Superficial checking only - accomplished by the
|
||||||
** jsonFuncArgMightBeBinary() call above. */
|
** jsonFuncArgMightBeBinary() call above. */
|
||||||
res = 1;
|
res = 1;
|
||||||
}else{
|
}else{
|
||||||
/* Strict checking. Check by translating BLOB->TEXT->BLOB. If
|
/* Strict checking. Check by translating BLOB->TEXT->BLOB. If
|
||||||
** no errors occur, call that a "strict check". */
|
** no errors occur, call that a "strict check". */
|
||||||
JsonParse px;
|
JsonParse px;
|
||||||
JsonString sx;
|
u32 iErr;
|
||||||
u8 oom = 0;
|
|
||||||
memset(&px, 0, sizeof(px));
|
memset(&px, 0, sizeof(px));
|
||||||
px.aBlob = (u8*)sqlite3_value_blob(argv[0]);
|
px.aBlob = (u8*)sqlite3_value_blob(argv[0]);
|
||||||
px.nBlob = sqlite3_value_bytes(argv[0]);
|
px.nBlob = sqlite3_value_bytes(argv[0]);
|
||||||
jsonStringInit(&sx, 0);
|
iErr = jsonbValidityCheck(&px, 0, px.nBlob, 1);
|
||||||
jsonXlateBlobToText(&px, 0, &sx);
|
res = iErr==0;
|
||||||
jsonParseReset(&px);
|
|
||||||
if( sx.eErr & JSTRING_OOM ) oom = 1;
|
|
||||||
if( sx.eErr==0 ){
|
|
||||||
memset(&px, 0, sizeof(px));
|
|
||||||
jsonStringTerminate(&sx);
|
|
||||||
px.zJson = sx.zBuf;
|
|
||||||
px.nJson = sx.nUsed;
|
|
||||||
if( jsonXlateTextToBlob(&px, 0)==px.nJson ){
|
|
||||||
res = 1;
|
|
||||||
}
|
|
||||||
oom |= px.oom;
|
|
||||||
jsonParseReset(&px);
|
|
||||||
}
|
|
||||||
jsonStringReset(&sx);
|
|
||||||
if( oom ){
|
|
||||||
sqlite3_result_error_nomem(ctx);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|||||||
Reference in New Issue
Block a user