]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Change the json1.c module so that it throws an error if any of the
authordrh <drh@noemail.net>
Sat, 29 Aug 2015 00:54:49 +0000 (00:54 +0000)
committerdrh <drh@noemail.net>
Sat, 29 Aug 2015 00:54:49 +0000 (00:54 +0000)
JSON selector paths are malformed.

FossilOrigin-Name: 3aa0855fd463076fc3277f1d9fe00d2f30e6b449

ext/misc/json1.c
manifest
manifest.uuid

index a8b9ed539d506043c76aab17cecb5adcd4fdc2c1..b4506c773f6a0ae2fb59cfb8518047f8de8d12d5 100644 (file)
@@ -108,6 +108,7 @@ struct JsonParse {
   const char *zJson; /* Original JSON string */
   u32 *aUp;          /* Index of parent of each node */
   u8 oom;            /* Set to true if out of memory */
+  u8 nErr;           /* Number of errors seen */
 };
 
 /**************************************************************************
@@ -786,7 +787,7 @@ static int jsonParseFindParents(JsonParse *pParse){
 }
 
 /* forward declaration */
-static JsonNode *jsonLookupAppend(JsonParse*,const char*,int*);
+static JsonNode *jsonLookupAppend(JsonParse*,const char*,int*,const char**);
 
 /*
 ** Search along zPath to find the node specified.  Return a pointer
@@ -797,11 +798,12 @@ static JsonNode *jsonLookupAppend(JsonParse*,const char*,int*);
 ** possible to do so and if no existing node corresponds to zPath.  If
 ** new nodes are appended *pApnd is set to 1.
 */
