# UNDF: UNDF-2026-000000299 diff --git a/src/trigger.c b/src/trigger.c index 4f9068a..5da63ac 100644 --- a/src/trigger.c +++ b/src/trigger.c @@ -781,10 +781,33 @@ void sqlite3UnlinkAndDeleteTrigger(sqlite3 *db, int iDb, const char *zName){ static int checkColumnOverlap(IdList *pIdList, ExprList *pEList){ int e; if( pIdList==0 || NEVER(pEList==0) ) return 1; + /* CWE-407 fix: for large column-overlap checks, build a hash set of the + ** trigger's watched-column names (pIdList) so each SET-column lookup is + ** O(1) instead of O(|pIdList|). SQLite's Hash uses a case-insensitive + ** key, matching sqlite3IdListIndex semantics. For small lists the linear + ** scan is kept; on OOM the hash count will be less than nId and we fall + ** back to the linear scan as well. */ + if( pIdList->nId>4 && pEList->nExpr>4 ){ + Hash h; + int i, found; + sqlite3HashInit(&h); + for(i=0; inId; i++){ + sqlite3HashInsert(&h, pIdList->a[i].zName, pIdList->a[i].zName); + } + if( h.count==pIdList->nId ){ + found = 0; + for(e=0; enExpr && !found; e++){ + if( sqlite3HashFind(&h, pEList->a[e].zEName) ) found = 1; + } + sqlite3HashClear(&h); + return found; + } + sqlite3HashClear(&h); /* OOM: fall through to linear scan */ + } for(e=0; enExpr; e++){ if( sqlite3IdListIndex(pIdList, pEList->a[e].zEName)>=0 ) return 1; } - return 0; + return 0; } /*