Skip to content

gh-91731: Replace Py_BUILD_ASSERT() with static_assert() #91730

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions Modules/_datetimemodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -6637,19 +6637,19 @@ _datetime_exec(PyObject *module)
/* A 4-year cycle has an extra leap day over what we'd get from
* pasting together 4 single years.
*/
Py_BUILD_ASSERT(DI4Y == 4 * 365 + 1);
static_assert(DI4Y == 4 * 365 + 1, "DI4Y");
assert(DI4Y == days_before_year(4+1));

/* Similarly, a 400-year cycle has an extra leap day over what we'd
* get from pasting together 4 100-year cycles.
*/
Py_BUILD_ASSERT(DI400Y == 4 * DI100Y + 1);
static_assert(DI400Y == 4 * DI100Y + 1, "DI400Y");
assert(DI400Y == days_before_year(400+1));

/* OTOH, a 100-year cycle has one fewer leap day than we'd get from
* pasting together 25 4-year cycles.
*/
Py_BUILD_ASSERT(DI100Y == 25 * DI4Y - 1);
static_assert(DI100Y == 25 * DI4Y - 1, "DI100Y");
assert(DI100Y == days_before_year(100+1));

us_per_ms = PyLong_FromLong(1000);
Expand Down
2 changes: 1 addition & 1 deletion Modules/_pickle.c
Original file line number Diff line number Diff line change
Expand Up @@ -964,7 +964,7 @@ _write_size64(char *out, size_t value)
{
size_t i;

Py_BUILD_ASSERT(sizeof(size_t) <= 8);
static_assert(sizeof(size_t) <= 8, "size_t is larger than 64-bit");

for (i = 0; i < sizeof(size_t); i++) {
out[i] = (unsigned char)((value >> (8 * i)) & 0xff);
Expand Down
3 changes: 2 additions & 1 deletion Modules/_testcapimodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -5157,7 +5157,8 @@ dict_get_version(PyObject *self, PyObject *args)

version = dict->ma_version_tag;

Py_BUILD_ASSERT(sizeof(unsigned long long) >= sizeof(version));
static_assert(sizeof(unsigned long long) >= sizeof(version),
"version is larger than unsigned long long");
return PyLong_FromUnsignedLongLong((unsigned long long)version);
}

Expand Down
12 changes: 8 additions & 4 deletions Modules/posixmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -2381,7 +2381,8 @@ _pystat_fromstructstat(PyObject *module, STRUCT_STAT *st)
return NULL;

PyStructSequence_SET_ITEM(v, 0, PyLong_FromLong((long)st->st_mode));
Py_BUILD_ASSERT(sizeof(unsigned long long) >= sizeof(st->st_ino));
static_assert(sizeof(unsigned long long) >= sizeof(st->st_ino),
"stat.st_ino is larger than unsigned long long");
PyStructSequence_SET_ITEM(v, 1, PyLong_FromUnsignedLongLong(st->st_ino));
#ifdef MS_WINDOWS
PyStructSequence_SET_ITEM(v, 2, PyLong_FromUnsignedLong(st->st_dev));
Expand All @@ -2396,7 +2397,8 @@ _pystat_fromstructstat(PyObject *module, STRUCT_STAT *st)
PyStructSequence_SET_ITEM(v, 4, _PyLong_FromUid(st->st_uid));
PyStructSequence_SET_ITEM(v, 5, _PyLong_FromGid(st->st_gid));
#endif
Py_BUILD_ASSERT(sizeof(long long) >= sizeof(st->st_size));
static_assert(sizeof(long long) >= sizeof(st->st_size),
"stat.st_size is larger than long long");
PyStructSequence_SET_ITEM(v, 6, PyLong_FromLongLong(st->st_size));

#if defined(HAVE_STAT_TV_NSEC)
Expand Down Expand Up @@ -13761,10 +13763,12 @@ _Py_COMP_DIAG_POP
self->win32_file_index = stat.st_ino;
self->got_file_index = 1;
}
Py_BUILD_ASSERT(sizeof(unsigned long long) >= sizeof(self->win32_file_index));
static_assert(sizeof(unsigned long long) >= sizeof(self->win32_file_index),
"DirEntry.win32_file_index is larger than unsigned long long");
return PyLong_FromUnsignedLongLong(self->win32_file_index);
#else /* POSIX */
Py_BUILD_ASSERT(sizeof(unsigned long long) >= sizeof(self->d_ino));
static_assert(sizeof(unsigned long long) >= sizeof(self->d_ino),
"DirEntry.d_ino is larger than unsigned long long");
return PyLong_FromUnsignedLongLong(self->d_ino);
#endif
}
Expand Down
4 changes: 3 additions & 1 deletion Modules/pyexpat.c
Original file line number Diff line number Diff line change
Expand Up @@ -745,14 +745,16 @@ pyexpat_xmlparser_Parse_impl(xmlparseobject *self, PyTypeObject *cls,
slen = view.len;
}

