mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-29 08:01:23 +03:00
Fix a use-after-free error that could occur if an fts5 table is written while scanning it using an fts5vocab cursor.
FossilOrigin-Name: e751c2ec786b5c1a1c9640fdc3fde036879a2c32db2bd67fe7c72604780f67b8
This commit is contained in:
@ -837,6 +837,40 @@ int sqlite3Fts5StructureTest(Fts5Index *p, void *pStruct){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Ensure that structure object (*pp) is writable.
|
||||
**
|
||||
** This function is a no-op if (*pRc) is not SQLITE_OK when it is called. If
|
||||
** an error occurs, (*pRc) is set to an SQLite error code before returning.
|
||||
*/
|
||||
static void fts5StructureMakeWritable(int *pRc, Fts5Structure **pp){
|
||||
Fts5Structure *p = *pp;
|
||||
if( *pRc==SQLITE_OK && p->nRef>1 ){
|
||||
int nByte = sizeof(Fts5Structure)+(p->nLevel-1)*sizeof(Fts5StructureLevel);
|
||||
Fts5Structure *pNew;
|
||||
pNew = (Fts5Structure*)sqlite3Fts5MallocZero(pRc, nByte);
|
||||
if( pNew ){
|
||||
int i;
|
||||
memcpy(pNew, p, nByte);
|
||||
for(i=0; i<p->nLevel; i++) pNew->aLevel[i].aSeg = 0;
|
||||
for(i=0; i<p->nLevel; i++){
|
||||
Fts5StructureLevel *pLvl = &pNew->aLevel[i];
|
||||
int nByte = sizeof(Fts5StructureSegment) * pNew->aLevel[i].nSeg;
|
||||
pLvl->aSeg = (Fts5StructureSegment*)sqlite3Fts5MallocZero(pRc, nByte);
|
||||
if( pLvl->aSeg==0 ){
|
||||
for(i=0; i<p->nLevel; i++){
|
||||
sqlite3_free(pNew->aLevel[i].aSeg);
|
||||
}
|
||||
sqlite3_free(pNew);
|
||||
return;
|
||||
}
|
||||
memcpy(pLvl->aSeg, p->aLevel[i].aSeg, nByte);
|
||||
}
|
||||
}
|
||||
*pp = pNew;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Deserialize and return the structure record currently stored in serialized
|
||||
** form within buffer pData/nData.
|
||||
@ -938,9 +972,11 @@ static int fts5StructureDecode(
|
||||
}
|
||||
|
||||
/*
|
||||
**
|
||||
** Add a level to the Fts5Structure.aLevel[] array of structure object
|
||||
** (*ppStruct).
|
||||
*/
|
||||
static void fts5StructureAddLevel(int *pRc, Fts5Structure **ppStruct){
|
||||
fts5StructureMakeWritable(pRc, ppStruct);
|
||||
if( *pRc==SQLITE_OK ){
|
||||
Fts5Structure *pStruct = *ppStruct;
|
||||
int nLevel = pStruct->nLevel;
|
||||
|
@ -255,6 +255,27 @@ do_test 5.1 {
|
||||
do_execsql_test 5.2 {
|
||||
SELECT * FROM t1
|
||||
} {one two three four five}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Check that the fts5 table cannot be written while there are vocab
|
||||
# cursors open.
|
||||
reset_db
|
||||
do_execsql_test 5.0 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(a);
|
||||
CREATE VIRTUAL TABLE v1 USING fts5vocab(t1, instance);
|
||||
WITH s(i) AS (
|
||||
VALUES(1) UNION ALL SELECT i+1 FROM s WHERE i<10000
|
||||
)
|
||||
INSERT INTO t1 SELECT
|
||||
'State Emergency Service (SES), Rural Fire Service (RFS) and Volunteers'
|
||||
FROM s;
|
||||
}
|
||||
|
||||
do_catchsql_test 5.1 {
|
||||
INSERT INTO t1 SELECT rowid FROM v1
|
||||
} {1 {query aborted}}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user