Skip to content

memcpy() usage without #include <string.h> in pwdmodule.c #121617

Description

@fuhsnn

Bug report

Bug description:

For a non-gcc/clang compiler, _Py_TYPEOF is not defined.

cpython/Include/pyport.h

Lines 548 to 551 in c08a302

// The macro is only defined if GCC or clang compiler is used.
#if defined(__GNUC__) || defined(__clang__)
# define _Py_TYPEOF(expr) __typeof__(expr)
#endif

Which leads to Py_CLEAR() fallback to an implementation with memcpy() call.

cpython/Include/object.h

Lines 1016 to 1027 in c08a302

#else
#define Py_CLEAR(op) \
do { \
PyObject **_tmp_op_ptr = _Py_CAST(PyObject**, &(op)); \
PyObject *_tmp_old_op = (*_tmp_op_ptr); \
if (_tmp_old_op != NULL) { \
PyObject *_null_ptr = _Py_NULL; \
memcpy(_tmp_op_ptr, &_null_ptr, sizeof(PyObject*)); \
Py_DECREF(_tmp_old_op); \
} \
} while (0)
#endif

Py_CLEAR() is used in ./Modules/pwdmodule.c

cpython/Modules/pwdmodule.c

Lines 355 to 358 in c08a302

static int pwdmodule_clear(PyObject *m) {
Py_CLEAR(get_pwd_state(m)->StructPwdType);
return 0;
}

without including string.h
#include <errno.h> // ERANGE
#include <pwd.h> // getpwuid()
#include <unistd.h> // sysconf()

For a non-gcc/clang compiler, this may fail due to missing memcpy() declaration.

./Include/object.h:1017: #define Py_CLEAR(op)     do {         PyObject **_tmp_op_ptr = _Py_CAST(PyObject**, &(op));         PyObject *_tmp_old_op = (*_tmp_op_ptr);         if (_tmp_old_op != NULL) {             PyObject *_null_ptr = _Py_NULL;             memcpy(_tmp_op_ptr, &_null_ptr, sizeof(PyObject*));             Py_DECREF(_tmp_old_op);         }     } while (0)
                                                                                                                                                                                                                                                                ^ implicit declaration of a function
./Modules/pwdmodule.c:356:     Py_CLEAR(get_pwd_state(m)->StructPwdType);
                               ^ in expansion of macro

On a side note, typeof is widely implemented among alternative C compilers like TinyCC and cproc, kefir, chibicc, and is standardized in C23. It could be beneficial to enable typeof usage through configure option or probing, instead of hard-coded off on non-gcc/clang compilers.

CPython versions tested on:

3.13

Operating systems tested on:

Linux

Linked PRs

Activity

  1. added
    type-bugAn unexpected behavior, bug, or error
    on Jul 11, 2024
  2. Zheaoli commented on Jul 11, 2024

    @Zheaoli
    Contributor

    For now, GCC and Clang are the officially supported toolchains for Python. I'm not sure we need support extra compiler set.

    But for now, this is expected behavior

  3. fuhsnn commented on Jul 11, 2024

    @fuhsnn
    ContributorAuthor

    For now, GCC and Clang are the officially supported toolchains

    From what I'm seeing, there are new code written as recent as 3.13 that explicitly provide support for 1. standard C11 compiler and 2. MSVC.

    #if _Py_USE_GCC_BUILTIN_ATOMICS
    # define Py_ATOMIC_GCC_H
    # include "cpython/pyatomic_gcc.h"
    # undef Py_ATOMIC_GCC_H
    #elif __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_ATOMICS__)
    # define Py_ATOMIC_STD_H
    # include "cpython/pyatomic_std.h"
    # undef Py_ATOMIC_STD_H
    #elif defined(_MSC_VER)
    # define Py_ATOMIC_MSC_H

    The define logic of _Py_TYPEOF() clearly has "implementations other than GCC and Clang" in mind,

    cpython/Include/pyport.h

    Lines 548 to 551 in c08a302

    // The macro is only defined if GCC or clang compiler is used.
    #if defined(__GNUC__) || defined(__clang__)
    # define _Py_TYPEOF(expr) __typeof__(expr)
    #endif

    even if the guarding condition only exists for MSVC, it would simply be !defined(_MSC_VER).

    If fact, were it be !defined(_MSC_VER) this issue would not exist, since the tested compiler actually support __typeof__.

  4. added a commit that references this issue on Jul 12, 2024
  5. encukou commented on Feb 10, 2026

    @encukou
    Member

    @vstinner, AFAIK you both rewrote Py_CLEAR and removed string.h. Are you interested in this issue?

    I don't think fixing only pwdmodule.h is correct; Py_CLEAR should work for all users of Python.h.

  6. added 3 commits that reference this issue on Feb 10, 2026
  7. vstinner commented on Feb 10, 2026

    @vstinner
    Member

    I don't think fixing only pwdmodule.h is correct; Py_CLEAR should work for all users of Python.h.

    I agree. I wrote #144666 to include <string.h> header if the _Py_TYPEOF macro is not defined.

    On a side note, typeof is widely implemented among alternative C compilers like TinyCC and cproc, kefir, chibicc, and is standardized in C23. It could be beneficial to enable typeof usage through configure option or probing, instead of hard-coded off on non-gcc/clang compilers.

    My PR also modify _Py_TYPEOF() macro to use C23 typeof() if available.

    I wrote a configure check for typeof() but it didn't work as expected. It says that typeof() is available, but then building Python fails because typeof() is undefined. The problem is that configure adds -std=c11 to CFLAGS_NODIST, and typeof() is only defined in C23 or newer. I abandoned the configure change, it's too tricky for me to get it right (run the checks with the same C flags than the ones used to build Python).

  8. vstinner commented on Feb 10, 2026

    @vstinner
    Member

    On a side note, typeof is widely implemented among alternative C compilers like TinyCC and cproc, kefir, chibicc, and is standardized in C23. It could be beneficial to enable typeof usage through configure option or probing, instead of hard-coded off on non-gcc/clang compilers.

    For fun, I tried building Python 3.15 (main branch) with tcc (TinyCC), but it failed to compile _Py_thread_local.

    The following program fails to build with: error: _Thread_local is not implemented (using tcc -std=c11).

    int main()
    {
        _Thread_local int myvar;
        return 0;
    }
  9. added a commit that references this issue on Feb 12, 2026
  10. vstinner commented on Feb 12, 2026

    @vstinner
    Member

    I fixed the Py_CLEAR() issue in the main branch: Python.h now always includes <string.h>.

    I don't think that it's worth it to backport the change to 3.13 and 3.14 branches. I close the issue.

    Thanks for the bug report @fuhsnn.

  11. fuhsnn commented on Feb 12, 2026

    @fuhsnn
    ContributorAuthor

    Thanks @vstinner!

  12. 3 remaining items

  13. added a commit that references this issue on Feb 15, 2026
  14. added a commit that references this issue on Feb 28, 2026
  15. added a commit that references this issue on Apr 25, 2026
  16. added 6 commits that reference this issue on Sep 8, 2026
  17. added 2 commits that reference this issue on Sep 12, 2026
  18. added 2 commits that reference this issue on Sep 14, 2026
  19. added a commit that references this issue on Oct 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    type-bugAn unexpected behavior, bug, or error

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions