Skip to content

Commit c06a829

Browse files
committed
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.
1 parent db8ecc2 commit c06a829

2 files changed

Lines changed: 11 additions & 0 deletions

File tree

asyncpg/protocol/record/recordobj.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -692,6 +692,7 @@ record_get(PyObject *self, PyTypeObject *defcls, PyObject *const *args,
692692
PyErr_Format(PyExc_TypeError,
693693
"Record.get() expected 1 or 2 arguments, got %zd",
694694
nargs);
695+
return NULL;
695696
}
696697

697698
if (kwnames != NULL && PyTuple_GET_SIZE(kwnames) != 0) {

tests/test_record.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,16 @@ def test_record_get(self):
288288
self.assertEqual(r.get('nonexistent'), None)
289289
self.assertEqual(r.get('nonexistent', 'default'), 'default')
290290

291+
def test_record_get_invalid_args(self):
292+
r = Record(R_AB, (42, 43))
293+
with self.checkref(r):
294+
with self.assertRaises(TypeError):
295+
r.get()
296+
with self.assertRaises(TypeError):
297+
r.get('a', 2, 3)
298+
with self.assertRaises(TypeError):
299+
r.get(default=2)
300+
291301
def test_record_not_pickleable(self):
292302
r = Record(R_A, (42,))
293303
with self.assertRaises(Exception):

0 commit comments

Comments
 (0)