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:
Serhiy Storchaka 2020-03-09 20:49:52 +02:00 committed by GitHub
parent 6d0ee60740
commit eebaa9bfc5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 39 additions and 15 deletions

View File

@ -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)

View File

@ -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

View File

@ -0,0 +1,2 @@
:c:macro:`Py_UNREACHABLE` is now implemented with
``__builtin_unreachable()`` and analogs in release mode.

View File

@ -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();
} }

View File

@ -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)

View File

@ -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();
} }
} }

View File

@ -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;
} }

View File

@ -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;
} }