1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-11-16 23:02:26 +03:00

Fix a potential use-after-free following an OOM in sqlite3ParserAddCleanup()

and add a mechanism to detect situations where this might occur in the
future.

FossilOrigin-Name: 38ef8ab9830e12acd2c710e113939b1f8dced02612c6933c37a3c948a4030d0a
This commit is contained in:
drh
2021-01-12 15:30:01 +00:00
parent cf3c078f93
commit 21d4f5b53a
6 changed files with 36 additions and 19 deletions

View File

@@ -590,20 +590,28 @@ void sqlite3ParserReset(Parse *pParse){
/*
** Add a new cleanup operation to a Parser. The cleanup should happen when
** the parser object is destroyed.
** the parser object is destroyed. But, beware: the cleanup might happen
** immediately.
**
** Use this mechanism for uncommon cleanups. There is a higher setup
** cost, so this should not be used for common cleanups. But for less
** cost for this mechansim (an extra malloc), so it should not be used
** for common cleanups that happen on most calls. But for less
** common cleanups, we save a single NULL-pointer comparison in
** sqlite3ParserReset(), which makes a surprising difference in total
** performance.
** sqlite3ParserReset(), which reduces the total CPU cycle count.
**
** If a memory allocation error occurs, then the cleanup happens immediately.
** When eithr SQLITE_DEBUG or SQLITE_COVERAGE_TEST are defined, the
** pParse->earlyCleanup flag is set in that case. Calling code show verify
** that test cases exist for which this happens, to guard against possible
** use-after-free errors following an OOM. The preferred way to do this is
** to immediately follow the call to this routine with:
**
** testcase( pParse->earlyCleanup );
*/
void sqlite3ParserAddCleanup(
Parse *pParse,
void (*xCleanup)(sqlite3*,void*),
void *pPtr
Parse *pParse, /* Destroy when this Parser finishes */
void (*xCleanup)(sqlite3*,void*), /* The cleanup routine */
void *pPtr /* Pointer to object to be cleaned up */
){
ParseCleanup *pCleanup = sqlite3DbMallocRaw(pParse->db, sizeof(*pCleanup));
if( pCleanup ){
@@ -613,6 +621,9 @@ void sqlite3ParserAddCleanup(
pCleanup->xCleanup = xCleanup;
}else{
xCleanup(pParse->db, pPtr);
#if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST)
pParse->earlyCleanup = 1;
#endif
}
}