From 392f6c5bc8e9548e83b00d1ca6b2223345d8c2ec Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Tue, 3 Dec 2024 11:32:55 +1100 Subject: [PATCH 1/6] Specify minimum PyGC_Head and PyObject alignment to fix build failure As documented in InternalDocs/garbage_collector.md, the garbage collector stores flags in the least significant two bits of the _gc_prev pointer in struct PyGC_Head. Consequently, this pointer is only capable of storing a location that's aligned to a 4-byte boundary. This alignment requirement is documented but it's not actually encoded. The code only works when python happens to run on a platform that has a sufficiently large minimum alignment for the structs in question. The same problem arises with PyObject pointers because the least significant bits get used for PyStackRef tags. Since we know that 2 bits are needed, we also know the minimum alignment that's needed. Let's make that explicit, so the compiler can then make those bits available. This patch fixes a segfault in _bootstrap_python. In 3.14.0 beta 2 this fixes the "Assertion `!PyStackRef_IsTaggedInt(ref)' failed" when built with --config-pydebug. Also, making the requirements explicit improves clarity. This bug was previously investigated by Adrian Glaubitz here: https://lists.debian.org/debian-68k/2024/11/msg00020.html https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1087600 Although Adrian's patch isn't really correct (because natural alignment is not needed), he deserves full credit for finding the root cause. --- Include/internal/pycore_gc.h | 2 +- Include/internal/pycore_interp_structs.h | 3 ++- Include/object.h | 9 +++++++-- .../Build/2024-12-04-10-00-35.gh-issue-127545.t0THjE.rst | 1 + 4 files changed, 11 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Build/2024-12-04-10-00-35.gh-issue-127545.t0THjE.rst diff --git a/Include/internal/pycore_gc.h b/Include/internal/pycore_gc.h index a6519aa086309d..2f65ddd47076f1 100644 --- a/Include/internal/pycore_gc.h +++ b/Include/internal/pycore_gc.h @@ -133,7 +133,7 @@ static inline void _PyObject_GC_SET_SHARED(PyObject *op) { */ #define _PyGC_NEXT_MASK_OLD_SPACE_1 1 -#define _PyGC_PREV_SHIFT 2 +#define _PyGC_PREV_SHIFT _PyObject_ALIGNMENT_SHIFT #define _PyGC_PREV_MASK (((uintptr_t) -1) << _PyGC_PREV_SHIFT) /* set for debugging information */ diff --git a/Include/internal/pycore_interp_structs.h b/Include/internal/pycore_interp_structs.h index f25f5847b3b307..88df75c8774382 100644 --- a/Include/internal/pycore_interp_structs.h +++ b/Include/internal/pycore_interp_structs.h @@ -163,8 +163,9 @@ typedef struct { // Tagged pointer to previous object in the list. // Lowest two bits are used for flags documented later. + // Those bits are made available by the struct's minimum alignment. uintptr_t _gc_prev; -} PyGC_Head; +} PyGC_Head Py_ALIGNED(1 << _PyObject_ALIGNMENT_SHIFT); #define _PyGC_Head_UNUSED PyGC_Head diff --git a/Include/object.h b/Include/object.h index 994cac1ad17501..37b93679d34477 100644 --- a/Include/object.h +++ b/Include/object.h @@ -101,6 +101,11 @@ whose size is determined when the object is allocated. #define PyObject_VAR_HEAD PyVarObject ob_base; #define Py_INVALID_SIZE (Py_ssize_t)-1 +/* PyObjects are given a minimum alignment so that the least significant bits + * of an object pointer become available for other purposes. + */ +#define _PyObject_ALIGNMENT_SHIFT 2 + /* Nothing is actually declared to be a PyObject, but every pointer to * a Python object can be cast to a PyObject*. This is inheritance built * by hand. Similarly every pointer to a variable-size Python object can, @@ -142,7 +147,7 @@ struct _object { #endif PyTypeObject *ob_type; -}; +} Py_ALIGNED(1 << _PyObject_ALIGNMENT_SHIFT); #else // Objects that are not owned by any thread use a thread id (tid) of zero. // This includes both immortal objects and objects whose reference count @@ -160,7 +165,7 @@ struct _object { uint32_t ob_ref_local; // local reference count Py_ssize_t ob_ref_shared; // shared (atomic) reference count PyTypeObject *ob_type; -}; +} Py_ALIGNED(1 << _PyObject_ALIGNMENT_SHIFT); #endif /* Cast argument to PyObject* type. */ diff --git a/Misc/NEWS.d/next/Build/2024-12-04-10-00-35.gh-issue-127545.t0THjE.rst b/Misc/NEWS.d/next/Build/2024-12-04-10-00-35.gh-issue-127545.t0THjE.rst new file mode 100644 index 00000000000000..3667e2778b7b93 --- /dev/null +++ b/Misc/NEWS.d/next/Build/2024-12-04-10-00-35.gh-issue-127545.t0THjE.rst @@ -0,0 +1 @@ +Fix crash when building on Linux/m68k. From e0156b0516ac4d125e480b81990eaf6549f193dc Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Fri, 6 Jun 2025 09:43:46 +0200 Subject: [PATCH 2/6] Replace _Py_ALIGN_AS(V) by _Py_ALIGNED_DEF(N, T) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a common façade for the various `_Alignas` alternatives, which behave in interesting ways. The standard `alignas` errors if it would decrease the alignment; to prevent that it can be used again with the defined variable's type. The standard `alignas` can't be used on a `struct` definition, the workaround is to use it on one of the `struct`'s members. MSVC `declspec(aligned)` only takes integer literals. MSVC `declspec(aligned)` had a bug when applied to a combined struct+member definition. The workaround is to separate the struct definition. Do that for `PyASCIIObject.state`. --- Include/Python.h | 13 --- Include/cpython/unicodeobject.h | 120 +++++++++++------------ Include/internal/pycore_interp_structs.h | 4 +- Include/object.h | 7 +- Include/pymacro.h | 83 ++++++++++------ 5 files changed, 118 insertions(+), 109 deletions(-) diff --git a/Include/Python.h b/Include/Python.h index f34d581f0b4c91..64be80145890a3 100644 --- a/Include/Python.h +++ b/Include/Python.h @@ -59,14 +59,6 @@ # include // __readgsqword() #endif -// Suppress known warnings in Python header files. -#if defined(_MSC_VER) -// Warning that alignas behaviour has changed. Doesn't affect us, because we -// never relied on the old behaviour. -#pragma warning(push) -#pragma warning(disable: 5274) -#endif - // Include Python header files #include "pyport.h" #include "pymacro.h" @@ -146,9 +138,4 @@ #include "cpython/pyfpe.h" #include "cpython/tracemalloc.h" -// Restore warning filter -#ifdef _MSC_VER -#pragma warning(pop) -#endif - #endif /* !Py_PYTHON_H */ diff --git a/Include/cpython/unicodeobject.h b/Include/cpython/unicodeobject.h index 3d0414f5291fe4..3a2457257195d4 100644 --- a/Include/cpython/unicodeobject.h +++ b/Include/cpython/unicodeobject.h @@ -47,6 +47,63 @@ static inline Py_UCS4 Py_UNICODE_LOW_SURROGATE(Py_UCS4 ch) { /* --- Unicode Type ------------------------------------------------------- */ +struct _PyUnicodeObject_state { + /* If interned is non-zero, the two references from the + dictionary to this object are *not* counted in ob_refcnt. + The possible values here are: + 0: Not Interned + 1: Interned + 2: Interned and Immortal + 3: Interned, Immortal, and Static + This categorization allows the runtime to determine the right + cleanup mechanism at runtime shutdown. */ +#ifdef Py_GIL_DISABLED + // Needs to be accessed atomically, so can't be a bit field. + unsigned char interned; +#else + unsigned int interned:2; +#endif + /* Character size: + + - PyUnicode_1BYTE_KIND (1): + + * character type = Py_UCS1 (8 bits, unsigned) + * all characters are in the range U+0000-U+00FF (latin1) + * if ascii is set, all characters are in the range U+0000-U+007F + (ASCII), otherwise at least one character is in the range + U+0080-U+00FF + + - PyUnicode_2BYTE_KIND (2): + + * character type = Py_UCS2 (16 bits, unsigned) + * all characters are in the range U+0000-U+FFFF (BMP) + * at least one character is in the range U+0100-U+FFFF + + - PyUnicode_4BYTE_KIND (4): + + * character type = Py_UCS4 (32 bits, unsigned) + * all characters are in the range U+0000-U+10FFFF + * at least one character is in the range U+10000-U+10FFFF + */ + unsigned int kind:3; + /* Compact is with respect to the allocation scheme. Compact unicode + objects only require one memory block while non-compact objects use + one block for the PyUnicodeObject struct and another for its data + buffer. */ + unsigned int compact:1; + /* The string only contains characters in the range U+0000-U+007F (ASCII) + and the kind is PyUnicode_1BYTE_KIND. If ascii is set and compact is + set, use the PyASCIIObject structure. */ + unsigned int ascii:1; + /* The object is statically allocated. */ + unsigned int statically_allocated:1; +#ifndef Py_GIL_DISABLED + /* Historical: padding to ensure that PyUnicode_DATA() is always aligned to + 4 bytes (see issue gh-63736 on m68k) */ + unsigned int :24; +#endif +}; + /* ASCII-only strings created through PyUnicode_New use the PyASCIIObject structure. state.ascii and state.compact are set, and the data immediately follow the structure. utf8_length can be found @@ -99,67 +156,8 @@ typedef struct { PyObject_HEAD Py_ssize_t length; /* Number of code points in the string */ Py_hash_t hash; /* Hash value; -1 if not set */ -#ifdef Py_GIL_DISABLED - /* Ensure 4 byte alignment for PyUnicode_DATA(), see gh-63736 on m68k. - In the non-free-threaded build, we'll use explicit padding instead */ - _Py_ALIGN_AS(4) -#endif - struct { - /* If interned is non-zero, the two references from the - dictionary to this object are *not* counted in ob_refcnt. - The possible values here are: - 0: Not Interned - 1: Interned - 2: Interned and Immortal - 3: Interned, Immortal, and Static - This categorization allows the runtime to determine the right - cleanup mechanism at runtime shutdown. */ -#ifdef Py_GIL_DISABLED - // Needs to be accessed atomically, so can't be a bit field. - unsigned char interned; -#else - unsigned int interned:2; -#endif - /* Character size: - - - PyUnicode_1BYTE_KIND (1): - - * character type = Py_UCS1 (8 bits, unsigned) - * all characters are in the range U+0000-U+00FF (latin1) - * if ascii is set, all characters are in the range U+0000-U+007F - (ASCII), otherwise at least one character is in the range - U+0080-U+00FF - - - PyUnicode_2BYTE_KIND (2): - - * character type = Py_UCS2 (16 bits, unsigned) - * all characters are in the range U+0000-U+FFFF (BMP) - * at least one character is in the range U+0100-U+FFFF - - - PyUnicode_4BYTE_KIND (4): - - * character type = Py_UCS4 (32 bits, unsigned) - * all characters are in the range U+0000-U+10FFFF - * at least one character is in the range U+10000-U+10FFFF - */ - unsigned int kind:3; - /* Compact is with respect to the allocation scheme. Compact unicode - objects only require one memory block while non-compact objects use - one block for the PyUnicodeObject struct and another for its data - buffer. */ - unsigned int compact:1; - /* The string only contains characters in the range U+0000-U+007F (ASCII) - and the kind is PyUnicode_1BYTE_KIND. If ascii is set and compact is - set, use the PyASCIIObject structure. */ - unsigned int ascii:1; - /* The object is statically allocated. */ - unsigned int statically_allocated:1; -#ifndef Py_GIL_DISABLED - /* Padding to ensure that PyUnicode_DATA() is always aligned to - 4 bytes (see issue gh-63736 on m68k) */ - unsigned int :24; -#endif - } state; + /* Ensure 4 byte alignment for PyUnicode_DATA(), see gh-63736 on m68k. */ + _Py_ALIGNED_DEF(4, struct _PyUnicodeObject_state) state; } PyASCIIObject; /* Non-ASCII strings allocated through PyUnicode_New use the diff --git a/Include/internal/pycore_interp_structs.h b/Include/internal/pycore_interp_structs.h index 88df75c8774382..e180fcb85e8d32 100644 --- a/Include/internal/pycore_interp_structs.h +++ b/Include/internal/pycore_interp_structs.h @@ -159,13 +159,13 @@ struct atexit_state { typedef struct { // Tagged pointer to next object in the list. // 0 means the object is not tracked - uintptr_t _gc_next; + _Py_ALIGNED_DEF(1 << _PyObject_ALIGNMENT_SHIFT, uintptr_t) _gc_next; // Tagged pointer to previous object in the list. // Lowest two bits are used for flags documented later. // Those bits are made available by the struct's minimum alignment. uintptr_t _gc_prev; -} PyGC_Head Py_ALIGNED(1 << _PyObject_ALIGNMENT_SHIFT); +} PyGC_Head; #define _PyGC_Head_UNUSED PyGC_Head diff --git a/Include/object.h b/Include/object.h index 37b93679d34477..63b7cb6219fe4b 100644 --- a/Include/object.h +++ b/Include/object.h @@ -141,13 +141,14 @@ struct _object { #else Py_ssize_t ob_refcnt; #endif + _Py_ALIGNED_DEF(1 << _PyObject_ALIGNMENT_SHIFT, char) _aligner; }; #ifdef _MSC_VER __pragma(warning(pop)) #endif PyTypeObject *ob_type; -} Py_ALIGNED(1 << _PyObject_ALIGNMENT_SHIFT); +}; #else // Objects that are not owned by any thread use a thread id (tid) of zero. // This includes both immortal objects and objects whose reference count @@ -158,14 +159,14 @@ struct _object { // ob_tid stores the thread id (or zero). It is also used by the GC and the // trashcan mechanism as a linked list pointer and by the GC to store the // computed "gc_refs" refcount. - uintptr_t ob_tid; + _Py_ALIGNED_DEF(1 << _PyObject_ALIGNMENT_SHIFT, uintptr_t) ob_tid; uint16_t ob_flags; PyMutex ob_mutex; // per-object lock uint8_t ob_gc_bits; // gc-related state uint32_t ob_ref_local; // local reference count Py_ssize_t ob_ref_shared; // shared (atomic) reference count PyTypeObject *ob_type; -} Py_ALIGNED(1 << _PyObject_ALIGNMENT_SHIFT); +}; #endif /* Cast argument to PyObject* type. */ diff --git a/Include/pymacro.h b/Include/pymacro.h index d410645034d848..c219b04b5fe59b 100644 --- a/Include/pymacro.h +++ b/Include/pymacro.h @@ -24,44 +24,67 @@ #endif -// _Py_ALIGN_AS: this compiler's spelling of `alignas` keyword, -// We currently use alignas for free-threaded builds only; additional compat -// checking would be great before we add it to the default build. -// Standards/compiler support: +// _Py_ALIGNED_DEF(N, T): Define a variable/member with increased alignment +// +// `N`: the desired minimum alignment, an integer literal +// `T`: the type of the defined variable +// (or a type with at least the defined variable's alignment) +// +// May not be used on a struct definition. +// +// Standards/compiler support for `alignas` alternatives: // - `alignas` is a keyword in C23 and C++11. // - `_Alignas` is a keyword in C11 // - GCC & clang has __attribute__((aligned)) // (use that for older standards in pedantic mode) // - MSVC has __declspec(align) // - `_Alignas` is common C compiler extension -// Older compilers may name it differently; to allow compilation on such -// unsupported platforms, we don't redefine _Py_ALIGN_AS if it's already +// Older compilers may name `alignas` differently; to allow compilation on such +// unsupported platforms, we don't redefine _Py_ALIGNED_DEF if it's already // defined. Note that defining it wrong (including defining it to nothing) will // cause ABI incompatibilities. -#ifdef Py_GIL_DISABLED -# ifndef _Py_ALIGN_AS -# ifdef __cplusplus -# if __cplusplus >= 201103L -# define _Py_ALIGN_AS(V) alignas(V) -# elif defined(__GNUC__) || defined(__clang__) -# define _Py_ALIGN_AS(V) __attribute__((aligned(V))) -# elif defined(_MSC_VER) -# define _Py_ALIGN_AS(V) __declspec(align(V)) -# else -# define _Py_ALIGN_AS(V) alignas(V) -# endif -# elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L -# define _Py_ALIGN_AS(V) alignas(V) -# elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L -# define _Py_ALIGN_AS(V) _Alignas(V) -# elif (defined(__GNUC__) || defined(__clang__)) -# define _Py_ALIGN_AS(V) __attribute__((aligned(V))) -# elif defined(_MSC_VER) -# define _Py_ALIGN_AS(V) __declspec(align(V)) -# else -# define _Py_ALIGN_AS(V) _Alignas(V) -# endif -# endif +// +// Behavior of `alignas` alternatives: +// - `alignas` & `_Alignas`: +// - Can be used multiple times; the greatest alignment applies. +// - It is an *error* if the combined effect of all `alignas` modifiers would +// decrease the alignment. +// - Takes types or numbers. +// - May not be used on a struct definition, unless also defining a variable. +// - Can't be used on a whole struct, only on members. +// - `__declspec(align)`: +// - Has no effect if it would decrease alignment. +// - Only takes an integer literal. +// - May be used on struct or variable definitions. +// - ` __attribute__((aligned))`: +// - Has no effect if it would decrease alignment. +// - Takes types or numbers +// - May be used on struct or variable definitions. +// However, when defining both the struct and the variable at once, +// `declspec(aligned)` causes compiler warning 5274 and possible ABI +// incompatibility. +#ifndef _Py_ALIGNED_DEF +# ifdef __cplusplus +# if __cplusplus >= 201103L +# define _Py_ALIGNED_DEF(N, T) alignas(N) alignas(T) T +# elif defined(__GNUC__) || defined(__clang__) +# define _Py_ALIGNED_DEF(N, T) __attribute__((aligned(N))) T +# elif defined(_MSC_VER) +# define _Py_ALIGNED_DEF(N, T) __declspec(align(N)) T +# else +# define _Py_ALIGNED_DEF(N, T) alignas(N) alignas(T) T +# endif +# elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L +# define _Py_ALIGNED_DEF(N, T) alignas(N) alignas(T) T +# elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L +# define _Py_ALIGNED_DEF(N, T) _Alignas(N) _Alignas(T) T +# elif (defined(__GNUC__) || defined(__clang__)) +# define _Py_ALIGNED_DEF(N, T) __attribute__((aligned(N))) T +# elif defined(_MSC_VER) +# define _Py_ALIGNED_DEF(N, T) __declspec(align(N)) T +# else +# define _Py_ALIGNED_DEF(N, T) _Alignas(N) _Alignas(T) T +# endif #endif /* Minimum value between x and y */ From 512fe5844e22a5639765416d67e6376880e4bba4 Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Fri, 6 Jun 2025 14:52:33 +0200 Subject: [PATCH 3/6] Actually make this a literal --- Include/internal/pycore_gc.h | 2 +- Include/internal/pycore_interp_structs.h | 2 +- Include/object.h | 7 ++++--- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Include/internal/pycore_gc.h b/Include/internal/pycore_gc.h index 2f65ddd47076f1..a6519aa086309d 100644 --- a/Include/internal/pycore_gc.h +++ b/Include/internal/pycore_gc.h @@ -133,7 +133,7 @@ static inline void _PyObject_GC_SET_SHARED(PyObject *op) { */ #define _PyGC_NEXT_MASK_OLD_SPACE_1 1 -#define _PyGC_PREV_SHIFT _PyObject_ALIGNMENT_SHIFT +#define _PyGC_PREV_SHIFT 2 #define _PyGC_PREV_MASK (((uintptr_t) -1) << _PyGC_PREV_SHIFT) /* set for debugging information */ diff --git a/Include/internal/pycore_interp_structs.h b/Include/internal/pycore_interp_structs.h index e180fcb85e8d32..f1f427d99dea69 100644 --- a/Include/internal/pycore_interp_structs.h +++ b/Include/internal/pycore_interp_structs.h @@ -159,7 +159,7 @@ struct atexit_state { typedef struct { // Tagged pointer to next object in the list. // 0 means the object is not tracked - _Py_ALIGNED_DEF(1 << _PyObject_ALIGNMENT_SHIFT, uintptr_t) _gc_next; + _Py_ALIGNED_DEF(_PyObject_MIN_ALIGNMENT, uintptr_t) _gc_next; // Tagged pointer to previous object in the list. // Lowest two bits are used for flags documented later. diff --git a/Include/object.h b/Include/object.h index 63b7cb6219fe4b..80bba1fd2d9561 100644 --- a/Include/object.h +++ b/Include/object.h @@ -103,8 +103,9 @@ whose size is determined when the object is allocated. /* PyObjects are given a minimum alignment so that the least significant bits * of an object pointer become available for other purposes. + * This must be an integer literal with the value (1 << _PyGC_PREV_SHIFT) */ -#define _PyObject_ALIGNMENT_SHIFT 2 +#define _PyObject_MIN_ALIGNMENT 4 /* Nothing is actually declared to be a PyObject, but every pointer to * a Python object can be cast to a PyObject*. This is inheritance built @@ -141,7 +142,7 @@ struct _object { #else Py_ssize_t ob_refcnt; #endif - _Py_ALIGNED_DEF(1 << _PyObject_ALIGNMENT_SHIFT, char) _aligner; + _Py_ALIGNED_DEF(_PyObject_MIN_ALIGNMENT, char) _aligner; }; #ifdef _MSC_VER __pragma(warning(pop)) @@ -159,7 +160,7 @@ struct _object { // ob_tid stores the thread id (or zero). It is also used by the GC and the // trashcan mechanism as a linked list pointer and by the GC to store the // computed "gc_refs" refcount. - _Py_ALIGNED_DEF(1 << _PyObject_ALIGNMENT_SHIFT, uintptr_t) ob_tid; + _Py_ALIGNED_DEF(_PyObject_MIN_ALIGNMENT, uintptr_t) ob_tid; uint16_t ob_flags; PyMutex ob_mutex; // per-object lock uint8_t ob_gc_bits; // gc-related state From 851cc3ad4135929771c4bcd7152fd75ac8617043 Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Sat, 7 Jun 2025 11:34:59 +0200 Subject: [PATCH 4/6] Move comment to the appropriate place --- Include/pymacro.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Include/pymacro.h b/Include/pymacro.h index c219b04b5fe59b..508db9de598a7a 100644 --- a/Include/pymacro.h +++ b/Include/pymacro.h @@ -56,13 +56,13 @@ // - Has no effect if it would decrease alignment. // - Only takes an integer literal. // - May be used on struct or variable definitions. +// However, when defining both the struct and the variable at once, +// `declspec(aligned)` causes compiler warning 5274 and possible ABI +// incompatibility. // - ` __attribute__((aligned))`: // - Has no effect if it would decrease alignment. // - Takes types or numbers // - May be used on struct or variable definitions. -// However, when defining both the struct and the variable at once, -// `declspec(aligned)` causes compiler warning 5274 and possible ABI -// incompatibility. #ifndef _Py_ALIGNED_DEF # ifdef __cplusplus # if __cplusplus >= 201103L From 80801dbe555e13abde5922f7a781f8a32e8cb0cc Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Sat, 7 Jun 2025 11:36:24 +0200 Subject: [PATCH 5/6] Remove redundant comment --- Include/pymacro.h | 1 - 1 file changed, 1 deletion(-) diff --git a/Include/pymacro.h b/Include/pymacro.h index 508db9de598a7a..c1c38ce8a1874a 100644 --- a/Include/pymacro.h +++ b/Include/pymacro.h @@ -51,7 +51,6 @@ // decrease the alignment. // - Takes types or numbers. // - May not be used on a struct definition, unless also defining a variable. -// - Can't be used on a whole struct, only on members. // - `__declspec(align)`: // - Has no effect if it would decrease alignment. // - Only takes an integer literal. From 6d7c805d769cf93318953d512f277479638bc0d1 Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Tue, 10 Jun 2025 13:08:33 +0200 Subject: [PATCH 6/6] Clarify units Co-authored-by: Victor Stinner --- Include/object.h | 2 +- Include/pymacro.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Include/object.h b/Include/object.h index 80bba1fd2d9561..f0a6b69bfd871f 100644 --- a/Include/object.h +++ b/Include/object.h @@ -103,7 +103,7 @@ whose size is determined when the object is allocated. /* PyObjects are given a minimum alignment so that the least significant bits * of an object pointer become available for other purposes. - * This must be an integer literal with the value (1 << _PyGC_PREV_SHIFT) + * This must be an integer literal with the value (1 << _PyGC_PREV_SHIFT), number of bytes. */ #define _PyObject_MIN_ALIGNMENT 4 diff --git a/Include/pymacro.h b/Include/pymacro.h index c1c38ce8a1874a..bfe660e8303d0f 100644 --- a/Include/pymacro.h +++ b/Include/pymacro.h @@ -26,7 +26,7 @@ // _Py_ALIGNED_DEF(N, T): Define a variable/member with increased alignment // -// `N`: the desired minimum alignment, an integer literal +// `N`: the desired minimum alignment, an integer literal, number of bytes // `T`: the type of the defined variable // (or a type with at least the defined variable's alignment) //