/ Check-in [0a72726d]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Do not allow virtual table constructors to be called recursively.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 0a72726da21581ab16cb3e964bd825b8f2e931e4
User & Date: dan 2015-04-10 07:55:07
References
2015-05-21
01:04
Do not allow virtual table constructors to be called recursively. Cherrypick [0a72726da21581ab] check-in: 0f0694e4 user: drh tags: branch-3.7.11
2015-05-20
19:50
Do not allow virtual table constructors to be called recursively. Cherrypick of [0a72726da215] check-in: 023a29ba user: dan tags: branch-3.8.6
Context
2015-05-21
01:04
Do not allow virtual table constructors to be called recursively. Cherrypick [0a72726da21581ab] check-in: 0f0694e4 user: drh tags: branch-3.7.11
2015-05-20
19:50
Do not allow virtual table constructors to be called recursively. Cherrypick of [0a72726da215] check-in: 023a29ba user: dan tags: branch-3.8.6
2015-04-10
12:04
Fix foreign key CASCADE for cases where the parent key is an INTEGER PRIMARY KEY and the parent table contains other columns named "rowid", "_rowid_", and "oid". check-in: ed3cbaab user: drh tags: trunk
08:20
Update this branch with latest trunk changes. check-in: 60be9c1c user: dan tags: sorter-opt
07:55
Do not allow virtual table constructors to be called recursively. check-in: 0a72726d user: dan tags: trunk
2015-04-09
19:39
Fix incorrect column names in UPDATE statements generated by the sqldiff utility. check-in: ee53b460 user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to ext/fts3/fts3.c.

  1015   1015   */
  1016   1016   static int fts3ContentColumns(
  1017   1017     sqlite3 *db,                    /* Database handle */
  1018   1018     const char *zDb,                /* Name of db (i.e. "main", "temp" etc.) */
  1019   1019     const char *zTbl,               /* Name of content table */
  1020   1020     const char ***pazCol,           /* OUT: Malloc'd array of column names */
  1021   1021     int *pnCol,                     /* OUT: Size of array *pazCol */
  1022         -  int *pnStr                      /* OUT: Bytes of string content */
         1022  +  int *pnStr,                     /* OUT: Bytes of string content */
         1023  +  char **pzErr                    /* OUT: error message */
  1023   1024   ){
  1024   1025     int rc = SQLITE_OK;             /* Return code */
  1025   1026     char *zSql;                     /* "SELECT *" statement on zTbl */  
  1026   1027     sqlite3_stmt *pStmt = 0;        /* Compiled version of zSql */
  1027   1028   
  1028   1029     zSql = sqlite3_mprintf("SELECT * FROM %Q.%Q", zDb, zTbl);
  1029   1030     if( !zSql ){
  1030   1031       rc = SQLITE_NOMEM;
  1031   1032     }else{
  1032   1033       rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0);
         1034  +    if( rc!=SQLITE_OK ){
         1035  +      *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
         1036  +    }
  1033   1037     }
  1034   1038     sqlite3_free(zSql);
  1035   1039   
  1036   1040     if( rc==SQLITE_OK ){
  1037   1041       const char **azCol;           /* Output array */
  1038   1042       int nStr = 0;                 /* Size of all column names (incl. 0x00) */
  1039   1043       int nCol;                     /* Number of table columns */
................................................................................
  1277   1281       sqlite3_free(zCompress); 
  1278   1282       sqlite3_free(zUncompress); 
  1279   1283       zCompress = 0;
  1280   1284       zUncompress = 0;
  1281   1285       if( nCol==0 ){
  1282   1286         sqlite3_free((void*)aCol); 
  1283   1287         aCol = 0;
  1284         -      rc = fts3ContentColumns(db, argv[1], zContent, &aCol, &nCol, &nString);
         1288  +      rc = fts3ContentColumns(db, argv[1], zContent,&aCol,&nCol,&nString,pzErr);
  1285   1289   
  1286   1290         /* If a languageid= option was specified, remove the language id
  1287   1291         ** column from the aCol[] array. */ 
  1288   1292         if( rc==SQLITE_OK && zLanguageid ){
  1289   1293           int j;
  1290   1294           for(j=0; j<nCol; j++){
  1291   1295             if( sqlite3_stricmp(zLanguageid, aCol[j])==0 ){

Changes to src/vtab.c.

    20     20   ** this struct allocated on the stack. It is used by the implementation of 
    21     21   ** the sqlite3_declare_vtab() and sqlite3_vtab_config() APIs, both of which
    22     22   ** are invoked only from within xCreate and xConnect methods.
    23     23   */
    24     24   struct VtabCtx {
    25     25     VTable *pVTable;    /* The virtual table being constructed */
    26     26     Table *pTab;        /* The Table object to which the virtual table belongs */
           27  +  VtabCtx *pPrior;    /* Parent context (if any) */
           28  +  int bDeclared;      /* True after sqlite3_declare_vtab() is called */
    27     29   };
    28     30   
    29     31   /*
    30     32   ** The actual function that does the work of creating a new module.
    31     33   ** This function implements the sqlite3_create_module() and
    32     34   ** sqlite3_create_module_v2() interfaces.
    33     35   */
................................................................................
   483    485   static int vtabCallConstructor(
   484    486     sqlite3 *db, 
   485    487     Table *pTab,
   486    488     Module *pMod,
   487    489     int (*xConstruct)(sqlite3*,void*,int,const char*const*,sqlite3_vtab**,char**),
   488    490     char **pzErr
   489    491   ){
   490         -  VtabCtx sCtx, *pPriorCtx;
          492  +  VtabCtx sCtx;
   491    493     VTable *pVTable;
   492    494     int rc;
   493    495     const char *const*azArg = (const char *const*)pTab->azModuleArg;
   494    496     int nArg = pTab->nModuleArg;
   495    497     char *zErr = 0;
   496         -  char *zModuleName = sqlite3MPrintf(db, "%s", pTab->zName);
          498  +  char *zModuleName;
   497    499     int iDb;
          500  +  VtabCtx *pCtx;
   498    501   
          502  +  /* Check that the virtual-table is not already being initialized */
          503  +  for(pCtx=db->pVtabCtx; pCtx; pCtx=pCtx->pPrior){
          504  +    if( pCtx->pTab==pTab ){
          505  +      *pzErr = sqlite3MPrintf(db, 
          506  +          "vtable constructor called recursively: %s", pTab->zName
          507  +      );
          508  +      return SQLITE_LOCKED;
          509  +    }
          510  +  }
          511  +
          512  +  zModuleName = sqlite3MPrintf(db, "%s", pTab->zName);
   499    513     if( !zModuleName ){
   500    514       return SQLITE_NOMEM;
   501    515     }
   502    516   
   503    517     pVTable = sqlite3DbMallocZero(db, sizeof(VTable));
   504    518     if( !pVTable ){
   505    519       sqlite3DbFree(db, zModuleName);
................................................................................
   512    526     pTab->azModuleArg[1] = db->aDb[iDb].zName;
   513    527   
   514    528     /* Invoke the virtual table constructor */
   515    529     assert( &db->pVtabCtx );
   516    530     assert( xConstruct );
   517    531     sCtx.pTab = pTab;
   518    532     sCtx.pVTable = pVTable;
   519         -  pPriorCtx = db->pVtabCtx;
          533  +  sCtx.pPrior = db->pVtabCtx;
          534  +  sCtx.bDeclared = 0;
   520    535     db->pVtabCtx = &sCtx;
   521    536     rc = xConstruct(db, pMod->pAux, nArg, azArg, &pVTable->pVtab, &zErr);
   522         -  db->pVtabCtx = pPriorCtx;
          537  +  db->pVtabCtx = sCtx.pPrior;
   523    538     if( rc==SQLITE_NOMEM ) db->mallocFailed = 1;
          539  +  assert( sCtx.pTab==pTab );
   524    540   
   525    541     if( SQLITE_OK!=rc ){
   526    542       if( zErr==0 ){
   527    543         *pzErr = sqlite3MPrintf(db, "vtable constructor failed: %s", zModuleName);
   528    544       }else {
   529    545         *pzErr = sqlite3MPrintf(db, "%s", zErr);
   530    546         sqlite3_free(zErr);
................................................................................
   532    548       sqlite3DbFree(db, pVTable);
   533    549     }else if( ALWAYS(pVTable->pVtab) ){
   534    550       /* Justification of ALWAYS():  A correct vtab constructor must allocate
   535    551       ** the sqlite3_vtab object if successful.  */
   536    552       memset(pVTable->pVtab, 0, sizeof(pVTable->pVtab[0]));
   537    553       pVTable->pVtab->pModule = pMod->pModule;
   538    554       pVTable->nRef = 1;
   539         -    if( sCtx.pTab ){
          555  +    if( sCtx.bDeclared==0 ){
   540    556         const char *zFormat = "vtable constructor did not declare schema: %s";
   541    557         *pzErr = sqlite3MPrintf(db, zFormat, pTab->zName);
   542    558         sqlite3VtabUnlock(pVTable);
   543    559         rc = SQLITE_ERROR;
   544    560       }else{
   545    561         int iCol;
   546    562         /* If everything went according to plan, link the new VTable structure
................................................................................
   702    718   
   703    719   /*
   704    720   ** This function is used to set the schema of a virtual table.  It is only
   705    721   ** valid to call this function from within the xCreate() or xConnect() of a
   706    722   ** virtual table module.
   707    723   */
   708    724   int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
          725  +  VtabCtx *pCtx = db->pVtabCtx;
   709    726     Parse *pParse;
   710         -
   711    727     int rc = SQLITE_OK;
   712    728     Table *pTab;
   713    729     char *zErr = 0;
   714    730   
   715    731   #ifdef SQLITE_ENABLE_API_ARMOR
   716    732     if( !sqlite3SafetyCheckOk(db) || zCreateTable==0 ){
   717    733       return SQLITE_MISUSE_BKPT;
   718    734     }
   719    735   #endif
   720    736     sqlite3_mutex_enter(db->mutex);
   721         -  if( !db->pVtabCtx || !(pTab = db->pVtabCtx->pTab) ){
          737  +  if( !pCtx || pCtx->bDeclared ){
   722    738       sqlite3Error(db, SQLITE_MISUSE);
   723    739       sqlite3_mutex_leave(db->mutex);
   724    740       return SQLITE_MISUSE_BKPT;
   725    741     }
          742  +  pTab = pCtx->pTab;
   726    743     assert( (pTab->tabFlags & TF_Virtual)!=0 );
   727    744   
   728    745     pParse = sqlite3StackAllocZero(db, sizeof(*pParse));
   729    746     if( pParse==0 ){
   730    747       rc = SQLITE_NOMEM;
   731    748     }else{
   732    749       pParse->declareVtab = 1;
................................................................................
   741    758       ){
   742    759         if( !pTab->aCol ){
   743    760           pTab->aCol = pParse->pNewTable->aCol;
   744    761           pTab->nCol = pParse->pNewTable->nCol;
   745    762           pParse->pNewTable->nCol = 0;
   746    763           pParse->pNewTable->aCol = 0;
   747    764         }
   748         -      db->pVtabCtx->pTab = 0;
          765  +      pCtx->bDeclared = 1;
   749    766       }else{
   750    767         sqlite3ErrorWithMsg(db, SQLITE_ERROR, (zErr ? "%s" : 0), zErr);
   751    768         sqlite3DbFree(db, zErr);
   752    769         rc = SQLITE_ERROR;
   753    770       }
   754    771       pParse->declareVtab = 0;
   755    772     

Changes to test/fts4content.test.

    44     44   #         SELECT statements.
    45     45   #
    46     46   #   8.* - Test that if the content=xxx and prefix options are used together,
    47     47   #         the 'rebuild' command still works.
    48     48   #
    49     49   #   9.* - Test using content=xxx where xxx is a virtual table.
    50     50   #
           51  +#   11.* - Test that circular references (e.g. "t1(content=t1)") are
           52  +#          detected.
           53  +#
    51     54   
    52     55   do_execsql_test 1.1.1 {
    53     56     CREATE TABLE t1(a, b, c);
    54     57     INSERT INTO t1 VALUES('w x', 'x y', 'y z');
    55     58     CREATE VIRTUAL TABLE ft1 USING fts4(content=t1);
    56     59   }
    57     60   
................................................................................
   402    405   }
   403    406   
   404    407   #-------------------------------------------------------------------------
   405    408   # Test cases 6.* test 
   406    409   # 
   407    410   do_catchsql_test 6.1.1 {
   408    411     CREATE VIRTUAL TABLE ft7 USING fts4(content=t7);
   409         -} {1 {vtable constructor failed: ft7}}
          412  +} {1 {no such table: main.t7}}
   410    413   
   411    414   do_execsql_test 6.2.1 {
   412    415     CREATE TABLE t7(one, two);
   413    416     CREATE VIRTUAL TABLE ft7 USING fts4(content=t7);
   414    417     INSERT INTO t7 VALUES('A B', 'B A');
   415    418     INSERT INTO t7 VALUES('C D', 'A A');
   416    419     SELECT * FROM ft7;
................................................................................
   429    432     SELECT name FROM sqlite_master WHERE name LIKE '%t7%'
   430    433   } {
   431    434     ft7 ft7_segments ft7_segdir sqlite_autoindex_ft7_segdir_1 
   432    435     ft7_docsize ft7_stat
   433    436   }
   434    437   do_catchsql_test 6.2.4 {
   435    438     SELECT * FROM ft7;
   436         -} {1 {vtable constructor failed: ft7}}
          439  +} {1 {no such table: main.t7}}
   437    440   do_execsql_test 6.2.5 {
   438    441     CREATE TABLE t7(x, y);
   439    442     INSERT INTO t7 VALUES('A B', 'B A');
   440    443     INSERT INTO t7 VALUES('C D', 'A A');
   441    444     SELECT * FROM ft7;
   442    445   } {
   443    446     {A B} {B A} {C D} {A A}
................................................................................
   617    620   do_execsql_test 10.6 { DELETE FROM ft WHERE docid=2 }
   618    621   
   619    622   do_execsql_test 10.7 {
   620    623     SELECT snippet(ft, '[', ']', '...', -1, 5) FROM ft WHERE ft MATCH 'e'
   621    624   } {
   622    625     {...c d [e] f g...}
   623    626   }
          627  +
          628  +#-------------------------------------------------------------------------
          629  +# Test cases 11.*
          630  +# 
          631  +reset_db
          632  +
          633  +do_catchsql_test 11.1 {
          634  +  CREATE VIRTUAL TABLE x1 USING fts4(content=x1);
          635  +} {1 {vtable constructor called recursively: x1}}
          636  +
   624    637   
   625    638   finish_test
          639  +