-static JsonNode *jsonLookup(
+static JsonNode *jsonLookupStep(
   JsonParse *pParse,      /* The JSON to search */
   u32 iRoot,              /* Begin the search at this node */
   const char *zPath,      /* The path to search */
-  int *pApnd              /* Append nodes to complete path if not NULL */
+  int *pApnd,             /* Append nodes to complete path if not NULL */
+  const char **pzErr      /* Make *pzErr point to any syntax error in zPath */
 ){
   u32 i, j, nKey;
   const char *zKey;
@@ -820,14 +822,17 @@ static JsonNode *jsonLookup(
       for(i=0; zPath[i] && zPath[i]!='.' && zPath[i]!='['; i++){}
       nKey = i;
     }
-    if( nKey==0 ) return 0;
+    if( nKey==0 ){
+      *pzErr = zPath;
+      return 0;
+    }
     j = 1;
     for(;;){
       while( j<=pRoot->n ){
         if( pRoot[j].n==nKey+2
          && strncmp(&pRoot[j].u.zJContent[1],zKey,nKey)==0
         ){
-          return jsonLookup(pParse, iRoot+j+1, &zPath[i], pApnd);
+          return jsonLookupStep(pParse, iRoot+j+1, &zPath[i], pApnd, pzErr);
         }
         j++;
         j += jsonNodeSize(&pRoot[j]);
@@ -843,7 +848,7 @@ static JsonNode *jsonLookup(
       iStart = jsonParseAddNode(pParse, JSON_OBJECT, 2, 0);
       iLabel = jsonParseAddNode(pParse, JSON_STRING, i, zPath);
       zPath += i;
-      pNode = jsonLookupAppend(pParse, zPath, pApnd);
+      pNode = jsonLookupAppend(pParse, zPath, pApnd, pzErr);
       if( pParse->oom ) return 0;
       if( pNode ){
         pRoot = &pParse->aNode[iRoot];
@@ -861,7 +866,10 @@ static JsonNode *jsonLookup(
       i = i*10 + zPath[0] - '0';
       zPath++;
     }
-    if( zPath[0]!=']' ) return 0;
+    if( zPath[0]!=']' ){
+      *pzErr = zPath;
+      return 0;
+    }
     zPath++;
     j = 1;
     for(;;){
@@ -875,13 +883,13 @@ static JsonNode *jsonLookup(
       j = 1;
     }
     if( j<=pRoot->n ){
-      return jsonLookup(pParse, iRoot+j, zPath, pApnd);
+      return jsonLookupStep(pParse, iRoot+j, zPath, pApnd, pzErr);
     }
     if( i==0 && pApnd ){
       u32 iStart;
       JsonNode *pNode;
       iStart = jsonParseAddNode(pParse, JSON_ARRAY, 1, 0);
-      pNode = jsonLookupAppend(pParse, zPath, pApnd);
+      pNode = jsonLookupAppend(pParse, zPath, pApnd, pzErr);
       if( pParse->oom ) return 0;
       if( pNode ){
         pRoot = &pParse->aNode[iRoot];
@@ -890,6 +898,8 @@ static JsonNode *jsonLookup(
       }
       return pNode;
     }
+  }else if( zPath[0]!=0 ){
+    *pzErr = zPath;
   }
   return 0;
 }
@@ -901,7 +911,8 @@ static JsonNode *jsonLookup(
 static JsonNode *jsonLookupAppend(
   JsonParse *pParse,     /* Append content to the JSON parse */
   const char *zPath,     /* Description of content to append */
-  int *pApnd             /* Set this flag to 1 */
+  int *pApnd,            /* Set this flag to 1 */
+  const char **pzErr     /* Make this point to any syntax error */
 ){
   *pApnd = 1;
   if( zPath[0]==0 ){
@@ -916,9 +927,76 @@ static JsonNode *jsonLookupAppend(
     return 0;
   }
   if( pParse->oom ) return 0;
-  return jsonLookup(pParse, pParse->nNode-1, zPath, pApnd);
+  return jsonLookupStep(pParse, pParse->nNode-1, zPath, pApnd, pzErr);
+}
+
+/*
+** Return the text of a syntax error message on a JSON path.  Space is
+** obtained from sqlite3_malloc().
+*/
+static char *jsonPathSyntaxError(const char *zErr){
+  return sqlite3_mprintf("JSON path error near '%q'", zErr);
 }
 
+/*
+** Do a node lookup using zPath.  Return a pointer to the node on success.
+** Return NULL if not found or if there is an error.
+**
+** On an error, write an error message into pCtx and increment the
+** pParse->nErr counter.
+**
+** If pApnd!=NULL then try to append missing nodes and set *pApnd = 1 if
+** nodes are appended.
+**
+** If the path starts with $$ then set *pFlags to JNODE_REPLACE|JNODE_JSON
+** as a single to the caller that the input text to be inserted should be 
+** interpreted as JSON rather than as ordinary text.
+*/
+static JsonNode *jsonLookup(
+  JsonParse *pParse,      /* The JSON to search */
+  const char *zPath,      /* The path to search */
+  int *pApnd,             /* Append nodes to complete path if not NULL */
+  sqlite3_context *pCtx,  /* Report errors here, if not NULL */
+  u8 *pFlags              /* Write JNODE_REPLACE or _REPLACE|_JSON here */
+){
+  const char *zErr = 0;
+  JsonNode *pNode = 0;
+  u8 fg = JNODE_REPLACE;
+
+  if( zPath==0 ) return 0;
+  if( zPath[0]!='$' ){
+    zErr = zPath;
+    goto lookup_err;
+  }
+  zPath++;
+  if( zPath[0]=='$' ){
+    if( pFlags==0 ){
+      zErr = zPath;
+      goto lookup_err;
+    }
+    zPath++;
+    fg = JNODE_REPLACE|JNODE_JSON;
+  }
+  if( pFlags ) *pFlags = fg;
+  pNode = jsonLookupStep(pParse, 0, zPath, pApnd, &zErr);
+  return pNode;
+
+lookup_err:
+  pParse->nErr++;
+  if( zErr!=0 && pCtx!=0 ){
+    char *z = jsonPathSyntaxError(zErr);
+    if( z ){
+      sqlite3_result_error(pCtx, z, -1);
+      sqlite3_free(z);
+    }else{
+      sqlite3_result_error_nomem(pCtx);
+    }
+  }
+  if( pFlags ) *pFlags = fg;
+  return 0;
+}
+
+
 /*
 ** Report the wrong number of arguments for json_insert(), json_replace()
 ** or json_set().
@@ -933,6 +1011,7 @@ static void jsonWrongNumArgs(
   sqlite3_free(zMsg);     
 }
 
+
 /****************************************************************************
 ** SQL functions used for testing and debugging
 ****************************************************************************/
@@ -1042,29 +1121,27 @@ static void jsonArrayLengthFunc(
   JsonParse x;          /* The parse */
   sqlite3_int64 n = 0;
   u32 i;
-  const char *zPath;
 
-  if( argc==2 ){
-    zPath = (const char*)sqlite3_value_text(argv[1]);
-    if( zPath==0 ) return;
-    if( zPath[0]!='$' ) return;
-    zPath++;
-  }else{
-    zPath = 0;
-  }
   if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
   if( x.nNode ){
-    JsonNode *pNode = x.aNode;
-    if( zPath ) pNode = jsonLookup(&x, 0, zPath, 0);
-    if( pNode->eType==JSON_ARRAY ){
+    JsonNode *pNode;
+    if( argc==2 ){
+      const char *zPath = (const char*)sqlite3_value_text(argv[1]);
+      pNode = jsonLookup(&x, zPath, 0, ctx, 0);
+    }else{
+      pNode = x.aNode;
+    }
+    if( pNode==0 ){
+      x.nErr = 1;
+    }else if( pNode->eType==JSON_ARRAY ){
       assert( (pNode->jnFlags & JNODE_APPEND)==0 );
       for(i=1; i<=pNode->n; n++){
         i += jsonNodeSize(&pNode[i]);
       }
     }
   }
+  if( x.nErr==0 ) sqlite3_result_int64(ctx, n);
   jsonParseReset(&x);
-  sqlite3_result_int64(ctx, n);
 }
 
 /*
@@ -1083,11 +1160,8 @@ static void jsonExtractFunc(
   const char *zPath;
   assert( argc==2 );
   zPath = (const char*)sqlite3_value_text(argv[1]);
-  if( zPath==0 ) return;
-  if( zPath[0]!='$' ) return;
-  zPath++;
   if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
-  pNode = jsonLookup(&x, 0, zPath, 0);
+  pNode = jsonLookup(&x, zPath, 0, ctx, 0);
   if( pNode ){
     jsonReturn(pNode, ctx, 0);
   }
@@ -1156,15 +1230,16 @@ static void jsonRemoveFunc(
   if( x.nNode ){
     for(i=1; i<(u32)argc; i++){
       zPath = (const char*)sqlite3_value_text(argv[i]);
-      if( zPath==0 ) continue;
-      if( zPath[0]!='$' ) continue;
-      pNode = jsonLookup(&x, 0, &zPath[1], 0);
+      if( zPath==0 ) goto remove_done;
+      pNode = jsonLookup(&x, zPath, 0, ctx, 0);
+      if( x.nErr ) goto remove_done;
       if( pNode ) pNode->jnFlags |= JNODE_REMOVE;
     }
     if( (x.aNode[0].jnFlags & JNODE_REMOVE)==0 ){
       jsonReturnJson(x.aNode, ctx, 0);
     }
   }
+remove_done:
   jsonParseReset(&x);
 }
 
@@ -1194,13 +1269,8 @@ static void jsonReplaceFunc(
     for(i=1; i<(u32)argc; i+=2){
       u8 jnFlags = JNODE_REPLACE;
       zPath = (const char*)sqlite3_value_text(argv[i]);
-      if( zPath==0 ) continue;
-      if( zPath[0]!='$' ) continue;
-      if( zPath[1]=='$' ){
-        zPath++;
-        jnFlags = JNODE_REPLACE|JNODE_JSON;
-      }
-      pNode = jsonLookup(&x, 0, &zPath[1], 0);
+      pNode = jsonLookup(&x, zPath, 0, ctx, &jnFlags);
+      if( x.nErr ) goto replace_err;
       if( pNode ){
         pNode->jnFlags &= ~JNODE_JSON;
         pNode->jnFlags |= jnFlags;
@@ -1213,6 +1283,7 @@ static void jsonReplaceFunc(
       jsonReturnJson(x.aNode, ctx, argv);
     }
   }
+replace_err:
   jsonParseReset(&x);
 }
 
@@ -1250,17 +1321,13 @@ static void jsonSetFunc(
     for(i=1; i<(u32)argc; i+=2){
       u8 jnFlags = JNODE_REPLACE;
       zPath = (const char*)sqlite3_value_text(argv[i]);
-      if( zPath==0 ) continue;
-      if( zPath[0]!='$' ) continue;
-      if( zPath[1]=='$' ){
-        zPath++;
-        jnFlags = JNODE_REPLACE|JNODE_JSON;
-      }
       bApnd = 0;
-      pNode = jsonLookup(&x, 0, &zPath[1], &bApnd);
+      pNode = jsonLookup(&x, zPath, &bApnd, ctx, &jnFlags);
       if( x.oom ){
         sqlite3_result_error_nomem(ctx);
         goto jsonSetDone;
+      }else if( x.nErr ){
+        goto jsonSetDone;
       }else if( pNode && (bApnd || bIsSet) ){
         pNode->jnFlags &= ~JNODE_JSON;
         pNode->jnFlags |= jnFlags;
@@ -1292,18 +1359,15 @@ static void jsonTypeFunc(
   JsonParse x;          /* The parse */
   const char *zPath;
 
-  if( argc==2 ){
-    zPath = (const char*)sqlite3_value_text(argv[1]);
-    if( zPath==0 ) return;
-    if( zPath[0]!='$' ) return;
-    zPath++;
-  }else{
-    zPath = 0;
-  }
   if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
   if( x.nNode ){
-    JsonNode *pNode = x.aNode;
-    if( zPath ) pNode = jsonLookup(&x, 0, zPath, 0);
+    JsonNode *pNode;
+    if( argc==2 ){
+      zPath = (const char*)sqlite3_value_text(argv[1]);
+      pNode = jsonLookup(&x, zPath, 0, ctx, 0);
+    }else{
+      pNode = x.aNode;
+    }
     if( pNode ){
       sqlite3_result_text(ctx, jsonType[pNode->eType], -1, SQLITE_STATIC);
     }
@@ -1680,27 +1744,45 @@ static int jsonEachFilter(
   if( z==0 ) return SQLITE_OK;
   if( idxNum&2 ){
     zPath = (const char*)sqlite3_value_text(argv[1]);
-    if( zPath==0 || zPath[0]!='$' ) return SQLITE_OK;
+    if( zPath==0 ) return SQLITE_OK;
+    if( zPath[0]!='$' ){
+      sqlite3_free(cur->pVtab->zErrMsg);
+      cur->pVtab->zErrMsg = jsonPathSyntaxError(zPath);
+      return cur->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM;
+    }
   }
   n = sqlite3_value_bytes(argv[0]);
   p->zJson = sqlite3_malloc64( n+1 );
   if( p->zJson==0 ) return SQLITE_NOMEM;
   memcpy(p->zJson, z, (size_t)n+1);
-  if( jsonParse(&p->sParse, 0, p->zJson) 
-   || (p->bRecursive && jsonParseFindParents(&p->sParse))
-  ){
+  if( jsonParse(&p->sParse, 0, p->zJson) ){
+    int rc = SQLITE_NOMEM;
+    if( p->sParse.oom==0 ){
+      sqlite3_free(cur->pVtab->zErrMsg);
+      cur->pVtab->zErrMsg = sqlite3_mprintf("malformed JSON");
+      if( cur->pVtab->zErrMsg ) rc = SQLITE_ERROR;
+    }
+    jsonEachCursorReset(p);
+    return rc;
+  }else if( p->bRecursive && jsonParseFindParents(&p->sParse) ){
     jsonEachCursorReset(p);
+    return SQLITE_NOMEM;
   }else{
     JsonNode *pNode;
     if( idxNum==3 ){
+      const char *zErr = 0;
       p->bRecursive = 0;
       n = sqlite3_value_bytes(argv[1]);
       p->zPath = sqlite3_malloc64( n+1 );
       if( p->zPath==0 ) return SQLITE_NOMEM;
       memcpy(p->zPath, zPath, (size_t)n+1);
-      pNode = jsonLookup(&p->sParse, 0, p->zPath+1, 0);
-      if( pNode==0 ){
+      pNode = jsonLookupStep(&p->sParse, 0, p->zPath+1, 0, &zErr);
+      if( p->sParse.nErr ){
+        sqlite3_free(cur->pVtab->zErrMsg);
+        cur->pVtab->zErrMsg = jsonPathSyntaxError(zErr);
         jsonEachCursorReset(p);
+        return cur->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM;
+      }else if( pNode==0 ){
         return SQLITE_OK;
       }
     }else{
index 630423411b9d17433c0ed96f991bbfa4ed23cd07..dda3e678a6f547a25b759f7802bce6c70b68c0c8 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Back\sout\sthe\sjson_check()\sroutine.\s\sInstead,\sthrow\san\serror\sif\sthe\sinput\sto\na\sjson\sfunction\s(other\sthan\sjson_valid())\sis\snot\svalid\sJSON.
-D 2015-08-28T20:07:40.320
+C Change\sthe\sjson1.c\smodule\sso\sthat\sit\sthrows\san\serror\sif\sany\sof\sthe\nJSON\sselector\spaths\sare\smalformed.
+D 2015-08-29T00:54:49.924
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in e2218eb228374422969de7b1680eda6864affcef
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -192,7 +192,7 @@ F ext/misc/eval.c f971962e92ebb8b0a4e6b62949463ee454d88fa2
 F ext/misc/fileio.c d4171c815d6543a9edef8308aab2951413cd8d0f
 F ext/misc/fuzzer.c 4c84635c71c26cfa7c2e5848cf49fe2d2cfcd767
 F ext/misc/ieee754.c b0362167289170627659e84173f5d2e8fee8566e
-F ext/misc/json1.c aa344845c2c211e8a7fd57ccd92901506dacdf5a
+F ext/misc/json1.c 063bf62fd44a06aa06fd22854fff09679cbb855f
 F ext/misc/nextchar.c 35c8b8baacb96d92abbb34a83a997b797075b342
 F ext/misc/percentile.c bcbee3c061b884eccb80e21651daaae8e1e43c63
 F ext/misc/regexp.c af92cdaa5058fcec1451e49becc7ba44dba023dc
@@ -1380,7 +1380,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
 F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b
 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P 0fdc36fe35ae2fc8e9688fe6c53437f4d47502d9
-R 72483a04f1004ed82fe324bdb4440aeb
+P dc9ce7b18cbe23d065317757234ef9fb8792da7a
+R 7515083280f6e706dffbefc132c1a59a
 U drh
-Z 66ee5efb60acb350500ed2a1605628ef
+Z f18bb212545a9a98b8ef3bc5262369aa
index b5b08b89f44d46a7e64039a06fadac8dfa0c4f7a..19c1a062078837a9d62ebc2af2e38ad174da0e7d 100644 (file)
@@ -1 +1 @@
-dc9ce7b18cbe23d065317757234ef9fb8792da7a
\ No newline at end of file
+3aa0855fd463076fc3277f1d9fe00d2f30e6b449
\ No newline at end of file