Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

segfault in 3.8 and 3.9 when running generated executables with PYTHONDEVMODE=1 #7790

Closed
6 tasks done
godlygeek opened this issue Jul 26, 2023 · 2 comments · Fixed by #7800
Closed
6 tasks done

segfault in 3.8 and 3.9 when running generated executables with PYTHONDEVMODE=1 #7790

godlygeek opened this issue Jul 26, 2023 · 2 comments · Fixed by #7800
Labels

Comments

@godlygeek
Copy link

Description of the issue

PyInstaller generated executables for Python 3.8 and Python 3.9 crash when run with PYTHONDEVMODE=1 set in the environment.

Context information (for bug reports)

  • Output of pyinstaller --version: 5.13.0

  • Version of Python: Reproduces with 3.8 and 3.9, but not with 3.6, 3.7, 3.10, or 3.11

  • Platform: Linux (tested on RHEL 7 and Debian 11.7)

  • try the latest development version, using the following command: ...

Reproduces with the latest development version.

Make sure everything is packaged correctly

  • start with clean installation
  • use the latest development version
  • Run your frozen program from a command window (shell) — instead of double-clicking on it
  • Package your program in --onedir mode
  • Package without UPX, say: use the option --noupx or set upx=False in your .spec-file
  • Repackage you application in verbose/debug mode. For this, pass the option --debug to pyi-makespec or pyinstaller or use EXE(..., debug=1, ...) in your .spec file.

A minimal example program which shows the error

$ python3.9 -m venv venv
$ . venv/bin/activate
(venv) $ pip install -q pyinstaller
(venv) $ pip list | grep pyinstaller
pyinstaller               5.13.0
pyinstaller-hooks-contrib 2023.6
(venv) $ echo 'print("Hello, world!")' >app.py
(venv) $ python -m PyInstaller app.py
249 INFO: PyInstaller: 5.13.0
250 INFO: Python: 3.9.2
255 INFO: Platform: Linux-5.15.117-19636-g22ac9b5f66af-x86_64-with-glibc2.31
260 INFO: wrote /tmp/pyinstaller_issue/app.spec
291 INFO: Extending PYTHONPATH with paths
['/tmp/pyinstaller_issue']
703 INFO: checking Analysis
703 INFO: Building Analysis because Analysis-00.toc is non existent
704 INFO: Initializing module dependency graph...
711 INFO: Caching module graph hooks...
730 INFO: Analyzing base_library.zip ...
2626 INFO: Loading module hook 'hook-encodings.py' from '/tmp/pyinstaller_issue/venv/lib/python3.9/site-packages/PyInstaller/hooks'...
4598 INFO: Loading module hook 'hook-pickle.py' from '/tmp/pyinstaller_issue/venv/lib/python3.9/site-packages/PyInstaller/hooks'...
5968 INFO: Loading module hook 'hook-heapq.py' from '/tmp/pyinstaller_issue/venv/lib/python3.9/site-packages/PyInstaller/hooks'...
7215 INFO: Caching module dependency graph...
7423 INFO: running Analysis Analysis-00.toc
7500 INFO: Analyzing /tmp/pyinstaller_issue/app.py
7512 INFO: Processing module hooks...
7545 INFO: Looking for ctypes DLLs
7553 INFO: Analyzing run-time hooks ...
7572 INFO: Looking for dynamic libraries
8694 INFO: Looking for eggs
8695 INFO: Python library not among binary dependencies. Performing additional search...
8849 INFO: Using Python library /lib/x86_64-linux-gnu/libpython3.9.so.1.0
8864 INFO: Warnings written to /tmp/pyinstaller_issue/build/app/warn-app.txt
8912 INFO: Graph cross-reference written to /tmp/pyinstaller_issue/build/app/xref-app.html
8955 INFO: checking PYZ
8955 INFO: Building PYZ because PYZ-00.toc is non existent
8956 INFO: Building PYZ (ZlibArchive) /tmp/pyinstaller_issue/build/app/PYZ-00.pyz
9283 INFO: Building PYZ (ZlibArchive) /tmp/pyinstaller_issue/build/app/PYZ-00.pyz completed successfully.
9293 INFO: checking PKG
9294 INFO: Building PKG because PKG-00.toc is non existent
9294 INFO: Building PKG (CArchive) app.pkg
9366 INFO: Building PKG (CArchive) app.pkg completed successfully.
9376 INFO: Bootloader /tmp/pyinstaller_issue/venv/lib/python3.9/site-packages/PyInstaller/bootloader/Linux-64bit-intel/run
9376 INFO: checking EXE
9376 INFO: Building EXE because EXE-00.toc is non existent
9376 INFO: Building EXE from EXE-00.toc
9376 INFO: Copying bootloader EXE to /tmp/pyinstaller_issue/build/app/app
9377 INFO: Appending PKG archive to custom ELF section in EXE
9414 INFO: Building EXE from EXE-00.toc completed successfully.
9422 INFO: checking COLLECT
9422 INFO: Building COLLECT because COLLECT-00.toc is non existent
9424 INFO: Building COLLECT COLLECT-00.toc
9508 INFO: Building COLLECT COLLECT-00.toc completed successfully.
(venv) $ ls
app.py  app.spec  build  dist  venv
(venv) $ ./dist/app/app
Hello, world!
(venv) $ PYTHONDEVMODE=1 ./dist/app/app
Debug memory block at address p=0x533210: API ''
    15987178197214944733 bytes originally requested
    The 7 pad bytes at p-7 are not all FORBIDDENBYTE (0xfd):
        at p-7: 0x00 *** OUCH
        at p-6: 0x00 *** OUCH
        at p-5: 0x00 *** OUCH
        at p-4: 0x00 *** OUCH
        at p-3: 0x00 *** OUCH
        at p-2: 0x00 *** OUCH
        at p-1: 0x00 *** OUCH
    Because memory is corrupted at the start, the count of bytes requested
       may be bogus, and checking the trailing pad bytes may segfault.
    The 8 pad bytes at tail=0xddddddddde310fed are zsh: segmentation fault (core dumped)  PYTHONDEVMODE=1 ./dist/app/app
