Skip to content

Commit 52e5deb

Browse files
Some asserts to demonstrate undefined behaviour
1 parent 56d9cf7 commit 52e5deb

File tree

5 files changed

+51
-8
lines changed

5 files changed

+51
-8
lines changed

Modules/_ctypes/cfield.c

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -419,11 +419,13 @@ get_ulonglong(PyObject *v, unsigned long long *p)
419419
*/
420420
#define GET_BITFIELD(v, size) \
421421
if (NUM_BITS(size)) { \
422+
assert(0 <= v); \
422423
v <<= (sizeof(v)*8 - LOW_BIT(size) - NUM_BITS(size)); \
423424
v >>= (sizeof(v)*8 - NUM_BITS(size)); \
424425
}
425426

426-
/* This macro RETURNS the first parameter with the bit field CHANGED. */
427+
/* This macro RETURNS the second parameter (x) with the bit field CHANGED. */
428+
// TODO: this one has UB, but I can't quite figure out the assert.
427429
#define SET(type, x, v, size) \
428430
(NUM_BITS(size) ? \
429431
( ( (type)x & ~(BIT_MASK(type, size) << LOW_BIT(size)) ) | ( ((type)v & BIT_MASK(type, size)) << LOW_BIT(size) ) ) \
@@ -769,6 +771,15 @@ l_set(void *ptr, PyObject *value, Py_ssize_t size)
769771
if (get_long(value, &val) < 0)
770772
return NULL;
771773
memcpy(&x, ptr, sizeof(x));
774+
assert(
775+
(NUM_BITS(size) - 1) < 63
776+
);
777+
assert(
778+
NUM_BITS(size) ? (0 <= BIT_MASK(long, size)) : true
779+
);
780+
781+
// TODO: figure out the proper assert here.
782+
// Modules/_ctypes/cfield.c:789:9: runtime error: left shift of 1 by 63 places cannot be represented in type 'long'
772783
x = SET(long, x, val, size);
773784
memcpy(ptr, &x, sizeof(x));
774785
_RET(value);

Modules/_struct.c

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -812,11 +812,16 @@ bu_int(_structmodulestate *state, const char *p, const formatdef *f)
812812
Py_ssize_t i = f->size;
813813
const unsigned char *bytes = (const unsigned char *)p;
814814
do {
815+
assert(0 <= x);
816+
assert(x <= (LLONG_MAX>>8));
815817
x = (x<<8) | *bytes++;
816818
} while (--i > 0);
817819
/* Extend the sign bit. */
818-
if (SIZEOF_LONG > f->size)
820+
if (SIZEOF_LONG > f->size) {
821+
assert(8 * f->size - 1 < 8 * SIZEOF_LONG_LONG - 1);
822+
assert(0 <= 8 * f->size - 1);
819823
x |= -(x & (1L << ((8 * f->size) - 1)));
824+
}
820825
return PyLong_FromLong(x);
821826
}
822827

@@ -839,11 +844,16 @@ bu_longlong(_structmodulestate *state, const char *p, const formatdef *f)
839844
Py_ssize_t i = f->size;
840845
const unsigned char *bytes = (const unsigned char *)p;
841846
do {
847+
assert(x >= 0);
848+
assert(x <= (LLONG_MAX>>8));
842849
x = (x<<8) | *bytes++;
843850
} while (--i > 0);
844851
/* Extend the sign bit. */
845-
if (SIZEOF_LONG_LONG > f->size)
852+
if (SIZEOF_LONG_LONG > f->size) {
853+
assert(8 * f->size - 1 < 8 * SIZEOF_LONG_LONG - 1);
854+
assert(0 <= 8 * f->size - 1);
846855
x |= -(x & ((long long)1 << ((8 * f->size) - 1)));
856+
}
847857
return PyLong_FromLongLong(x);
848858
}
849859

@@ -1033,11 +1043,16 @@ lu_int(_structmodulestate *state, const char *p, const formatdef *f)
10331043
Py_ssize_t i = f->size;
10341044
const unsigned char *bytes = (const unsigned char *)p;
10351045
do {
1046+
assert(0 <= x);
1047+
assert(x <= (LONG_MAX>>8));
10361048
x = (x<<8) | bytes[--i];
10371049
} while (i > 0);
10381050
/* Extend the sign bit. */
1039-
if (SIZEOF_LONG > f->size)
1051+
if (SIZEOF_LONG > f->size) {
1052+
assert(8 * f->size - 1 < 8 * SIZEOF_LONG - 1);
1053+
assert(0 <= 8 * f->size - 1);
10401054
x |= -(x & (1L << ((8 * f->size) - 1)));
1055+
}
10411056
return PyLong_FromLong(x);
10421057
}
10431058