static_assert(MAX_CHUNK_SIZE <= INT_MAX,
"MAX_CHUNK_SIZE is larger than INT_MAX");
while (slen > MAX_CHUNK_SIZE) {
rc = XML_Parse(self->itself, s, MAX_CHUNK_SIZE, 0);
if (!rc)
goto done;
s += MAX_CHUNK_SIZE;
slen -= MAX_CHUNK_SIZE;
}
Py_BUILD_ASSERT(MAX_CHUNK_SIZE <= INT_MAX);

assert(slen <= INT_MAX);
rc = XML_Parse(self->itself, s, (int)slen, isfinal);

Expand Down
7 changes: 5 additions & 2 deletions Objects/longobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -771,7 +771,10 @@ _PyLong_Sign(PyObject *vv)
static int
bit_length_digit(digit x)
{
Py_BUILD_ASSERT(PyLong_SHIFT <= sizeof(unsigned long) * 8);
// digit can be larger than unsigned long, but only PyLong_SHIFT bits
// of it will be ever used.
static_assert(PyLong_SHIFT <= sizeof(unsigned long) * 8,
"digit is larger than unsigned long");
return _Py_bit_length((unsigned long)x);
}

Expand Down Expand Up @@ -5647,7 +5650,7 @@ popcount_digit(digit d)
{
// digit can be larger than uint32_t, but only PyLong_SHIFT bits
// of it will be ever used.
Py_BUILD_ASSERT(PyLong_SHIFT <= 32);
static_assert(PyLong_SHIFT <= 32, "digit is larger than uint32_t");
return _Py_popcount32((uint32_t)d);
}

