Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | The reuse-subroutine optimization [c9a3498113074bbc] might have generated byte-code that loops forever. This check-in fixes the problem. |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA3-256: |
0cc4ed8c6e53aca1f5e94c132bedbc7f |
User & Date: | drh 2025-01-30 21:12:58 |
Context
2025-01-31
| ||
00:54 | Merge all the latest trunk changes into the extra-security branch. (check-in: 86ba5756 user: drh tags: extra-security) | |
2025-01-30
| ||
21:16 | The reuse-subroutine optimization might have generated byte-code that loops forever. This check-in fixes the problem. (Leaf check-in: a8714e8c user: drh tags: branch-3.48) | |
21:12 | The reuse-subroutine optimization [c9a3498113074bbc] might have generated byte-code that loops forever. This check-in fixes the problem. (Leaf check-in: 0cc4ed8c user: drh tags: trunk) | |
16:07 | Remove an unused parameter from an internal-use subroutine in the TCL interface. (check-in: a700692b user: drh tags: trunk) | |
Changes
Changes to src/expr.c.
︙ | ︙ | |||
3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 | pOp = sqlite3VdbeGetOp(v, 1); pEnd = sqlite3VdbeGetLastOp(v); for(; pOp<pEnd; pOp++){ if( pOp->p4type!=P4_SUBRTNSIG ) continue; assert( pOp->opcode==OP_BeginSubrtn ); pSig = pOp->p4.pSubrtnSig; assert( pSig!=0 ); if( pNewSig->selId!=pSig->selId ) continue; if( strcmp(pNewSig->zAff,pSig->zAff)!=0 ) continue; pExpr->y.sub.iAddr = pSig->iAddr; pExpr->y.sub.regReturn = pSig->regReturn; pExpr->iTable = pSig->iTable; ExprSetProperty(pExpr, EP_Subrtn); return 1; | > | 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 | pOp = sqlite3VdbeGetOp(v, 1); pEnd = sqlite3VdbeGetLastOp(v); for(; pOp<pEnd; pOp++){ if( pOp->p4type!=P4_SUBRTNSIG ) continue; assert( pOp->opcode==OP_BeginSubrtn ); pSig = pOp->p4.pSubrtnSig; assert( pSig!=0 ); if( !pSig->bComplete ) continue; if( pNewSig->selId!=pSig->selId ) continue; if( strcmp(pNewSig->zAff,pSig->zAff)!=0 ) continue; pExpr->y.sub.iAddr = pSig->iAddr; pExpr->y.sub.regReturn = pSig->regReturn; pExpr->iTable = pSig->iTable; ExprSetProperty(pExpr, EP_Subrtn); return 1; |
︙ | ︙ | |||
3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 | ){ int addrOnce = 0; /* Address of the OP_Once instruction at top */ int addr; /* Address of OP_OpenEphemeral instruction */ Expr *pLeft; /* the LHS of the IN operator */ KeyInfo *pKeyInfo = 0; /* Key information */ int nVal; /* Size of vector pLeft */ Vdbe *v; /* The prepared statement under construction */ v = pParse->pVdbe; assert( v!=0 ); /* The evaluation of the IN must be repeated every time it ** is encountered if any of the following is true: ** ** * The right-hand side is a correlated subquery ** * The right-hand side is an expression list containing variables ** * We are inside a trigger ** ** If all of the above are false, then we can compute the RHS just once ** and reuse it many names. */ if( !ExprHasProperty(pExpr, EP_VarSelect) && pParse->iSelfTab==0 ){ /* Reuse of the RHS is allowed ** ** Compute a signature for the RHS of the IN operator to facility ** finding and reusing prior instances of the same IN operator. */ | > < | 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 | ){ int addrOnce = 0; /* Address of the OP_Once instruction at top */ int addr; /* Address of OP_OpenEphemeral instruction */ Expr *pLeft; /* the LHS of the IN operator */ KeyInfo *pKeyInfo = 0; /* Key information */ int nVal; /* Size of vector pLeft */ Vdbe *v; /* The prepared statement under construction */ SubrtnSig *pSig = 0; /* Signature for this subroutine */ v = pParse->pVdbe; assert( v!=0 ); /* The evaluation of the IN must be repeated every time it ** is encountered if any of the following is true: ** ** * The right-hand side is a correlated subquery ** * The right-hand side is an expression list containing variables ** * We are inside a trigger ** ** If all of the above are false, then we can compute the RHS just once ** and reuse it many names. */ if( !ExprHasProperty(pExpr, EP_VarSelect) && pParse->iSelfTab==0 ){ /* Reuse of the RHS is allowed ** ** Compute a signature for the RHS of the IN operator to facility ** finding and reusing prior instances of the same IN operator. */ assert( !ExprUseXSelect(pExpr) || pExpr->x.pSelect!=0 ); if( ExprUseXSelect(pExpr) && (pExpr->x.pSelect->selFlags & SF_All)==0 ){ pSig = sqlite3DbMallocRawNN(pParse->db, sizeof(pSig[0])); if( pSig ){ pSig->selId = pExpr->x.pSelect->selId; pSig->zAff = exprINAffinity(pParse, pExpr); } |
︙ | ︙ | |||
3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 | assert( !ExprUseYWin(pExpr) ); ExprSetProperty(pExpr, EP_Subrtn); assert( !ExprHasProperty(pExpr, EP_TokenOnly|EP_Reduced) ); pExpr->y.sub.regReturn = ++pParse->nMem; pExpr->y.sub.iAddr = sqlite3VdbeAddOp2(v, OP_BeginSubrtn, 0, pExpr->y.sub.regReturn) + 1; if( pSig ){ pSig->iAddr = pExpr->y.sub.iAddr; pSig->regReturn = pExpr->y.sub.regReturn; pSig->iTable = iTab; pParse->mSubrtnSig = 1 << (pSig->selId&7); sqlite3VdbeChangeP4(v, -1, (const char*)pSig, P4_SUBRTNSIG); } addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); | > | 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 | assert( !ExprUseYWin(pExpr) ); ExprSetProperty(pExpr, EP_Subrtn); assert( !ExprHasProperty(pExpr, EP_TokenOnly|EP_Reduced) ); pExpr->y.sub.regReturn = ++pParse->nMem; pExpr->y.sub.iAddr = sqlite3VdbeAddOp2(v, OP_BeginSubrtn, 0, pExpr->y.sub.regReturn) + 1; if( pSig ){ pSig->bComplete = 0; pSig->iAddr = pExpr->y.sub.iAddr; pSig->regReturn = pExpr->y.sub.regReturn; pSig->iTable = iTab; pParse->mSubrtnSig = 1 << (pSig->selId&7); sqlite3VdbeChangeP4(v, -1, (const char*)pSig, P4_SUBRTNSIG); } addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); |
︙ | ︙ | |||
3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 | sqlite3ExprCode(pParse, pE2, r1); sqlite3VdbeAddOp4(v, OP_MakeRecord, r1, 1, r2, &affinity, 1); sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iTab, r2, r1, 1); } sqlite3ReleaseTempReg(pParse, r1); sqlite3ReleaseTempReg(pParse, r2); } if( pKeyInfo ){ sqlite3VdbeChangeP4(v, addr, (void *)pKeyInfo, P4_KEYINFO); } if( addrOnce ){ sqlite3VdbeAddOp1(v, OP_NullRow, iTab); sqlite3VdbeJumpHere(v, addrOnce); /* Subroutine return */ | > | 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 | sqlite3ExprCode(pParse, pE2, r1); sqlite3VdbeAddOp4(v, OP_MakeRecord, r1, 1, r2, &affinity, 1); sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iTab, r2, r1, 1); } sqlite3ReleaseTempReg(pParse, r1); sqlite3ReleaseTempReg(pParse, r2); } if( pSig ) pSig->bComplete = 1; if( pKeyInfo ){ sqlite3VdbeChangeP4(v, addr, (void *)pKeyInfo, P4_KEYINFO); } if( addrOnce ){ sqlite3VdbeAddOp1(v, OP_NullRow, iTab); sqlite3VdbeJumpHere(v, addrOnce); /* Subroutine return */ |
︙ | ︙ |
Changes to src/vdbe.h.
︙ | ︙ | |||
36 37 38 39 40 41 42 43 44 45 46 47 48 49 | /* ** A signature for a reusable subroutine that materializes the RHS of ** an IN operator. */ struct SubrtnSig { int selId; /* SELECT-id for the SELECT statement on the RHS */ char *zAff; /* Affinity of the overall IN expression */ int iTable; /* Ephemeral table generated by the subroutine */ int iAddr; /* Subroutine entry address */ int regReturn; /* Register used to hold return address */ }; /* | > | 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | /* ** A signature for a reusable subroutine that materializes the RHS of ** an IN operator. */ struct SubrtnSig { int selId; /* SELECT-id for the SELECT statement on the RHS */ u8 bComplete; /* True if fully coded and available for reusable */ char *zAff; /* Affinity of the overall IN expression */ int iTable; /* Ephemeral table generated by the subroutine */ int iAddr; /* Subroutine entry address */ int regReturn; /* Register used to hold return address */ }; /* |
︙ | ︙ |
Changes to test/in7.test.
︙ | ︙ | |||
214 215 216 217 218 219 220 221 222 | } {1 1} do_execsql_test 3.7 { SELECT t1.a, t2.b FROM t1, t2 WHERE (t1.a, t2.b) = (1, 2); } {1 2} do_execsql_test 3.8 { SELECT t1.a, t2.b FROM t1, t2 WHERE (t1.a, t2.b) IN ((1, 2)); } {1 2} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 | } {1 1} do_execsql_test 3.7 { SELECT t1.a, t2.b FROM t1, t2 WHERE (t1.a, t2.b) = (1, 2); } {1 2} do_execsql_test 3.8 { SELECT t1.a, t2.b FROM t1, t2 WHERE (t1.a, t2.b) IN ((1, 2)); } {1 2} # 2025-01-30 Inifinite loop in byte-code discovered by dbsqlfuzz # having to do with SubrtnSig logic. The code was using a Subroutine # from within itself resulting in infinite recursion. # # This test will spin forever if the bug has not been fixed, or if # it reappears. # reset_db do_execsql_test 4.0 { CREATE TABLE t1(a INTEGER PRIMARY KEY, b); INSERT INTO t1 VALUES(1,x'1111'); CREATE TABLE t2(c); CREATE TABLE t3(d); CREATE TRIGGER t1tr UPDATE ON t1 BEGIN UPDATE t1 SET b=x'2222' FROM t2; UPDATE t1 SET b = (SELECT a IN (SELECT a FROM t1 WHERE (b,a) IN (SELECT rowid, d FROM t3 ) ) FROM t1 NATURAL RIGHT JOIN t1 ); END; UPDATE t1 SET b=x'3333'; SELECT quote(b) FROM t1; } {X'3333'} finish_test |