Bug report
Bug description:
A segmentation fault occurs in the _sqlite module when a connection is closed inside an aggregate step() callback. After sqlite3_step() returns, _pysqlite_query_execute() calls sqlite3_last_insert_rowid(self->connection->db) without verifying that self->connection->db is still valid.
If the connection was closed during the callback, self->connection->db becomes NULL, leading to a NULL pointer dereference inside sqlite3_last_insert_rowid().
Affected Code
Modules/_sqlite/cursor.c:974
lastrowid = sqlite3_last_insert_rowid (self -> connection -> db );
Reproducer
import sqlite3
conn = sqlite3 .connect (":memory:" , autocommit = True )
conn .execute ("CREATE TABLE t(x INTEGER)" )
for i in range (50 ):
conn .execute ("INSERT INTO t VALUES (?)" , (i ,))
class MyAgg :
def __init__ (self ):
self .total = 0
def step (self , value ):
self .total += value
conn .close ()
def finalize (self ):
return self .total
conn .create_aggregate ("agg_sum" , 1 , MyAgg )
conn .execute ("SELECT agg_sum(x) FROM t" ).fetchone ()
Result
AddressSanitizer :DEADLYSIGNAL
== = == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == ==
== 19418 == ERROR : AddressSanitizer : SEGV on unknown address 0x000000000038 (pc 0x742d9562d034 bp 0x7fffdf6c6360 sp 0x7fffdf6c62f8 T0 )
== 19418 == The signal is caused by a READ memory access .
== 19418 == Hint : address points to the zero page .
#0 0x742d9562d034 in sqlite3_last_insert_rowid (/lib/x86_64-linux-gnu/libsqlite3.so.0+0xaa034) (BuildId: f5959b839b5d4de9879dc3630ecde4d76d4be713)
#1 0x742d96bd55c5 in _pysqlite_query_execute Modules/_sqlite/cursor.c:974
#2 0x742d96bcdbc5 in pysqlite_connection_execute_impl Modules/_sqlite/connection.c:1848
#3 0x742d96bcdd60 in pysqlite_connection_execute Modules/_sqlite/clinic/connection.c.h:967
#4 0x5f5ad4a35cd6 in method_vectorcall_FASTCALL Objects/descrobject.c:402
#5 0x5f5ad4a15ccc in _PyObject_VectorcallTstate Include/internal/pycore_call.h:136
#6 0x5f5ad4a15dbf in PyObject_Vectorcall Objects/call.c:327
#7 0x5f5ad4c948b7 in _Py_VectorCallInstrumentation_StackRefSteal Python/ceval.c:769
#8 0x5f5ad4ca487b in _PyEval_EvalFrameDefault Python/generated_cases.c.h:1817
#9 0x5f5ad4cdbab0 in _PyEval_EvalFrame Include/internal/pycore_ceval.h:118
#10 0x5f5ad4cdbe16 in _PyEval_Vector Python/ceval.c:2132
#11 0x5f5ad4cdc0cc in PyEval_EvalCode Python/ceval.c:680
#12 0x5f5ad4ddf771 in run_eval_code_obj Python/pythonrun.c:1366
#13 0x5f5ad4ddfab7 in run_mod Python/pythonrun.c:1469
#14 0x5f5ad4de09ec in pyrun_file Python/pythonrun.c:1294
#15 0x5f5ad4de3822 in _PyRun_SimpleFileObject Python/pythonrun.c:518
#16 0x5f5ad4de3ace in _PyRun_AnyFileObject Python/pythonrun.c:81
#17 0x5f5ad4e38d76 in pymain_run_file_obj Modules/main.c:410
#18 0x5f5ad4e38fe3 in pymain_run_file Modules/main.c:429
#19 0x5f5ad4e3a7e1 in pymain_run_python Modules/main.c:691
#20 0x5f5ad4e3ae77 in Py_RunMain Modules/main.c:772
#21 0x5f5ad4e3b063 in pymain_main Modules/main.c:802
#22 0x5f5ad4e3b3e8 in Py_BytesMain Modules/main.c:826
#23 0x5f5ad48a0675 in main Programs/python.c:15
#24 0x742d9782a3b7 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
#25 0x742d9782a47a in __libc_start_main_impl ../csu/libc-start.c:360
#26 0x5f5ad48a05a4 in _start (/home/raminfp/Projects/cpython/python+0x2ee5a4) (BuildId: fde840bca26b2112d86f1a7490e122abaa6caef7)
AddressSanitizer can not provide additional info .
SUMMARY : AddressSanitizer : SEGV (/lib /x86_64 - linux - gnu /libsqlite3 .so .0 +0xaa034 ) (BuildId : f5959b839b5d4de9879dc3630ecde4d76d4be713 ) in sqlite3_last_insert_rowid
== 19418 == ABORTING
Suggested Fix
Add a NULL check before calling sqlite3_last_insert_rowid():
if (self -> connection -> db != NULL ) {
lastrowid = sqlite3_last_insert_rowid (self -> connection -> db );
}
CPython versions tested on:
CPython main branch
Operating systems tested on:
Linux
Linked PRs
Reactions are currently unavailable
Bug report
Bug description:
A segmentation fault occurs in the
_sqlitemodule when a connection is closed inside an aggregatestep()callback. Aftersqlite3_step()returns,_pysqlite_query_execute()callssqlite3_last_insert_rowid(self->connection->db)without verifying thatself->connection->dbis still valid.If the connection was closed during the callback,
self->connection->dbbecomesNULL, leading to a NULL pointer dereference insidesqlite3_last_insert_rowid().Affected Code
Modules/_sqlite/cursor.c:974Reproducer
Result
Suggested Fix
Add a NULL check before calling sqlite3_last_insert_rowid():
CPython versions tested on:
CPython main branch
Operating systems tested on:
Linux
Linked PRs