Expand Down
3 changes: 2 additions & 1 deletion Objects/sliceobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,8 @@ PySlice_Unpack(PyObject *_r,
PySliceObject *r = (PySliceObject*)_r;
/* this is harder to get right than you might think */

Py_BUILD_ASSERT(PY_SSIZE_T_MIN + 1 <= -PY_SSIZE_T_MAX);
static_assert(PY_SSIZE_T_MIN + 1 <= -PY_SSIZE_T_MAX,
"-PY_SSIZE_T_MAX < PY_SSIZE_T_MIN + 1");

if (r->step == Py_None) {
*step = 1;
Expand Down
2 changes: 1 addition & 1 deletion Python/fileutils.c
Original file line number Diff line number Diff line change
Expand Up @@ -956,7 +956,7 @@ static wchar_t *
_Py_ConvertWCharForm(const wchar_t *source, Py_ssize_t size,
const char *tocode, const char *fromcode)
{
Py_BUILD_ASSERT(sizeof(wchar_t) == 4);
static_assert(sizeof(wchar_t) == 4, "wchar_t must be 32-bit");

/* Ensure we won't overflow the size. */
if (size > (PY_SSIZE_T_MAX / (Py_ssize_t)sizeof(wchar_t))) {
Expand Down
4 changes: 3 additions & 1 deletion Python/initconfig.c
Original file line number Diff line number Diff line change
Expand Up @@ -1507,9 +1507,11 @@ config_get_xoption_value(const PyConfig *config, wchar_t *name)
static PyStatus
config_init_hash_seed(PyConfig *config)
{
static_assert(sizeof(_Py_HashSecret_t) == sizeof(_Py_HashSecret.uc),
"_Py_HashSecret_t has wrong size");

const char *seed_text = config_get_env(config, "PYTHONHASHSEED");

Py_BUILD_ASSERT(sizeof(_Py_HashSecret_t) == sizeof(_Py_HashSecret.uc));
/* Convert a text seed to a numeric one */
if (seed_text && strcmp(seed_text, "random") != 0) {
const char *endptr = seed_text;
Expand Down
63 changes: 40 additions & 23 deletions Python/pytime.c
Original file line number Diff line number Diff line change
Expand Up @@ -162,12 +162,11 @@ time_t
_PyLong_AsTime_t(PyObject *obj)
{
#if SIZEOF_TIME_T == SIZEOF_LONG_LONG
long long val;
val = PyLong_AsLongLong(obj);
long long val = PyLong_AsLongLong(obj);
#elif SIZEOF_TIME_T <= SIZEOF_LONG
long val = PyLong_AsLong(obj);
#else
long val;
Py_BUILD_ASSERT(sizeof(time_t) <= sizeof(long));
val = PyLong_AsLong(obj);
# error "unsupported time_t size"
#endif
if (val == -1 && PyErr_Occurred()) {
if (PyErr_ExceptionMatches(PyExc_OverflowError)) {
Expand All @@ -184,9 +183,10 @@ _PyLong_FromTime_t(time_t t)
{
#if SIZEOF_TIME_T == SIZEOF_LONG_LONG
return PyLong_FromLongLong((long long)t);
#else
Py_BUILD_ASSERT(sizeof(time_t) <= sizeof(long));
#elif SIZEOF_TIME_T <= SIZEOF_LONG
return PyLong_FromLong((long)t);
#else
# error "unsupported time_t size"
#endif
}

Expand Down Expand Up @@ -386,10 +386,10 @@ _PyTime_t
_PyTime_FromSeconds(int seconds)
{
/* ensure that integer overflow cannot happen, int type should have 32
bits, whereas _PyTime_t type has at least 64 bits (SEC_TO_MS takes 30
bits, whereas _PyTime_t type has at least 64 bits (SEC_TO_NS takes 30
bits). */
Py_BUILD_ASSERT(INT_MAX <= _PyTime_MAX / SEC_TO_NS);
Py_BUILD_ASSERT(INT_MIN >= _PyTime_MIN / SEC_TO_NS);
static_assert(INT_MAX <= _PyTime_MAX / SEC_TO_NS, "_PyTime_t overflow");
static_assert(INT_MIN >= _PyTime_MIN / SEC_TO_NS, "_PyTime_t underflow");

_PyTime_t t = (_PyTime_t)seconds;
assert((t >= 0 && t <= _PyTime_MAX / SEC_TO_NS)
Expand All @@ -416,7 +416,8 @@ _PyTime_FromNanosecondsObject(_PyTime_t *tp, PyObject *obj)
return -1;
}

Py_BUILD_ASSERT(sizeof(long long) == sizeof(_PyTime_t));
static_assert(sizeof(long long) == sizeof(_PyTime_t),
"_PyTime_t is not long long");
long long nsec = PyLong_AsLongLong(obj);
if (nsec == -1 && PyErr_Occurred()) {
if (PyErr_ExceptionMatches(PyExc_OverflowError)) {
Expand All @@ -437,7 +438,8 @@ pytime_fromtimespec(_PyTime_t *tp, struct timespec *ts, int raise_exc)
{
_PyTime_t t, tv_nsec;

Py_BUILD_ASSERT(sizeof(ts->tv_sec) <= sizeof(_PyTime_t));
static_assert(sizeof(ts->tv_sec) <= sizeof(_PyTime_t),
"timespec.tv_sec is larger than _PyTime_t");
t = (_PyTime_t)ts->tv_sec;

int res1 = pytime_mul(&t, SEC_TO_NS);
Expand Down Expand Up @@ -466,7 +468,8 @@ _PyTime_FromTimespec(_PyTime_t *tp, struct timespec *ts)
static int
pytime_fromtimeval(_PyTime_t *tp, struct timeval *tv, int raise_exc)
{
Py_BUILD_ASSERT(sizeof(tv->tv_sec) <= sizeof(_PyTime_t));
static_assert(sizeof(tv->tv_sec) <= sizeof(_PyTime_t),
"timeval.tv_sec is larger than _PyTime_t");
_PyTime_t t = (_PyTime_t)tv->tv_sec;

int res1 = pytime_mul(&t, SEC_TO_NS);
Expand Down Expand Up @@ -537,7 +540,8 @@ pytime_from_object(_PyTime_t *tp, PyObject *obj, _PyTime_round_t round,
return -1;
}

Py_BUILD_ASSERT(sizeof(long long) <= sizeof(_PyTime_t));
static_assert(sizeof(long long) <= sizeof(_PyTime_t),
"_PyTime_t is smaller than long long");
_PyTime_t ns = (_PyTime_t)sec;
if (pytime_mul(&ns, unit_to_ns) < 0) {
pytime_overflow();
Expand Down Expand Up @@ -589,7 +593,8 @@ PyObject *
_PyTime_AsNanosecondsObject(_PyTime_t t)
{
_PyTime_t ns = pytime_as_nanoseconds(t);
Py_BUILD_ASSERT(sizeof(long long) >= sizeof(_PyTime_t));
static_assert(sizeof(long long) >= sizeof(_PyTime_t),
"_PyTime_t is larger than long long");
return PyLong_FromLongLong((long long)ns);
}

Expand Down Expand Up @@ -984,15 +989,17 @@ py_mach_timebase_info(_PyTime_t *pnumer, _PyTime_t *pdenom, int raise)
_PyTime_t. In practice, timebase uses uint32_t, so casting cannot
overflow. At the end, only make sure that the type is uint32_t
(_PyTime_t is 64-bit long). */
Py_BUILD_ASSERT(sizeof(timebase.numer) < sizeof(_PyTime_t));
Py_BUILD_ASSERT(sizeof(timebase.denom) < sizeof(_PyTime_t));
static_assert(sizeof(timebase.numer) <= sizeof(_PyTime_t),
"timebase.numer is larger than _PyTime_t");
static_assert(sizeof(timebase.denom) <= sizeof(_PyTime_t),
"timebase.denom is larger than _PyTime_t");

/* Make sure that (ticks * timebase.numer) cannot overflow in
_PyTime_MulDiv(), with ticks < timebase.denom.
/* Make sure that _PyTime_MulDiv(ticks, timebase_numer, timebase_denom)
cannot overflow.

Known time bases:

* always (1, 1) on Intel
* (1, 1) on Intel
* (1000000000, 33333335) or (1000000000, 25000000) on PowerPC

None of these time bases can overflow with 64-bit _PyTime_t, but
Expand All @@ -1019,8 +1026,17 @@ py_get_monotonic_clock(_PyTime_t *tp, _Py_clock_info_t *info, int raise_exc)

#if defined(MS_WINDOWS)
ULONGLONG ticks = GetTickCount64();
Py_BUILD_ASSERT(sizeof(ticks) <= sizeof(_PyTime_t));
_PyTime_t t = (_PyTime_t)ticks;
static_assert(sizeof(ticks) <= sizeof(_PyTime_t),
"ULONGLONG is larger than _PyTime_t");
_PyTime_t t;
if (ticks <= (ULONGLONG)_PyTime_MAX) {
t = (_PyTime_t)ticks;
}
else {
// GetTickCount64() maximum is larger than _PyTime_t maximum:
// ULONGLONG is unsigned, whereas _PyTime_t is signed.
t = _PyTime_MAX;
}

int res = pytime_mul(&t, MS_TO_NS);
*tp = t;
Expand Down Expand Up @@ -1211,7 +1227,8 @@ py_get_win_perf_counter(_PyTime_t *tp, _Py_clock_info_t *info, int raise_exc)
/* Make sure that casting LONGLONG to _PyTime_t cannot overflow,
both types are signed */
_PyTime_t ticks;
Py_BUILD_ASSERT(sizeof(ticksll) <= sizeof(ticks));
static_assert(sizeof(ticksll) <= sizeof(ticks),
"LONGLONG is larger than _PyTime_t");
ticks = (_PyTime_t)ticksll;

_PyTime_t ns = _PyTime_MulDiv(ticks, SEC_TO_NS, (_PyTime_t)frequency);
Expand Down