/ Check-in [18e10f81]
Login

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

Overview
Comment:Fix database corrupting code generation error for UPDATE OR REPLACE. ticket #2832. Still need to add test cases and additional defensive logic to avoid future occurrences of similar problems. (CVS 4613)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 18e10f816782ca7842f651e9b2a23da1aab645c8
User & Date: drh 2007-12-12 12:25:22
Context
2007-12-12
14:46
Test file containing minimal example of bug #2832. (CVS 4614) check-in: ed2e61a9 user: danielk1977 tags: trunk
12:25
Fix database corrupting code generation error for UPDATE OR REPLACE. ticket #2832. Still need to add test cases and additional defensive logic to avoid future occurrences of similar problems. (CVS 4613) check-in: 18e10f81 user: drh tags: trunk
12:00
Add a new OP_StackDepth opcode to help detect VDBE stack leaks early, before they cause damage. For diagnostics in ticket #2832. (CVS 4612) check-in: 3fd6a267 user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/sqlite.h.in.

    26     26   ** on how SQLite interfaces are suppose to operate.
    27     27   **
    28     28   ** The name of this file under configuration management is "sqlite.h.in".
    29     29   ** The makefile makes some minor changes to this file (such as inserting
    30     30   ** the version number) and changes its name to "sqlite3.h" as
    31     31   ** part of the build process.
    32     32   **
    33         -** @(#) $Id: sqlite.h.in,v 1.276 2007/12/06 02:42:08 drh Exp $
           33  +** @(#) $Id: sqlite.h.in,v 1.277 2007/12/12 12:25:22 drh Exp $
    34     34   */
    35     35   #ifndef _SQLITE3_H_
    36     36   #define _SQLITE3_H_
    37     37   #include <stdarg.h>     /* Needed for the definition of va_list */
    38     38   
    39     39   /*
    40     40   ** Make sure we can call this stuff from C++.
................................................................................
   294    294   **
   295    295   ** See also: [SQLITE_IOERR_READ | extended result codes]
   296    296   **
   297    297   */
   298    298   #define SQLITE_OK           0   /* Successful result */
   299    299   /* beginning-of-error-codes */
   300    300   #define SQLITE_ERROR        1   /* SQL error or missing database */
   301         -#define SQLITE_INTERNAL     2   /* NOT USED. Internal logic error in SQLite */
          301  +#define SQLITE_INTERNAL     2   /* Internal logic error in SQLite */
   302    302   #define SQLITE_PERM         3   /* Access permission denied */
   303    303   #define SQLITE_ABORT        4   /* Callback routine requested an abort */
   304    304   #define SQLITE_BUSY         5   /* The database file is locked */
   305    305   #define SQLITE_LOCKED       6   /* A table in the database is locked */
   306    306   #define SQLITE_NOMEM        7   /* A malloc() failed */
   307    307   #define SQLITE_READONLY     8   /* Attempt to write a readonly database */
   308    308   #define SQLITE_INTERRUPT    9   /* Operation terminated by sqlite3_interrupt()*/

Changes to src/update.c.

     8      8   **    May you find forgiveness for yourself and forgive others.
     9      9   **    May you share freely, never taking more than you give.
    10     10   **
    11     11   *************************************************************************
    12     12   ** This file contains C code routines that are called by the parser
    13     13   ** to handle UPDATE statements.
    14     14   **
    15         -** $Id: update.c,v 1.142 2007/12/12 12:00:46 drh Exp $
           15  +** $Id: update.c,v 1.143 2007/12/12 12:25:22 drh Exp $
    16     16   */
    17     17   #include "sqliteInt.h"
    18     18   
    19     19   #ifndef SQLITE_OMIT_VIRTUALTABLE
    20     20   /* Forward declaration */
    21     21   static void updateVirtualTable(
    22     22     Parse *pParse,       /* The parsing context */
................................................................................
   101    101     int chngRowid;         /* True if the record number is being changed */
   102    102     Expr *pRowidExpr = 0;  /* Expression defining the new record number */
   103    103     int openAll = 0;       /* True if all indices need to be opened */
   104    104     AuthContext sContext;  /* The authorization context */
   105    105     NameContext sNC;       /* The name-context to resolve expressions in */
   106    106     int iDb;               /* Database containing the table being updated */
   107    107     int memCnt = 0;        /* Memory cell used for counting rows changed */
          108  +  int mem1;      /* Memory address storing the rowid for next row to update */
   108    109   
   109    110   #ifndef SQLITE_OMIT_TRIGGER
   110    111     int isView;                  /* Trying to update a view */
   111    112     int triggers_exist = 0;      /* True if any row triggers exist */
   112    113   #endif
   113    114   
   114    115     int newIdx      = -1;  /* index of trigger "new" temp table       */
................................................................................
   257    258   
   258    259     /* Begin generating code.
   259    260     */
   260    261     v = sqlite3GetVdbe(pParse);
   261    262     if( v==0 ) goto update_cleanup;
   262    263     if( pParse->nested==0 ) sqlite3VdbeCountChanges(v);
   263    264     sqlite3BeginWriteOperation(pParse, 1, iDb);
          265  +  mem1 = pParse->nMem++;
   264    266   
   265    267   #ifndef SQLITE_OMIT_VIRTUALTABLE
   266    268     /* Virtual tables must be handled separately */
   267    269     if( IsVirtual(pTab) ){
   268    270       updateVirtualTable(pParse, pTabList, pTab, pChanges, pRowidExpr, aXRef,
   269    271                          pWhere);
   270    272       pWhere = 0;
................................................................................
   314    316     */
   315    317     if( db->flags & SQLITE_CountRows && !pParse->trigStack ){
   316    318       memCnt = pParse->nMem++;
   317    319       sqlite3VdbeAddOp(v, OP_MemInt, 0, memCnt);
   318    320     }
   319    321   
   320    322     if( triggers_exist ){
   321         -    int mem1;      /* Memory address storing the rowid for next row to update */
   322    323       
   323    324       /* Create pseudo-tables for NEW and OLD
   324    325       */
   325    326       sqlite3VdbeAddOp(v, OP_OpenPseudo, oldIdx, 0);
   326    327       sqlite3VdbeAddOp(v, OP_SetNumColumns, oldIdx, pTab->nCol);
   327    328       sqlite3VdbeAddOp(v, OP_OpenPseudo, newIdx, 0);
   328    329       sqlite3VdbeAddOp(v, OP_SetNumColumns, newIdx, pTab->nCol);
   329    330   
   330    331       /* The top of the update loop for when there are triggers.
   331    332       */
   332    333       addr = sqlite3VdbeAddOp(v, OP_FifoRead, 0, 0);
   333    334       sqlite3VdbeAddOp(v, OP_StackDepth, -1, 0);
   334         -    mem1 = pParse->nMem++;
   335    335       sqlite3VdbeAddOp(v, OP_MemStore, mem1, 0);
   336    336       
   337    337       if( !isView ){
   338    338         /* Open a cursor and make it point to the record that is
   339    339         ** being updated.
   340    340         */
   341    341         sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenRead);
................................................................................
   383    383       if( sqlite3CodeRowTrigger(pParse, TK_UPDATE, pChanges, TRIGGER_BEFORE, pTab,
   384    384             newIdx, oldIdx, onError, addr) ){
   385    385         goto update_cleanup;
   386    386       }
   387    387       
   388    388       if( !isView ){
   389    389         sqlite3VdbeAddOp(v, OP_MemLoad, mem1, 0);
   390         -      sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
   391    390       }
   392    391     }
   393    392   
   394    393     if( !isView && !IsVirtual(pTab) ){
   395    394       /* 
   396    395       ** Open every index that needs updating.  Note that if any
   397    396       ** index could potentially invoke a REPLACE conflict resolution 
................................................................................
   425    424       ** might not change and we will need to copy the old value.
   426    425       ** Also, the old data is needed to delete the old index entries.
   427    426       ** So make the cursor point at the old record.
   428    427       */
   429    428       if( !triggers_exist ){
   430    429         addr = sqlite3VdbeAddOp(v, OP_FifoRead, 0, 0);
   431    430         sqlite3VdbeAddOp(v, OP_StackDepth, -1, 0);
   432         -      sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
          431  +      sqlite3VdbeAddOp(v, OP_MemStore, mem1, 0);
   433    432       }
   434    433       sqlite3VdbeAddOp(v, OP_NotExists, iCur, addr);
          434  +    sqlite3VdbeAddOp(v, OP_MemLoad, mem1, 0);
   435    435   
   436    436       /* If the record number will change, push the record number as it
   437    437       ** will be after the update. (The old record number is currently
   438    438       ** on top of the stack.)
   439    439       */
   440    440       if( chngRowid ){
   441    441         sqlite3ExprCode(pParse, pRowidExpr);

Changes to src/vdbe.c.

    39     39   **
    40     40   ** Various scripts scan this source file in order to generate HTML
    41     41   ** documentation, headers files, or other derived files.  The formatting
    42     42   ** of the code in this file is, therefore, important.  See other comments
    43     43   ** in this file for details.  If in doubt, do not deviate from existing
    44     44   ** commenting and indentation practices when changing or adding code.
    45     45   **
    46         -** $Id: vdbe.c,v 1.657 2007/12/12 12:00:46 drh Exp $
           46  +** $Id: vdbe.c,v 1.658 2007/12/12 12:25:22 drh Exp $
    47     47   */
    48     48   #include "sqliteInt.h"
    49     49   #include <ctype.h>
    50     50   #include "vdbeInt.h"
    51     51   
    52     52   /*
    53     53   ** The following global variable is incremented every time a cursor
................................................................................
   701    701   ** This opcode is used for internal consistency checking.
   702    702   */
   703    703   case OP_StackDepth: {       /* no-push */
   704    704     if( pOp->p1<0 ){
   705    705       pOp->p1 = pTos - p->aStack + 1;
   706    706     }else if( pOp->p1!=pTos - p->aStack + 1 ){
   707    707       p->pTos = pTos;
   708         -    p->rc = SQLITE_ERROR;
          708  +    p->rc = rc = SQLITE_INTERNAL;
   709    709       p->pc = pc;
   710    710       p->errorAction = OE_Rollback;
   711         -    sqlite3SetString(&p->zErrMsg, "internal VDBE stack overflow", (char*)0);
          711  +    sqlite3SetString(&p->zErrMsg, "internal error: VDBE stack leak", (char*)0);
   712    712       goto vdbe_return;
   713    713     }
   714    714     break;
   715    715   }
   716    716   
   717    717   /* Opcode: Integer P1 * *
   718    718   **