]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Work toward enhanced functionality for json_valid() with deep checking
authordrh <>
Mon, 11 Dec 2023 14:01:38 +0000 (14:01 +0000)
committerdrh <>
Mon, 11 Dec 2023 14:01:38 +0000 (14:01 +0000)
of the JSONB (second argument has bit 0x08).

FossilOrigin-Name: c370d573198b151767f04e91bf8baa4ae0076751ae468c5709742a0b0ed16770

manifest
manifest.uuid
src/json.c

index f1e356acec1dc456db8e1772bb550ea92bb7dba3..0ee7bf7d351fd59637236b1b3ed7f239fa8fb52b 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Fix\sa\spotential\suse\sof\suninitialized\svalue\sin\sjson_valid()\swith\s2nd\nargument\sof\s8.
-D 2023-12-11T02:39:11.053
+C Work\stoward\senhanced\sfunctionality\sfor\sjson_valid()\swith\sdeep\schecking\nof\sthe\sJSONB\s(second\sargument\shas\sbit\s0x08).
+D 2023-12-11T14:01:38.458
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -696,7 +696,7 @@ F src/hash.h 3340ab6e1d13e725571d7cee6d3e3135f0779a7d8e76a9ce0a85971fa3953c51
 F src/hwtime.h f9c2dfb84dce7acf95ce6d289e46f5f9d3d1afd328e53da8f8e9008e3b3caae6
 F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
 F src/insert.c 3f0a94082d978bbdd33c38fefea15346c6c6bffb70bc645a71dc0f1f87dd3276
-F src/json.c 022548736478f10bec4f2766f2c9fe1cc25c06b14cabb0ca64b4a1beb83fbf16
+F src/json.c 683a85f8b35a79c817b05723cee14ce7281a9f76e78d64950cfb50be10caf6d0
 F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
 F src/loadext.c 7432c944ff197046d67a1207790a1b13eec4548c85a9457eb0896bb3641dfb36
 F src/main.c 1b89f3de98d1b59fec5bac1d66d6ece21f703821b8eaa0d53d9604c35309f6f9
@@ -2153,8 +2153,11 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 1503cba6d17e9bade7a5c103ddd23241ff4741f9a2e3032ffe2987af243dae65
-R 10c5202c73d5a29cc977b618b1930c91
+P fa102036fe46eeb71b7df3e265be1935ae5c78e0b939b08841bcfb8abadbc77a
+R d66c4373e6cbfb5a424f82330e7184cd
+T *branch * jsonb-valid
+T *sym-jsonb-valid *
+T -sym-trunk *
 U drh
-Z 03628577bea44fb563932e72818a5e19
+Z 18d49697fdb46dc3745b2a8b7db33d7b
 # Remove this line to create a well-formed Fossil manifest.
index c4f83fcd222058387ef5e6875937f701802ee828..b365e86e8e4e51453c0207ac09667093de486eee 100644 (file)
@@ -1 +1 @@
-fa102036fe46eeb71b7df3e265be1935ae5c78e0b939b08841bcfb8abadbc77a
\ No newline at end of file
+c370d573198b151767f04e91bf8baa4ae0076751ae468c5709742a0b0ed16770
\ No newline at end of file
index 71a1b789a44ac2194f97182279a79857ac465531..ab69f33ce0006accb07831488a2a693612b18a9f 100644 (file)
@@ -3869,6 +3869,128 @@ json_type_done:
   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, FLAGS)
@@ -3954,38 +4076,19 @@ static void jsonValidFunc(
     case SQLITE_BLOB: {
       if( (flags & 0x0c)!=0 && jsonFuncArgMightBeBinary(argv[0]) ){
         if( flags & 0x04 ){
-          /* Superficial checking only - accomplisehd by the
+          /* Superficial checking only - accomplished by the
           ** jsonFuncArgMightBeBinary() call above. */
           res = 1;
         }else{
           /* Strict checking.  Check by translating BLOB->TEXT->BLOB.  If
           ** no errors occur, call that a "strict check". */
           JsonParse px;
-          JsonString sx;
-          u8 oom = 0;
+          u32 iErr;
           memset(&px, 0, sizeof(px));
           px.aBlob = (u8*)sqlite3_value_blob(argv[0]);
           px.nBlob = sqlite3_value_bytes(argv[0]);
-          jsonStringInit(&sx, 0);
-          jsonXlateBlobToText(&px, 0, &sx);
-          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;
-          }
+          iErr = jsonbValidityCheck(&px, 0, px.nBlob, 1);
+          res = iErr==0;
         }
       }
       break;