(venv) $

Stacktrace / full error message

Program received signal SIGSEGV, Segmentation fault.
_PyObject_DebugDumpAddress (p=0x431230) at ../Objects/obmalloc.c:2458
2458    ../Objects/obmalloc.c: No such file or directory.
(gdb) bt
#0  _PyObject_DebugDumpAddress (p=0x431230) at ../Objects/obmalloc.c:2458
#1  0x00007ffff792e821 in _PyMem_DebugCheckAddress (func=func@entry=0x7ffff7b279d0 <__func__.1> "_PyMem_DebugRawFree", api=<optimized out>, p=p@entry=0x431230) at ../Objects/obmalloc.c:2375
#2  0x00007ffff792eeb9 in _PyMem_DebugRawFree (p=0x431230, ctx=0x7ffff7d54a00 <_PyMem_Debug>) at ../Objects/obmalloc.c:2208
#3  _PyMem_DebugRawFree (ctx=0x7ffff7d54a00 <_PyMem_Debug>, p=0x431230) at ../Objects/obmalloc.c:2197
#4  0x00007ffff79f3f12 in Py_SetPath (path=0x40f4a0 L"/tmp/pyinstaller_issue/dist/app/base_library.zip:/tmp/pyinstaller_issue/dist/app/lib-dynload:/tmp/pyinstaller_issue/dist/app") at ../Python/pathconfig.c:463
#5  0x0000000000405bef in ?? ()
#6  0x0000000000403e46 in ?? ()
#7  0x0000000000404193 in ?? ()
#8  0x00007ffff7dc9d0a in __libc_start_main (main=0x402540, argc=1, argv=0x7fffffffdd18, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffdd08) at ../csu/libc-start.c:308
#9  0x000000000040256e in ?? ()
(gdb)
@godlygeek godlygeek added the triage Please triage and relabel this issue label Jul 26, 2023
@godlygeek godlygeek changed the title segfault in 3.8 and 3.9 when running with PYTHONDEVMODE=1 segfault in 3.8 and 3.9 when running generated executables with PYTHONDEVMODE=1 Jul 26, 2023
@rokm rokm added bug and removed triage Please triage and relabel this issue labels Jul 27, 2023
@rokm
Copy link
Member

rokm commented Jul 27, 2023

Hmm, indeed. Looks like setting PYTHONMALLOC=debug in environment is enough to trigger the error due to strict memory allocator validation.

@rokm
Copy link
Member

rokm commented Jul 27, 2023

Since this can be triggered by the following example,

Code

#include <stdio.h>
#include <dlfcn.h>
#include <wchar.h>


typedef void (_prototype_Py_SetPath) (wchar_t *);


int main (int argc, char **argv)
{
    if (argc != 2) {
        printf("Usage: %s <python_lib>\n", argv[0]);
        return -1;
    }

    void *pylib = dlopen(argv[1], RTLD_NOW | RTLD_GLOBAL);
    if (!pylib) {
        printf("Failed to load python library %s\n", argv[1]);
        return -1;
    }

    _prototype_Py_SetPath *Py_SetPath = dlsym(pylib, "Py_SetPath");
    if (!Py_SetPath) {
        printf("Failed to lookup Py_SetPath!\n");
        return -1;
    }

    wchar_t path[] = L"/some/path";
    Py_SetPath(path);

    dlclose(pylib);

    printf("Great success!\n");

    return 0;
}

Output and backtrace

Debug memory block at address p=0x408b10: API '�'
    0 bytes originally requested
    The 7 pad bytes at p-7 are not all FORBIDDENBYTE (0xfd):
        at p-7: 0x00 *** OUCH
        at p-6: 0x00 *** OUCH
        at p-5: 0x00 *** OUCH
        at p-4: 0x00 *** OUCH
        at p-3: 0x00 *** OUCH
        at p-2: 0x00 *** OUCH
        at p-1: 0x00 *** OUCH
    Because memory is corrupted at the start, the count of bytes requested
       may be bogus, and checking the trailing pad bytes may segfault.
    The 8 pad bytes at tail=0x408b10 are not all FORBIDDENBYTE (0xfd):
        at tail+0: 0x2f *** OUCH
        at tail+1: 0x00 *** OUCH
        at tail+2: 0x00 *** OUCH
        at tail+3: 0x00 *** OUCH
        at tail+4: 0x68 *** OUCH
        at tail+5: 0x00 *** OUCH
        at tail+6: 0x00 *** OUCH
        at tail+7: 0x00 *** OUCH

Enable tracemalloc to get the memory block allocation traceback

Fatal Python error: _PyMem_DebugRawFree: bad ID: Allocated using API '�', verified using API 'r'
Python runtime state: preinitialized


Program received signal SIGABRT, Aborted.
__pthread_kill_implementation (threadid=<optimized out>, signo=signo@entry=6, no_tid=no_tid@entry=0) at pthread_kill.c:44
44	      return INTERNAL_SYSCALL_ERROR_P (ret) ? INTERNAL_SYSCALL_ERRNO (ret) : 0;
Missing separate debuginfos, use: dnf debuginfo-install libxcrypt-4.4.36-1.fc38.x86_64
(gdb) bt
#0  __pthread_kill_implementation (threadid=<optimized out>, signo=signo@entry=6, no_tid=no_tid@entry=0) at pthread_kill.c:44
#1  0x00007ffff7e498b3 in __pthread_kill_internal (signo=6, threadid=<optimized out>) at pthread_kill.c:78
#2  0x00007ffff7df8abe in __GI_raise (sig=sig@entry=6) at ../sysdeps/posix/raise.c:26
#3  0x00007ffff7de187f in __GI_abort () at abort.c:79
#4  0x00007ffff7a66a16 in fatal_error_exit (status=-1) at Python/pylifecycle.c:2201
#5  fatal_error (stream=stream@entry=0x7ffff7f906a0 <_IO_2_1_stderr_>, header=header@entry=0, prefix=prefix@entry=0x0, msg=msg@entry=0x0, status=status@entry=-1) at Python/pylifecycle.c:2219
#6  0x00007ffff7bda03c in _Py_FatalErrorFormat (func=func@entry=0x7ffff7c7ab90 <__func__.1> "_PyMem_DebugRawFree", format=format@entry=0x7ffff7c7a7f0 "bad ID: Allocated using API '%c', verified using API '%c'") at Python/pylifecycle.c:2335
#7  0x00007ffff7b0419c in _PyMem_DebugCheckAddress (func=0x7ffff7c7ab90 <__func__.1> "_PyMem_DebugRawFree", api=<optimized out>, p=<optimized out>) at Objects/obmalloc.c:2376
#8  0x00007ffff7b04b89 in _PyMem_DebugRawFree (p=0x408b10, ctx=0x7ffff7d6e9a0 <_PyMem_Debug>) at Objects/obmalloc.c:2208
#9  _PyMem_DebugRawFree (ctx=0x7ffff7d6e9a0 <_PyMem_Debug>, p=0x408b10) at Objects/obmalloc.c:2197
#10 0x00007ffff7bd38f2 in Py_SetPath (path=0x7fffffffd5c0 L"/some/path") at Python/pathconfig.c:463
#11 0x0000000000401271 in main ()

my guess would be that python is trying to free un-initialized string pointers here.

Perhaps enabling this Py_GetPath call on all platforms would let us work around this mess... CI before and CI after.

I also wonder if we should unset both PYTHONMALLOC and PYTHONDEV at the beginning of bootloader execution, since frozen application is supposed to be isolated from the environment...

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Sep 28, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants