Skip to content

Commit 001ef46

Browse files
author
Erlend Egeberg Aasland
authored
bpo-44991: Make GIL handling more explicit in sqlite3 callbacks (GH-27934)
- acquire the GIL at the very start[1] - release the GIL at the very end [1] The trace callback performs a sanity check before acquiring the GIL Automerge-Triggered-By: GH:encukou
1 parent edae42f commit 001ef46

File tree

1 file changed

+27
-35
lines changed

1 file changed

+27
-35
lines changed

Modules/_sqlite/connection.c

+27-35
Original file line numberDiff line numberDiff line change
@@ -626,14 +626,12 @@ set_sqlite_error(sqlite3_context *context, const char *msg)
626626
static void
627627
_pysqlite_func_callback(sqlite3_context *context, int argc, sqlite3_value **argv)
628628
{
629+
PyGILState_STATE threadstate = PyGILState_Ensure();
630+
629631
PyObject* args;
630632
PyObject* py_retval = NULL;
631633
int ok;
632634

633-
PyGILState_STATE threadstate;
634-
635-
threadstate = PyGILState_Ensure();
636-
637635
args = _pysqlite_build_py_params(context, argc, argv);
638636
if (args) {
639637
callback_context *ctx = (callback_context *)sqlite3_user_data(context);
@@ -656,15 +654,13 @@ _pysqlite_func_callback(sqlite3_context *context, int argc, sqlite3_value **argv
656654

657655
static void _pysqlite_step_callback(sqlite3_context *context, int argc, sqlite3_value** params)
658656
{
657+
PyGILState_STATE threadstate = PyGILState_Ensure();
658+
659659
PyObject* args;
660660
PyObject* function_result = NULL;
661661
PyObject** aggregate_instance;
662662
PyObject* stepmethod = NULL;
663663

664-
PyGILState_STATE threadstate;
665-
666-
threadstate = PyGILState_Ensure();
667-
668664
aggregate_instance = (PyObject**)sqlite3_aggregate_context(context, sizeof(PyObject*));
669665

670666
if (*aggregate_instance == NULL) {
@@ -706,16 +702,14 @@ static void _pysqlite_step_callback(sqlite3_context *context, int argc, sqlite3_
706702
static void
707703
_pysqlite_final_callback(sqlite3_context *context)
708704
{
705+
PyGILState_STATE threadstate = PyGILState_Ensure();
706+
709707
PyObject* function_result;
710708
PyObject** aggregate_instance;
711709
_Py_IDENTIFIER(finalize);
712710
int ok;
713711
PyObject *exception, *value, *tb;
714712

715-
PyGILState_STATE threadstate;
716-
717-
threadstate = PyGILState_Ensure();
718-
719713
aggregate_instance = (PyObject**)sqlite3_aggregate_context(context, 0);
720714
if (aggregate_instance == NULL) {
721715
/* No rows matched the query; the step handler was never called. */
@@ -787,34 +781,34 @@ static void _pysqlite_drop_unused_cursor_references(pysqlite_Connection* self)
787781
static callback_context *
788782
create_callback_context(pysqlite_state *state, PyObject *callable)
789783
{
790-
PyGILState_STATE gstate = PyGILState_Ensure();
791784
callback_context *ctx = PyMem_Malloc(sizeof(callback_context));
792785
if (ctx != NULL) {
793786
ctx->callable = Py_NewRef(callable);
794787
ctx->state = state;
795788
}
796-
PyGILState_Release(gstate);
797789
return ctx;
798790
}
799791

800792
static void
801793
free_callback_context(callback_context *ctx)
794+
{
795+
assert(ctx != NULL);
796+
Py_DECREF(ctx->callable);
797+
PyMem_Free(ctx);
798+
}
799+
800+
static void
801+
_destructor(void *ctx)
802802
{
803803
if (ctx != NULL) {
804804
// This function may be called without the GIL held, so we need to
805805
// ensure that we destroy 'ctx' with the GIL held.
806806
PyGILState_STATE gstate = PyGILState_Ensure();
807-
Py_DECREF(ctx->callable);
808-
PyMem_Free(ctx);
807+
free_callback_context((callback_context *)ctx);
809808
PyGILState_Release(gstate);
810809
}
811810
}
812811

813-
static void _destructor(void* args)
814-
{
815-
free_callback_context((callback_context *)args);
816-
}
817-
818812
/*[clinic input]
819813
_sqlite3.Connection.create_function as pysqlite_connection_create_function
820814
@@ -914,11 +908,10 @@ pysqlite_connection_create_aggregate_impl(pysqlite_Connection *self,
914908

915909
static int _authorizer_callback(void* user_arg, int action, const char* arg1, const char* arg2 , const char* dbname, const char* access_attempt_source)
916910
{
911+
PyGILState_STATE gilstate = PyGILState_Ensure();
912+
917913
PyObject *ret;
918914
int rc;
919-
PyGILState_STATE gilstate;
920-
921-
gilstate = PyGILState_Ensure();
922915

923916
ret = PyObject_CallFunction((PyObject*)user_arg, "issss", action, arg1, arg2, dbname, access_attempt_source);
924917

@@ -959,11 +952,10 @@ static int _authorizer_callback(void* user_arg, int action, const char* arg1, co
959952

960953
static int _progress_handler(void* user_arg)
961954
{
955+
PyGILState_STATE gilstate = PyGILState_Ensure();
956+
962957
int rc;
963958
PyObject *ret;
964-
PyGILState_STATE gilstate;
965-
966-
gilstate = PyGILState_Ensure();
967959
ret = _PyObject_CallNoArg((PyObject*)user_arg);
968960

969961
if (!ret) {
@@ -1000,18 +992,16 @@ static int _trace_callback(unsigned int type, void* user_arg, void* prepared_sta
1000992
static void _trace_callback(void* user_arg, const char* statement_string)
1001993
#endif
1002994
{
1003-
PyObject *py_statement = NULL;
1004-
PyObject *ret = NULL;
1005-
1006-
PyGILState_STATE gilstate;
1007-
1008995
#ifdef HAVE_TRACE_V2
1009996
if (type != SQLITE_TRACE_STMT) {
1010997
return 0;
1011998
}
1012999
#endif
10131000

1014-
gilstate = PyGILState_Ensure();
1001+
PyGILState_STATE gilstate = PyGILState_Ensure();
1002+
1003+
PyObject *py_statement = NULL;
1004+
PyObject *ret = NULL;
10151005
py_statement = PyUnicode_DecodeUTF8(statement_string,
10161006
strlen(statement_string), "replace");
10171007
if (py_statement) {
@@ -1461,14 +1451,16 @@ pysqlite_collation_callback(
14611451
int text1_length, const void* text1_data,
14621452
int text2_length, const void* text2_data)
14631453
{
1454+
PyGILState_STATE gilstate = PyGILState_Ensure();
1455+
14641456
PyObject* string1 = 0;
14651457
PyObject* string2 = 0;
1466-
PyGILState_STATE gilstate;
14671458
PyObject* retval = NULL;
14681459
long longval;
14691460
int result = 0;
1470-
gilstate = PyGILState_Ensure();
14711461

1462+
/* This callback may be executed multiple times per sqlite3_step(). Bail if
1463+
* the previous call failed */
14721464
if (PyErr_Occurred()) {
14731465
goto finally;
14741466
}

0 commit comments

Comments
 (0)