Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Py_BUILD_ASSERT is broken on non-constant expression #118124

Closed
Labels
type-bugAn unexpected behavior, bug, or error
@namniav

Description

@namniav

Bug report

Bug description:

MacrosPy_BUILD_ASSERT andPy_BUILD_ASSERT_EXPR defined inInclude/pymacro.h are broken whencond is not a constant expression, becausesizeof is allowed to apply on variable-length arrays(VLA) since C99 and with compiler extension since C89.

/* Assert a build-time dependency, as an expression.   Your compile will fail if the condition isn't true, or can't be evaluated   by the compiler. This can be used in an expression: its value is 0.   Example:   #define foo_to_char(foo)  \       ((char *)(foo)        \        + Py_BUILD_ASSERT_EXPR(offsetof(struct foo, string) == 0))   Written by Rusty Russell, public domain, http://ccodearchive.net/ */#definePy_BUILD_ASSERT_EXPR(cond) \    (sizeof(char [1 - 2*!(cond)]) - 1)#definePy_BUILD_ASSERT(cond)  do {         \        (void)Py_BUILD_ASSERT_EXPR(cond);   \    } while(0)

Following code compiles on Clang and GCC without error:

voidfoo(intparam){Py_BUILD_ASSERT(param>0);}

Since CPython is now using C11 (PEP7) andstatic_assert is already used in other public internal headers(e.g.Include/internal/pycore_long.h),Py_BUILD_ASSERT should be deprecated and usestatic_assert instead.

Since they are defined in a public header of CPython without a "_Py" prefix, removing them might break third-party code.

Py_BUILD_ASSERT can be defined tostatic_assert in a way with deprecating warning message:

#definePy_BUILD_ASSERT(cond)  do { \        Py_DEPRECATED(3.14) \        int _Py_BUILD_ASSERT_is_deprecated_use_static_assert_instead = 0; \        _Py_BUILD_ASSERT_is_deprecated_use_static_assert_instead; \        static_assert(cond, ""); \    } while(0)

Py_BUILD_ASSERT_EXPR is used (and only used) in another macroPy_ARRAY_LENGTH, so it can't be deprecated yet.

FixingPy_BUILD_ASSERT_EXPR is tricky, most because of old non-conformant MSVC1. And we need it also working in C++. The easiest fix is to change documentation so that it should be used only with constant expression or there's no assertion otherwise. But If we want to make it mandatory, here's a workaround:

#if defined(__cplusplus)template<typenameT>struct_Py_BUILD_ASSERT_EXPR_prohibit_vla {static_assert(sizeof(T)==1,"Py_BUILD_ASSERT_EXPR can only be used with constant ""expression of value true");    };#  definePy_BUILD_ASSERT_EXPR(cond) \        (!sizeof(_Py_BUILD_ASSERT_EXPR_prohibit_vla<char[1 - 2 * !(cond)]>))#elif defined(_MSC_VER)#  definePy_BUILD_ASSERT_EXPR(cond) \        (!sizeof( \            __pragma(warning(push)) \            __pragma(warning(suppress: 4116)) \            enum { \                Py_CONCAT(_Py_BUILD_ASSERT_EXPR_prohibit_vla_,__LINE__) = \                    sizeof(char[1 - 2 * !(cond)]) \            } \            __pragma(warning(pop)) \        ))#else#  definePy_BUILD_ASSERT_EXPR(cond) \        (!sizeof( \            enum { \                Py_CONCAT(_Py_BUILD_ASSERT_EXPR_prohibit_vla_,__LINE__) = \                    sizeof(char[1 - 2 * !(cond)]) \            } \        ))#endif

You can view and try the workarounds using the amazing conformance-viewer in amazing Compiler Explorer: forC and forC++.

CPython versions tested on:

CPython main branch

Operating systems tested on:

No response

Linked PRs

Footnotes

  1. One of the unbelievable bugs is that MSVC prior to v19.21 accepts negative-length(implicitly extended to unsigned value) arrays when used as template argument, e.g.A<char[-1]>.

Metadata

Metadata

Assignees

No one assigned

    Labels

    type-bugAn unexpected behavior, bug, or error

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions


      [8]ページ先頭

      ©2009-2026 Movatter.jp