From c06a829d5ff3b4e78a2c7012bbd05262a57c8ccb Mon Sep 17 00:00:00 2001 From: Apoorv Darshan Date: Thu, 9 Jul 2026 19:15:03 +0530 Subject: [PATCH] Fix segfault in Record.get() with invalid positional arg count record_get() set a TypeError with PyErr_Format() when given the wrong number of positional arguments but did not return, falling through to record_item_by_name() with an uninitialized `key` pointer. Depending on the stack contents this either crashed the interpreter (SEGV) or silently returned the default instead of raising TypeError. The release build also emitted a `'key' may be used uninitialized` warning. Return NULL immediately after setting the error, and add regression coverage for the invalid argument-count cases. Fixes #1328. --- asyncpg/protocol/record/recordobj.c | 1 + tests/test_record.py | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/asyncpg/protocol/record/recordobj.c b/asyncpg/protocol/record/recordobj.c index 58c66662..03654af1 100644 --- a/asyncpg/protocol/record/recordobj.c +++ b/asyncpg/protocol/record/recordobj.c @@ -692,6 +692,7 @@ record_get(PyObject *self, PyTypeObject *defcls, PyObject *const *args, PyErr_Format(PyExc_TypeError, "Record.get() expected 1 or 2 arguments, got %zd", nargs); + return NULL; } if (kwnames != NULL && PyTuple_GET_SIZE(kwnames) != 0) { diff --git a/tests/test_record.py b/tests/test_record.py index d463c41f..725cd15a 100644 --- a/tests/test_record.py +++ b/tests/test_record.py @@ -288,6 +288,16 @@ def test_record_get(self): self.assertEqual(r.get('nonexistent'), None) self.assertEqual(r.get('nonexistent', 'default'), 'default') + def test_record_get_invalid_args(self): + r = Record(R_AB, (42, 43)) + with self.checkref(r): + with self.assertRaises(TypeError): + r.get() + with self.assertRaises(TypeError): + r.get('a', 2, 3) + with self.assertRaises(TypeError): + r.get(default=2) + def test_record_not_pickleable(self): r = Record(R_A, (42,)) with self.assertRaises(Exception):