Bug report
I don't think it is very important, since this is just a test, but why have it when it is spotted?
test_k_code:
|
/* This function not only tests the 'k' getargs code, but also the |
|
PyLong_AsUnsignedLongMask() function. */ |
|
static PyObject * |
|
test_k_code(PyObject *self, PyObject *Py_UNUSED(ignored)) |
|
{ |
|
PyObject *tuple, *num; |
|
unsigned long value; |
|
|
|
tuple = PyTuple_New(1); |
|
if (tuple == NULL) { |
|
return NULL; |
|
} |
|
|
|
/* a number larger than ULONG_MAX even on 64-bit platforms */ |
|
num = PyLong_FromString("FFFFFFFFFFFFFFFFFFFFFFFF", NULL, 16); |
|
if (num == NULL) { |
|
return NULL; |
|
} |
|
|
|
value = PyLong_AsUnsignedLongMask(num); |
|
if (value != ULONG_MAX) { |
|
PyErr_SetString(PyExc_AssertionError, |
|
"test_k_code: " |
|
"PyLong_AsUnsignedLongMask() returned wrong value for long 0xFFF...FFF"); |
|
return NULL; |
|
} |
|
|
|
PyTuple_SET_ITEM(tuple, 0, num); |
|
|
|
value = 0; |
|
if (!PyArg_ParseTuple(tuple, "k:test_k_code", &value)) { |
|
return NULL; |
|
} |
|
if (value != ULONG_MAX) { |
|
PyErr_SetString(PyExc_AssertionError, |
|
"test_k_code: k code returned wrong value for long 0xFFF...FFF"); |
|
return NULL; |
|
} |
|
|
|
Py_DECREF(num); |
|
num = PyLong_FromString("-FFFFFFFF000000000000000042", NULL, 16); |
|
if (num == NULL) { |
|
return NULL; |
|
} |
|
|
|
value = PyLong_AsUnsignedLongMask(num); |
|
if (value != (unsigned long)-0x42) { |
|
PyErr_SetString(PyExc_AssertionError, |
|
"test_k_code: " |
|
"PyLong_AsUnsignedLongMask() returned wrong value for long -0xFFF..000042"); |
|
return NULL; |
|
} |
|
|
|
PyTuple_SET_ITEM(tuple, 0, num); |
|
|
|
value = 0; |
|
if (!PyArg_ParseTuple(tuple, "k:test_k_code", &value)) { |
|
return NULL; |
|
} |
|
if (value != (unsigned long)-0x42) { |
|
PyErr_SetString(PyExc_AssertionError, |
|
"test_k_code: k code returned wrong value for long -0xFFF..000042"); |
|
return NULL; |
|
} |
|
|
|
Py_DECREF(tuple); |
|
Py_RETURN_NONE; |
|
} |
On errors tuple is not decrefed.
Also, note these lines:
|
PyTuple_SET_ITEM(tuple, 0, num); |
|
|
|
value = 0; |
|
if (!PyArg_ParseTuple(tuple, "k:test_k_code", &value)) { |
|
return NULL; |
|
} |
|
if (value != ULONG_MAX) { |
|
PyErr_SetString(PyExc_AssertionError, |
|
"test_k_code: k code returned wrong value for long 0xFFF...FFF"); |
|
return NULL; |
|
} |
|
|
|
Py_DECREF(num); |
|
num = PyLong_FromString("-FFFFFFFF000000000000000042", NULL, 16); |
|
if (num == NULL) { |
|
return NULL; |
|
} |
Here' we leave a tuple is a semi-broken state. Its 0'th item has a reference count of 0.
We should also recreate a tuple here with the new items. test_L_code also has this problem.
|
static PyObject * |
|
test_L_code(PyObject *self, PyObject *Py_UNUSED(ignored)) |
|
{ |
|
PyObject *tuple, *num; |
|
long long value; |
|
|
|
tuple = PyTuple_New(1); |
|
if (tuple == NULL) { |
|
return NULL; |
|
} |
|
|
|
num = PyLong_FromLong(42); |
|
if (num == NULL) { |
|
return NULL; |
|
} |
|
|
|
PyTuple_SET_ITEM(tuple, 0, num); |
|
|
|
value = -1; |
|
if (!PyArg_ParseTuple(tuple, "L:test_L_code", &value)) { |
|
return NULL; |
|
} |
|
if (value != 42) { |
|
PyErr_SetString(PyExc_AssertionError, |
|
"test_L_code: L code returned wrong value for long 42"); |
|
return NULL; |
|
} |
|
|
|
Py_DECREF(num); |
|
num = PyLong_FromLong(42); |
|
if (num == NULL) { |
|
return NULL; |
|
} |
|
|
|
PyTuple_SET_ITEM(tuple, 0, num); |
|
|
|
value = -1; |
|
if (!PyArg_ParseTuple(tuple, "L:test_L_code", &value)) { |
|
return NULL; |
|
} |
|
if (value != 42) { |
|
PyErr_SetString(PyExc_AssertionError, |
|
"test_L_code: L code returned wrong value for int 42"); |
|
return NULL; |
|
} |
|
|
|
Py_DECREF(tuple); |
|
Py_RETURN_NONE; |
|
} |
On errors tuple is not decrefed. And num is re-assigned without tuple cleanup.
|
/* Test the s and z codes for PyArg_ParseTuple. |
|
*/ |
|
static PyObject * |
|
test_s_code(PyObject *self, PyObject *Py_UNUSED(ignored)) |
|
{ |
|
/* Unicode strings should be accepted */ |
|
PyObject *tuple = PyTuple_New(1); |
|
if (tuple == NULL) { |
|
return NULL; |
|
} |
|
|
|
PyObject *obj = PyUnicode_Decode("t\xeate", strlen("t\xeate"), |
|
"latin-1", NULL); |
|
if (obj == NULL) { |
|
return NULL; |
|
} |
|
|
|
PyTuple_SET_ITEM(tuple, 0, obj); |
|
|
|
/* These two blocks used to raise a TypeError: |
|
* "argument must be string without null bytes, not str" |
|
*/ |
|
char *value; |
|
if (!PyArg_ParseTuple(tuple, "s:test_s_code1", &value)) { |
|
return NULL; |
|
} |
|
|
|
if (!PyArg_ParseTuple(tuple, "z:test_s_code2", &value)) { |
|
return NULL; |
|
} |
|
|
|
Py_DECREF(tuple); |
|
Py_RETURN_NONE; |
|
} |
As well, tuple is leaked on errors.
I have a PR ready.
Linked PRs
Bug report
I don't think it is very important, since this is just a test, but why have it when it is spotted?
test_k_code:cpython/Modules/_testcapi/getargs.c
Lines 331 to 398 in 326c6c4
On errors
tupleis not decrefed.Also, note these lines:
cpython/Modules/_testcapi/getargs.c
Lines 358 to 374 in 326c6c4
Here' we leave a
tupleis a semi-broken state. Its 0'th item has a reference count of 0.We should also recreate a
tuplehere with the new items.test_L_codealso has this problem.cpython/Modules/_testcapi/getargs.c
Lines 684 to 732 in 326c6c4
On errors
tupleis not decrefed. Andnumis re-assigned withouttuplecleanup.cpython/Modules/_testcapi/getargs.c
Lines 734 to 767 in 326c6c4
As well,
tupleis leaked on errors.I have a PR ready.
Linked PRs
test_*_codein_testcapi/getargs.c#110573test_*from_testcapi/getargs.c#111214