java-topology/defects/sqlite/patch/sqlite-0001-checkcolumnoverlap-hash.patch
russell@unturf.com 0a580b313d undefect. CWE-407 — 63 sites patched across 27 ecosystems
Authors: russell@unturf.com · brackishbert@gmail.com · foxhop.net · TimeHexOn.com

Patches, unit tests, benchmarks, whitepaper, and outreach briefs.
Public domain — no copyright claimed. Use freely.
2026-03-26 17:11:57 -04:00

39 lines
1.4 KiB
Diff

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; i<pIdList->nId; i++){
+ sqlite3HashInsert(&h, pIdList->a[i].zName, pIdList->a[i].zName);
+ }
+ if( h.count==pIdList->nId ){
+ found = 0;
+ for(e=0; e<pEList->nExpr && !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; e<pEList->nExpr; e++){
if( sqlite3IdListIndex(pIdList, pEList->a[e].zEName)>=0 ) return 1;
}
- return 0;
+ return 0;
}
/*