I have a very large (~400k lines) Python function that I am attempting to define through an exec()
call. If I run the following Python script:
exec("""def blah()
# 400k lines of IF/THEN/ELSE
""", globals())
blah()
By calling Python from the command line, it works fine.
However, if I do the same within a Django instance, it crashes the server without any error message or stack trace, which I can only assume is due to a segmentation fault.
Both Django runserver and the above script are run from the same Conda enviroment, and both have unlimited stack available (confirmed by printing out resource.getrlimit
in Django).
Here's my full ulimit -a
output:
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
pending signals (-i) 515017
max locked memory (kbytes, -l) 64
max memory size (kbytes, -m) unlimited
open files (-n) 1024
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 0
stack size (kbytes, -s) unlimited
cpu time (seconds, -t) unlimited
max user processes (-u) 4096
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited
The command sequence to launch the Django server is as follows:
source activate <conda env name>
python manage.py runserver
This is the shell input/output leading to the crash:
(faf) [pymaster@t9dpyths3 faf]$ python manage.py runserver 9000
Watching for file changes with StatReloader
Performing system checks...
System check identified no issues (0 silenced).
August 04, 2020 - 08:25:19
Django version 3.0.3, using settings 'faf.settings'
Starting development server at http://127.0.0.1:9000/
Quit the server with CONTROL-C.
[04/Aug/2020 08:25:25] "GET /projects/ HTTP/1.1" 200 13847
[04/Aug/2020 08:26:49] "PUT /projects/projectname/ HTTP/1.1" 200 76 # This event triggers the exec
(faf) [pymaster@t9dpyths3 faf]$
The problem might be due to int(s), float(s) and others may cause segmentation fault
As mentioned here:
Please try setting the environmental flag PYTHONMALLOC=debug
This might allow your code to run without running into segmentation errors, if you do still get an error you should be able to catch it using.
PYTHONMALLOC=debug python3 -X tracemalloc=10
You might also want to check out: faulthandler
This module contains functions to dump Python tracebacks explicitly, on a fault, after a timeout, or on a user signal. Call faulthandler.enable() to install fault handlers for the SIGSEGV, SIGFPE, SIGABRT, SIGBUS, and SIGILL signals. You can also enable them at startup by setting the PYTHONFAULTHANDLER environment variable or by using the -X faulthandler command line option.
Adding this for more clarity since it's related; the following is taken from the answer provided by Darrrrrren and is a tweak to make faulthandler run on threaded django applications:
So I was able to get a stack trace by initializing Python with faulthandler, but additionally I had to run
manage.py runserver
--nothreading --noreload
- for some reason if you do not disable threading with Django, even faulthandler will not print a stack trace.
If you're using Python 2 (perhaps accidentally), you're simply passing too much to exec
You can reproduce this as follows (also see a relevant codegolf!)
% python2
>>> exec(
... """if True:
... pass
... """ * (200 * 1000) # 400k lines
... )
segmentation fault python2
You should be able to fix this by breaking it up (described in my other answer), or by writing the code to a file and importing it instead (as suggested/already implemented in comments)
This limit on exec
should be fixed in Python 3 (RecursionError), but may affect a few unlucky versions (see ticket).
So I was able to get a stack trace by initializing Python with faulthandler
, but additionally I had to run manage.py runserver --nothreading --noreload
- for some reason if you do not disable threading with Django, even faulthandler will not print a stack trace.
Fatal Python error: Segmentation fault
Current thread 0x00007fe61836b740 (most recent call first):
File "/apps/AADD/projects/FAF/Web App/faf/modelling/views.py", line 42 in index
File "/apps/AADD/envs/faf/lib/python3.6/site-packages/django/core/handlers/base.py", line 113 in _get_response
File "/apps/AADD/envs/faf/lib/python3.6/site-packages/django/core/handlers/exception.py", line 34 in inner
File "/apps/AADD/envs/faf/lib/python3.6/site-packages/django/utils/deprecation.py", line 94 in __call__
File "/apps/AADD/envs/faf/lib/python3.6/site-packages/django/core/handlers/exception.py", line 34 in inner
File "/apps/AADD/envs/faf/lib/python3.6/site-packages/django/utils/deprecation.py", line 94 in __call__
File "/apps/AADD/envs/faf/lib/python3.6/site-packages/django/core/handlers/exception.py", line 34 in inner
File "/apps/AADD/envs/faf/lib/python3.6/site-packages/django/utils/deprecation.py", line 94 in __call__
File "/apps/AADD/envs/faf/lib/python3.6/site-packages/django/core/handlers/exception.py", line 34 in inner
File "/apps/AADD/envs/faf/lib/python3.6/site-packages/django/utils/deprecation.py", line 94 in __call__
File "/apps/AADD/envs/faf/lib/python3.6/site-packages/django/core/handlers/exception.py", line 34 in inner
File "/apps/AADD/envs/faf/lib/python3.6/site-packages/django/utils/deprecation.py", line 94 in __call__
File "/apps/AADD/envs/faf/lib/python3.6/site-packages/django/core/handlers/exception.py", line 34 in inner
File "/apps/AADD/envs/faf/lib/python3.6/site-packages/django/utils/deprecation.py", line 94 in __call__
File "/apps/AADD/envs/faf/lib/python3.6/site-packages/django/core/handlers/exception.py", line 34 in inner
File "/apps/AADD/envs/faf/lib/python3.6/site-packages/django/utils/deprecation.py", line 94 in __call__
File "/apps/AADD/envs/faf/lib/python3.6/site-packages/django/core/handlers/exception.py", line 34 in inner
File "/apps/AADD/envs/faf/lib/python3.6/site-packages/django/core/handlers/base.py", line 75 in get_response
File "/apps/AADD/envs/faf/lib/python3.6/site-packages/django/core/handlers/wsgi.py", line 133 in __call__
File "/apps/AADD/envs/faf/lib/python3.6/site-packages/django/contrib/staticfiles/handlers.py", line 68 in __call__
File "/apps/AADD/envs/faf/lib/python3.6/wsgiref/handlers.py", line 137 in run
File "/apps/AADD/envs/faf/lib/python3.6/site-packages/django/core/servers/basehttp.py", line 197 in handle_one_request
File "/apps/AADD/envs/faf/lib/python3.6/site-packages/django/core/servers/basehttp.py", line 172 in handle
File "/apps/AADD/envs/faf/lib/python3.6/socketserver.py", line 724 in __init__
File "/apps/AADD/envs/faf/lib/python3.6/socketserver.py", line 364 in finish_request
File "/apps/AADD/envs/faf/lib/python3.6/socketserver.py", line 351 in process_request
File "/apps/AADD/envs/faf/lib/python3.6/socketserver.py", line 320 in _handle_request_noblock
File "/apps/AADD/envs/faf/lib/python3.6/socketserver.py", line 241 in serve_forever
File "/apps/AADD/envs/faf/lib/python3.6/site-packages/django/core/servers/basehttp.py", line 216 in run
File "/apps/AADD/envs/faf/lib/python3.6/site-packages/django/core/management/commands/runserver.py", line 139 in inner_run
File "/apps/AADD/envs/faf/lib/python3.6/site-packages/django/core/management/commands/runserver.py", line 104 in run
File "/apps/AADD/envs/faf/lib/python3.6/site-packages/django/core/management/commands/runserver.py", line 95 in handle
File "/apps/AADD/envs/faf/lib/python3.6/site-packages/django/core/management/base.py", line 369 in execute
File "/apps/AADD/envs/faf/lib/python3.6/site-packages/django/core/management/commands/runserver.py", line 60 in execute
File "/apps/AADD/envs/faf/lib/python3.6/site-packages/django/core/management/base.py", line 328 in run_from_argv
File "/apps/AADD/envs/faf/lib/python3.6/site-packages/django/core/management/__init__.py", line 395 in execute
File "/apps/AADD/envs/faf/lib/python3.6/site-packages/django/core/management/__init__.py", line 401 in execute_from_command_line
File "manage.py", line 17 in main
File "manage.py", line 21 in <module>
Segmentation fault
If I provide unlimited stack space, the exec()
actually works in Django, but only with --nothreading
. So I have a hunch that Django is somehow restricting stack size to spawned off threads.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With