|
5 | 5 | #define PY_SSIZE_T_CLEAN
|
6 | 6 | #include <Python.h>
|
7 | 7 |
|
| 8 | +#include "_memalloc_debug.h" |
8 | 9 | #include "_memalloc_heap.h"
|
9 | 10 | #include "_memalloc_reentrant.h"
|
10 | 11 | #include "_memalloc_tb.h"
|
@@ -48,7 +49,13 @@ static PyObject* object_string = NULL;
|
48 | 49 | // We add an option here to _add_ a crash, in order to observe this condition in a future diagnostic iteration.
|
49 | 50 | // **This option is _intended_ to crash the Python process** do not use without a good reason!
|
50 | 51 | static char g_crash_on_mutex_pass_str[] = "_DD_PROFILING_MEMALLOC_CRASH_ON_MUTEX_PASS";
|
51 |
| -static const char* g_truthy_values[] = { "1", "true", "yes", "on", "enable", "enabled", NULL }; // NB the sentinel NULL |
| 52 | +// The allocation profiler functions should (in theory) only be called when allocating Python |
| 53 | +// objects, which should (in theory) only be done with the GIL held. We have reason to believe |
| 54 | +// that this code is sometimes reached without the GIL held, since some crashes in the code |
| 55 | +// seem to go away with our own locking. This debug flag will make the profiler crash if |
| 56 | +// it detects the GIL is not held in places where we think it ought to be. |
| 57 | +static char g_crash_on_no_gil_str[] = "_DD_PROFILING_MEMALLOC_CRASH_ON_NO_GIL"; |
| 58 | +static bool g_crash_on_no_gil = false; |
52 | 59 | static memlock_t g_memalloc_lock;
|
53 | 60 |
|
54 | 61 | static alloc_tracker_t* global_alloc_tracker;
|
@@ -92,25 +99,24 @@ static void
|
92 | 99 | memalloc_init()
|
93 | 100 | {
|
94 | 101 | // Check if we should crash the process on mutex pass
|
95 |
| - char* crash_on_mutex_pass_str = getenv(g_crash_on_mutex_pass_str); |
96 |
| - bool crash_on_mutex_pass = false; |
97 |
| - if (crash_on_mutex_pass_str) { |
98 |
| - for (int i = 0; g_truthy_values[i]; i++) { |
99 |
| - if (strcmp(crash_on_mutex_pass_str, g_truthy_values[i]) == 0) { |
100 |
| - crash_on_mutex_pass = true; |
101 |
| - break; |
102 |
| - } |
103 |
| - } |
104 |
| - } |
| 102 | + bool crash_on_mutex_pass = memalloc_get_bool_env(g_crash_on_mutex_pass_str); |
105 | 103 | memlock_init(&g_memalloc_lock, crash_on_mutex_pass);
|
106 | 104 | #ifndef _WIN32
|
107 | 105 | pthread_atfork(memalloc_prefork, memalloc_postfork_parent, memalloc_postfork_child);
|
108 | 106 | #endif
|
| 107 | + |
| 108 | + g_crash_on_no_gil = memalloc_get_bool_env(g_crash_on_no_gil_str); |
109 | 109 | }
|
110 | 110 |
|
111 | 111 | static void
|
112 | 112 | memalloc_add_event(memalloc_context_t* ctx, void* ptr, size_t size)
|
113 | 113 | {
|
| 114 | + if (g_crash_on_no_gil && !PyGILState_Check()) { |
| 115 | + int* p = NULL; |
| 116 | + *p = 0; |
| 117 | + abort(); // should never reach here |
| 118 | + } |
| 119 | + |
114 | 120 | uint64_t alloc_count = atomic_add_clamped(&global_alloc_tracker->alloc_count, 1, ALLOC_TRACKER_MAX_COUNT);
|
115 | 121 |
|
116 | 122 | /* Return if we've reached the maximum number of allocations */
|
|
0 commit comments