@@ -1060,11 +1075,16 @@ lu_longlong(_structmodulestate *state, const char *p, const formatdef *f)
10601075
Py_ssize_t i = f->size;
10611076
const unsigned char *bytes = (const unsigned char *)p;
10621077
do {
1078+
assert(0 <= x);
1079+
assert(x <= (LLONG_MAX>>8));
10631080
x = (x<<8) | bytes[--i];
10641081
} while (i > 0);
10651082
/* Extend the sign bit. */
1066-
if (SIZEOF_LONG_LONG > f->size)
1083+
if (SIZEOF_LONG_LONG > f->size) {
1084+
assert(8 * f->size - 1 < 8 * SIZEOF_LONG_LONG - 1);
1085+
assert(0 <= 8 * f->size - 1);
10671086
x |= -(x & ((long long)1 << ((8 * f->size) - 1)));
1087+
}
10681088
return PyLong_FromLongLong(x);
10691089
}
10701090

Modules/_testcapimodule.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4918,6 +4918,7 @@ meth_fastcall_keywords(PyObject* self, PyObject* const* args,
49184918
if (pyargs == NULL) {
49194919
return NULL;
49204920
}
4921+
assert(args != NULL);
49214922
PyObject *pykwargs = PyObject_Vectorcall((PyObject*)&PyDict_Type,
49224923
args + nargs, 0, kwargs);
49234924
return Py_BuildValue("NNN", _null_to_none(self), pyargs, pykwargs);

Modules/audioop.c

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ st_14linear2ulaw(int16_t pcm_val) /* 2's complement (14-bit range) */
170170
if (seg >= 8) /* out of range, return maximum value. */
171171
return (unsigned char) (0x7F ^ mask);
172172
else {
173+
assert(0 <= seg);
173174
uval = (unsigned char) (seg << 4) | ((pcm_val >> (seg + 1)) & 0xF);
174175
return (uval ^ mask);
175176
}
@@ -346,11 +347,16 @@ static const int stepsizeTable[89] = {
346347
SETINT32((cp), (i), (val)); \
347348
} while(0)
348349

350+
static inline int lshift_safe(int x, Py_ssize_t b) {
351+
assert(0 <= x);
352+
assert(x <= (INT_MAX >> b));
353+
return x << b;
354+
}
349355

350356
#define GETSAMPLE32(size, cp, i) ( \
351-
(size == 1) ? (int)GETINT8((cp), (i)) << 24 : \
352-
(size == 2) ? (int)GETINT16((cp), (i)) << 16 : \
353-
(size == 3) ? (int)GETINT24((cp), (i)) << 8 : \
357+
(size == 1) ? lshift_safe((int)GETINT8((cp), (i)), 24) : \
358+
(size == 2) ? lshift_safe((int)GETINT16((cp), (i)), 16) : \
359+
(size == 3) ? lshift_safe((int)GETINT24((cp), (i)), 8) : \
354360
(int)GETINT32((cp), (i)))
355361

356362
#define SETSAMPLE32(size, cp, i, val) do { \
@@ -1558,6 +1564,7 @@ audioop_ulaw2lin_impl(PyObject *module, Py_buffer *fragment, int width)
15581564

15591565
cp = fragment->buf;
15601566
for (i = 0; i < fragment->len*width; i += width) {
1567+
assert(0 <= st_ulaw2linear16(*cp));
15611568
int val = st_ulaw2linear16(*cp++) << 16;
15621569
SETSAMPLE32(width, ncp, i, val);
15631570
}
@@ -1632,6 +1639,7 @@ audioop_alaw2lin_impl(PyObject *module, Py_buffer *fragment, int width)
16321639
cp = fragment->buf;
16331640

16341641
for (i = 0; i < fragment->len*width; i += width) {
1642+
assert(0 <= st_alaw2linear16(*cp));
16351643
val = st_alaw2linear16(*cp++) << 16;
16361644
SETSAMPLE32(width, ncp, i, val);
16371645
}
@@ -1757,6 +1765,7 @@ audioop_lin2adpcm_impl(PyObject *module, Py_buffer *fragment, int width,
17571765

17581766
/* Step 6 - Output value */
17591767
if ( bufferstep ) {
1768+
assert (0 <= delta);
17601769
outputbuffer = (delta << 4) & 0xf0;
17611770
} else {
17621771
*ncp++ = (delta & 0x0f) | outputbuffer;
@@ -1875,6 +1884,7 @@ audioop_adpcm2lin_impl(PyObject *module, Py_buffer *fragment, int width,
18751884
step = stepsizeTable[index];
18761885

18771886
/* Step 6 - Output value */
1887+
assert(0 <= valpred);
18781888
SETSAMPLE32(width, ncp, i, valpred << 16);
18791889
}
18801890

Python/ceval.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5532,6 +5532,7 @@ initialize_locals(PyThreadState *tstate, PyFunctionObject *func,
55325532
/* Pack other positional arguments into the *args argument */
55335533
if (co->co_flags & CO_VARARGS) {
55345534
PyObject *u = NULL;
5535+
assert(args != NULL);
55355536
u = _PyTuple_FromArraySteal(args + n, argcount - n);
55365537
if (u == NULL) {
55375538
goto fail_post_positional;

0 commit comments

Comments
 (0)