Skip to content

Commit 36234db

Browse files
committed
fix segmentation fault
1 parent 685f46e commit 36234db

File tree

3 files changed

+51
-15
lines changed

3 files changed

+51
-15
lines changed

cbitstruct/_cbitstruct.c

+26-14
Original file line numberDiff line numberDiff line change
@@ -633,9 +633,15 @@ static Py_ssize_t PyArg_ParseTupleAndKeywordsFirstN(
633633
va_list varargs;
634634
va_start(varargs, n);
635635

636+
Py_ssize_t return_value = -1;
636637
Py_ssize_t nkwargs = kwargs ? PyObject_Length(kwargs) : 0;
637638
Py_ssize_t n_actual_args = n - nkwargs;
638639

640+
if (PyTuple_GET_SIZE(args) < n_actual_args) {
641+
PyErr_SetString(PyExc_TypeError, "Not enough arguments");
642+
goto exit;
643+
}
644+
639645
PyObject* actual_args = PyTuple_GetSlice(args, 0, n_actual_args);
640646
if (!actual_args) {
641647
PyErr_NoMemory();
@@ -646,10 +652,11 @@ static Py_ssize_t PyArg_ParseTupleAndKeywordsFirstN(
646652
actual_args, kwargs, format, keywords, varargs)) {
647653
}
648654
Py_DECREF(actual_args);
655+
return_value = n_actual_args;
649656

650657
exit:
651658
va_end(varargs);
652-
return n_actual_args;
659+
return return_value;
653660
}
654661

655662
static bool PopFillPadding(PyObject* kwargs)
@@ -907,21 +914,22 @@ static PyObject* CompiledFormat_pack_into(
907914
PyObject* kwargs)
908915
{
909916
PyObject* return_value = NULL;
910-
911-
bool fill_padding = PopFillPadding(kwargs);
912-
913917
Py_buffer buffer = {NULL, NULL};
914918
Py_ssize_t offset = 0;
915919

920+
bool fill_padding = PopFillPadding(kwargs);
921+
Py_ssize_t n_args = PyTuple_GET_SIZE(args);
922+
PyObject** data = PySequence_Fast_ITEMS(args);
923+
916924
static char* _keywords[] = {"buf", "offset", NULL};
917925
// custom (and vague) error message as all other 'pack_into'
918926
// versions are processed by this function. Using the default
919927
// error message would give bad information to the user
920928
Py_ssize_t n_args_parsed = PyArg_ParseTupleAndKeywordsFirstN(
921929
args, kwargs, "y*n:pack_into", _keywords, 2, &buffer, &offset);
922-
923-
Py_ssize_t n_args = PyTuple_GET_SIZE(args);
924-
PyObject** data = PySequence_Fast_ITEMS(args);
930+
if (n_args_parsed < 0) {
931+
goto exit;
932+
}
925933

926934
return_value = CompiledFormat_pack_into_raw(
927935
self->compiled_fmt,
@@ -931,6 +939,7 @@ static PyObject* CompiledFormat_pack_into(
931939
n_args - n_args_parsed,
932940
fill_padding);
933941

942+
exit:
934943
if (buffer.obj) {
935944
PyBuffer_Release(&buffer);
936945
}
@@ -1325,13 +1334,15 @@ static PyObject* pack(PyObject* module, PyObject* args, PyObject* kwargs)
13251334
{
13261335
PyObject* return_value = NULL;
13271336
const char* fmt = NULL;
1337+
PyCompiledFormatObject self;
1338+
memset(&self, 0, sizeof(self));
13281339

13291340
static char* _keywords[] = {"fmt", NULL};
13301341
Py_ssize_t n_args_parsed = PyArg_ParseTupleAndKeywordsFirstN(
13311342
args, kwargs, "s:pack", _keywords, 1, &fmt);
1332-
1333-
PyCompiledFormatObject self;
1334-
memset(&self, 0, sizeof(self));
1343+
if (n_args_parsed < 0) {
1344+
goto exit;
1345+
}
13351346

13361347
if (CompiledFormat___init___impl(&self, fmt)) {
13371348
// CompiledFormat___init___impl has set the exception
@@ -1363,15 +1374,16 @@ static PyObject* pack_into(PyObject* module, PyObject* args, PyObject* kwargs)
13631374
Py_buffer buffer = {NULL, NULL};
13641375
Py_ssize_t offset = 0;
13651376
const char* fmt = NULL;
1366-
1377+
PyCompiledFormatObject self;
1378+
memset(&self, 0, sizeof(self));
13671379
bool fill_padding = PopFillPadding(kwargs);
13681380

13691381
static char* _keywords[] = {"fmt", "buf", "offset", NULL};
13701382
Py_ssize_t n_args_parsed = PyArg_ParseTupleAndKeywordsFirstN(
13711383
args, kwargs, "sy*n:pack_into", _keywords, 3, &fmt, &buffer, &offset);
1372-
1373-
PyCompiledFormatObject self;
1374-
memset(&self, 0, sizeof(self));
1384+
if (n_args_parsed < 0) {
1385+
goto exit;
1386+
}
13751387

13761388
if (CompiledFormat___init___impl(&self, fmt)) {
13771389
// CompiledFormat___init___impl has set the exception

cbitstruct/tests/test_api.py

+24
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,30 @@
1515

1616

1717
class BitstructApiTest(unittest.TestCase):
18+
def test_no_args(self):
19+
self.assertRaises(Exception, cbitstruct.byteswap)
20+
self.assertRaises(Exception, cbitstruct.calcsize)
21+
self.assertRaises(Exception, cbitstruct.pack)
22+
self.assertRaises(Exception, cbitstruct.pack_into)
23+
self.assertRaises(Exception, cbitstruct.pack_dict)
24+
self.assertRaises(Exception, cbitstruct.pack_into_dict)
25+
self.assertRaises(Exception, cbitstruct.unpack)
26+
self.assertRaises(Exception, cbitstruct.unpack_from)
27+
self.assertRaises(Exception, cbitstruct.unpack_dict)
28+
self.assertRaises(Exception, cbitstruct.unpack_from_dict)
29+
self.assertRaises(Exception, cbitstruct.CompiledFormat)
30+
self.assertRaises(Exception, cbitstruct.CompiledFormatDict)
31+
cf = cbitstruct.CompiledFormat(FMT)
32+
self.assertRaises(Exception, cf.pack)
33+
self.assertRaises(Exception, cf.pack_into)
34+
self.assertRaises(Exception, cf.unpack)
35+
self.assertRaises(Exception, cf.unpack_from)
36+
cfd = cbitstruct.CompiledFormatDict(FMT, NAMES)
37+
self.assertRaises(Exception, cf.pack)
38+
self.assertRaises(Exception, cf.pack_into)
39+
self.assertRaises(Exception, cf.unpack)
40+
self.assertRaises(Exception, cf.unpack_from)
41+
1842
def test_compiled_format(self):
1943
cbitstruct.CompiledFormat(fmt=FMT)
2044
cbitstruct.CompiledFormat(FMT)

setup.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525

2626
setup(
2727
name="cbitstruct",
28-
version="1.0.0",
28+
version="1.0.1",
2929
author="Quentin CHATEAU",
3030
author_email="[email protected]",
3131
license="GPLv3",

0 commit comments

Comments
 (0)