bpo-38249: Expand Py_UNREACHABLE() to __builtin_unreachable() in the release mode. (GH-16329)
Co-authored-by: Victor Stinner <vstinner@python.org>
This commit is contained in:
parent
6d0ee60740
commit
eebaa9bfc5
|
@ -107,11 +107,24 @@ complete listing.
|
||||||
|
|
||||||
.. c:macro:: Py_UNREACHABLE()
|
.. c:macro:: Py_UNREACHABLE()
|
||||||
|
|
||||||
Use this when you have a code path that you do not expect to be reached.
|
Use this when you have a code path that cannot be reached by design.
|
||||||
For example, in the ``default:`` clause in a ``switch`` statement for which
|
For example, in the ``default:`` clause in a ``switch`` statement for which
|
||||||
all possible values are covered in ``case`` statements. Use this in places
|
all possible values are covered in ``case`` statements. Use this in places
|
||||||
where you might be tempted to put an ``assert(0)`` or ``abort()`` call.
|
where you might be tempted to put an ``assert(0)`` or ``abort()`` call.
|
||||||
|
|
||||||
|
In release mode, the macro helps the compiler to optimize the code, and
|
||||||
|
avoids a warning about unreachable code. For example, the macro is
|
||||||
|
implemented with ``__builtin_unreachable()`` on GCC in release mode.
|
||||||
|
|
||||||
|
A use for ``Py_UNREACHABLE()`` is following a call a function that
|
||||||
|
never returns but that is not declared :c:macro:`_Py_NO_RETURN`.
|
||||||
|
|
||||||
|
If a code path is very unlikely code but can be reached under exceptional
|
||||||
|
case, this macro must not be used. For example, under low memory condition
|
||||||
|
or if a system call returns a value out of the expected range. In this
|
||||||
|
case, it's better to report the error to the caller. If the error cannot
|
||||||
|
be reported to caller, :c:func:`Py_FatalError` can be used.
|
||||||
|
|
||||||
.. versionadded:: 3.7
|
.. versionadded:: 3.7
|
||||||
|
|
||||||
.. c:macro:: Py_ABS(x)
|
.. c:macro:: Py_ABS(x)
|
||||||
|
|
|
@ -101,7 +101,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(RANDALL_WAS_HERE)
|
#if defined(RANDALL_WAS_HERE)
|
||||||
#define Py_UNREACHABLE() \
|
# define Py_UNREACHABLE() \
|
||||||
Py_FatalError( \
|
Py_FatalError( \
|
||||||
"If you're seeing this, the code is in what I thought was\n" \
|
"If you're seeing this, the code is in what I thought was\n" \
|
||||||
"an unreachable state.\n\n" \
|
"an unreachable state.\n\n" \
|
||||||
|
@ -113,13 +113,17 @@
|
||||||
"I'm so sorry.\n" \
|
"I'm so sorry.\n" \
|
||||||
"https://xkcd.com/2200")
|
"https://xkcd.com/2200")
|
||||||
#elif defined(Py_DEBUG)
|
#elif defined(Py_DEBUG)
|
||||||
#define Py_UNREACHABLE() \
|
# define Py_UNREACHABLE() \
|
||||||
Py_FatalError( \
|
Py_FatalError( \
|
||||||
"We've reached an unreachable state. Anything is possible.\n" \
|
"We've reached an unreachable state. Anything is possible.\n" \
|
||||||
"The limits were in our heads all along. Follow your dreams.\n" \
|
"The limits were in our heads all along. Follow your dreams.\n" \
|
||||||
"https://xkcd.com/2200")
|
"https://xkcd.com/2200")
|
||||||
|
#elif defined(__GNUC__) || defined(__clang__) || defined(__INTEL_COMPILER)
|
||||||
|
# define Py_UNREACHABLE() __builtin_unreachable()
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
# define Py_UNREACHABLE() __assume(0)
|
||||||
#else
|
#else
|
||||||
#define Py_UNREACHABLE() \
|
# define Py_UNREACHABLE() \
|
||||||
Py_FatalError("Unreachable C code path reached")
|
Py_FatalError("Unreachable C code path reached")
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
:c:macro:`Py_UNREACHABLE` is now implemented with
|
||||||
|
``__builtin_unreachable()`` and analogs in release mode.
|
|
@ -712,7 +712,7 @@ tracemalloc_realloc(void *ctx, void *ptr, size_t new_size)
|
||||||
|
|
||||||
The GIL and the table lock ensures that only one thread is
|
The GIL and the table lock ensures that only one thread is
|
||||||
allocating memory. */
|
allocating memory. */
|
||||||
Py_UNREACHABLE();
|
Py_FatalError("tracemalloc_realloc() failed to allocate a trace");
|
||||||
}
|
}
|
||||||
TABLES_UNLOCK();
|
TABLES_UNLOCK();
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,13 +6,14 @@
|
||||||
Py_LOCAL_INLINE(int)
|
Py_LOCAL_INLINE(int)
|
||||||
unicode_eq(PyObject *aa, PyObject *bb)
|
unicode_eq(PyObject *aa, PyObject *bb)
|
||||||
{
|
{
|
||||||
|
assert(PyUnicode_Check(aa));
|
||||||
|
assert(PyUnicode_Check(bb));
|
||||||
|
assert(PyUnicode_IS_READY(aa));
|
||||||
|
assert(PyUnicode_IS_READY(bb));
|
||||||
|
|
||||||
PyUnicodeObject *a = (PyUnicodeObject *)aa;
|
PyUnicodeObject *a = (PyUnicodeObject *)aa;
|
||||||
PyUnicodeObject *b = (PyUnicodeObject *)bb;
|
PyUnicodeObject *b = (PyUnicodeObject *)bb;
|
||||||
|
|
||||||
if (PyUnicode_READY(a) == -1 || PyUnicode_READY(b) == -1) {
|
|
||||||
Py_UNREACHABLE();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (PyUnicode_GET_LENGTH(a) != PyUnicode_GET_LENGTH(b))
|
if (PyUnicode_GET_LENGTH(a) != PyUnicode_GET_LENGTH(b))
|
||||||
return 0;
|
return 0;
|
||||||
if (PyUnicode_GET_LENGTH(a) == 0)
|
if (PyUnicode_GET_LENGTH(a) == 0)
|
||||||
|
|
|
@ -574,7 +574,7 @@ calc_number_widths(NumberFieldWidths *spec, Py_ssize_t n_prefix,
|
||||||
spec->n_lpadding = n_padding;
|
spec->n_lpadding = n_padding;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* Shouldn't get here, but treat it as '>' */
|
/* Shouldn't get here */
|
||||||
Py_UNREACHABLE();
|
Py_UNREACHABLE();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -511,8 +511,12 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names,
|
||||||
if (instrsize(j) > ilen) {
|
if (instrsize(j) > ilen) {
|
||||||
goto exitUnchanged;
|
goto exitUnchanged;
|
||||||
}
|
}
|
||||||
assert(ilen <= INT_MAX);
|
|
||||||
/* If instrsize(j) < ilen, we'll emit EXTENDED_ARG 0 */
|
/* If instrsize(j) < ilen, we'll emit EXTENDED_ARG 0 */
|
||||||
|
if (ilen > 4) {
|
||||||
|
/* Can only happen when PyCode_Optimize() is called with
|
||||||
|
malformed bytecode. */
|
||||||
|
goto exitUnchanged;
|
||||||
|
}
|
||||||
write_op_arg(codestr + h, opcode, j, (int)ilen);
|
write_op_arg(codestr + h, opcode, j, (int)ilen);
|
||||||
h += ilen;
|
h += ilen;
|
||||||
}
|
}
|
||||||
|
|
|
@ -746,7 +746,7 @@ _PyTime_GetSystemClock(void)
|
||||||
_PyTime_t t;
|
_PyTime_t t;
|
||||||
if (pygettimeofday(&t, NULL, 0) < 0) {
|
if (pygettimeofday(&t, NULL, 0) < 0) {
|
||||||
/* should not happen, _PyTime_Init() checked the clock at startup */
|
/* should not happen, _PyTime_Init() checked the clock at startup */
|
||||||
Py_UNREACHABLE();
|
Py_FatalError("pygettimeofday() failed");
|
||||||
}
|
}
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
@ -776,7 +776,7 @@ pymonotonic(_PyTime_t *tp, _Py_clock_info_t *info, int raise)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
/* Hello, time traveler! */
|
/* Hello, time traveler! */
|
||||||
Py_UNREACHABLE();
|
Py_FatalError("pymonotonic: integer overflow");
|
||||||
}
|
}
|
||||||
*tp = t * MS_TO_NS;
|
*tp = t * MS_TO_NS;
|
||||||
|
|
||||||
|
@ -918,7 +918,7 @@ _PyTime_GetMonotonicClock(void)
|
||||||
if (pymonotonic(&t, NULL, 0) < 0) {
|
if (pymonotonic(&t, NULL, 0) < 0) {
|
||||||
/* should not happen, _PyTime_Init() checked that monotonic clock at
|
/* should not happen, _PyTime_Init() checked that monotonic clock at
|
||||||
startup */
|
startup */
|
||||||
Py_UNREACHABLE();
|
Py_FatalError("pymonotonic() failed");
|
||||||
}
|
}
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
@ -1019,7 +1019,7 @@ _PyTime_GetPerfCounter(void)
|
||||||
{
|
{
|
||||||
_PyTime_t t;
|
_PyTime_t t;
|
||||||
if (_PyTime_GetPerfCounterWithInfo(&t, NULL)) {
|
if (_PyTime_GetPerfCounterWithInfo(&t, NULL)) {
|
||||||
Py_UNREACHABLE();
|
Py_FatalError("_PyTime_GetPerfCounterWithInfo() failed");
|
||||||
}
|
}
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue