Repository navigation
Py_MIN(), Py_MAX() and Py_ABS() cause C compatibility regressions #158942
Description
Activity
- addedtype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
on Oct 6, 2026 Has this caused problems in practice anywhere, or is this just conceptual? Some of these examples look very artificial (it is not particularly useful to use
Py_MAXinswitchcases, for example).cc @vstinner
Reacted by Victor Stinner- addedinterpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)
on Oct 7, 2026 All the examples except the switch one look important to fix. The one with file_scope is however too fragile IMO as Py_MIN/MAX could be considered a function call (in which case it shouldn't be used in arrays static lengths).
IIRC @vstinner you recently altered those macros
- added3.16new features, bugs and security fixesnew features, bugs and security fixestype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or errorinterpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)buildThe build process and cross-buildThe build process and cross-buildand removedtype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or errorinterpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)
on Oct 7, 2026 I created PR #158969 to fix most issues reported here. I didn't fix file_scope.c: you need a workaround in your code for this one. The case_label.c case is not fixed, but just: don't do that :-)
/* file_scope.c: compile with -c */
#include <Python.h>
static char buf[Py_MAX(sizeof(long), 16)];
struct S { char data[Py_MIN(8, 32)]; };
enum { E = Py_MAX(3, 7) };It's unfortunate that this use case is broken by the new macros implementation. If you need the macros at file scope, you might have to bring your own implementation of these macros (copy Python 3.15 macros to your C file and rename them).
/* shadow.c: compile with -c -Wall -Wextra -Wshadow */
int f(int a, int b, int c) { return Py_MAX(Py_MIN(a, b), c); }This one is fixed by my PR.
/* signcmp.c: compile with -c -Wall -Wextra */
int f(size_t n) { return (int)Py_MIN(n, INT_MAX); }That's a legit bug in your bug. It's a nice and deliberate side effect of the new implementation: detect such sign comparison bug!
The correct size is:
int f(size_t n) { return (int)Py_MIN(n, (size_t)INT_MAX); }./* case_label.c: compile with -c */
case Py_MAX(1, 2): return 1;I don't think that's a realistic use case. Just don't do that :-) Did you use a LLM to generate these C files?
Yes, I first noticed the issue where variables named
_xand_ycould be shadowed. I then used an LLM to further evaluate #157496 and generated these test cases.Reacted by Victor Stinner
Bug report
Summary
On GCC and clang, when compiling C ,
Py_MIN(),Py_MAX()andPy_ABS()are now GNU statement expressions that copy each argument into local variables named_xand_y. Code that used these public macros in an integer constant expression no longer compiles: file-scope array sizes, struct member array sizes,enumvalues andcaselabels all fail. Code that passes a bit-field also no longer compiles. When the caller passes a variable named_xor_y, the code compiles and the result is silently wrong:Py_MAX(a, _x)returnsa, andPy_MIN(b, _y)andPy_ABS(_x)read an uninitialized local. Nested calls such asPy_MAX(Py_MIN(a, b), c)now emit-Wshadowwarnings, and mixed-sign arguments such asPy_MIN(size_t_var, INT_MAX)emit-Wsign-comparewarnings under GCC.Reproduction Code
Requires GCC or clang compiling C. MSVC and C++ use the previous ternary definitions. The commands below use GCC 13.3.0 and clang 18.1.3 on x86-64 Linux, with
-Ipointing at a CPython source tree that includes the newInclude/pymacro.h.Wrong results:
Compile failures and new warnings (each block is a separate file):
Actual Behavior
wrong_result.coutput:GCC compiles
wrong_result.cwithout any warning at the default warning level. Under-Wall, clang warnsvariable '_y' is uninitialized when used within its own initialization [-Wuninitialized]and the same for_x. GCC gives no such warning.Compile failures with GCC:
Compile failures with clang:
New warnings:
clang emits no
-Wsign-comparewarning forsigncmp.c.CPython versions tested on:
CPython main branch
Operating systems tested on:
Linux
Linked PRs
Py_MIN,Py_MAX, andPy_ABS#158943