sf-veritas 0.11.10__cp314-cp314-manylinux_2_28_x86_64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (141) hide show
  1. sf_veritas/__init__.py +46 -0
  2. sf_veritas/_auto_preload.py +73 -0
  3. sf_veritas/_sfconfig.c +162 -0
  4. sf_veritas/_sfconfig.cpython-314-x86_64-linux-gnu.so +0 -0
  5. sf_veritas/_sfcrashhandler.c +267 -0
  6. sf_veritas/_sfcrashhandler.cpython-314-x86_64-linux-gnu.so +0 -0
  7. sf_veritas/_sffastlog.c +953 -0
  8. sf_veritas/_sffastlog.cpython-314-x86_64-linux-gnu.so +0 -0
  9. sf_veritas/_sffastnet.c +994 -0
  10. sf_veritas/_sffastnet.cpython-314-x86_64-linux-gnu.so +0 -0
  11. sf_veritas/_sffastnetworkrequest.c +727 -0
  12. sf_veritas/_sffastnetworkrequest.cpython-314-x86_64-linux-gnu.so +0 -0
  13. sf_veritas/_sffuncspan.c +2791 -0
  14. sf_veritas/_sffuncspan.cpython-314-x86_64-linux-gnu.so +0 -0
  15. sf_veritas/_sffuncspan_config.c +730 -0
  16. sf_veritas/_sffuncspan_config.cpython-314-x86_64-linux-gnu.so +0 -0
  17. sf_veritas/_sfheadercheck.c +341 -0
  18. sf_veritas/_sfheadercheck.cpython-314-x86_64-linux-gnu.so +0 -0
  19. sf_veritas/_sfnetworkhop.c +1454 -0
  20. sf_veritas/_sfnetworkhop.cpython-314-x86_64-linux-gnu.so +0 -0
  21. sf_veritas/_sfservice.c +1223 -0
  22. sf_veritas/_sfservice.cpython-314-x86_64-linux-gnu.so +0 -0
  23. sf_veritas/_sfteepreload.c +6227 -0
  24. sf_veritas/app_config.py +57 -0
  25. sf_veritas/cli.py +336 -0
  26. sf_veritas/constants.py +10 -0
  27. sf_veritas/custom_excepthook.py +304 -0
  28. sf_veritas/custom_log_handler.py +146 -0
  29. sf_veritas/custom_output_wrapper.py +153 -0
  30. sf_veritas/custom_print.py +153 -0
  31. sf_veritas/django_app.py +5 -0
  32. sf_veritas/env_vars.py +186 -0
  33. sf_veritas/exception_handling_middleware.py +18 -0
  34. sf_veritas/exception_metaclass.py +69 -0
  35. sf_veritas/fast_frame_info.py +116 -0
  36. sf_veritas/fast_network_hop.py +293 -0
  37. sf_veritas/frame_tools.py +112 -0
  38. sf_veritas/funcspan_config_loader.py +693 -0
  39. sf_veritas/function_span_profiler.py +1313 -0
  40. sf_veritas/get_preload_path.py +34 -0
  41. sf_veritas/import_hook.py +62 -0
  42. sf_veritas/infra_details/__init__.py +3 -0
  43. sf_veritas/infra_details/get_infra_details.py +24 -0
  44. sf_veritas/infra_details/kubernetes/__init__.py +3 -0
  45. sf_veritas/infra_details/kubernetes/get_cluster_name.py +147 -0
  46. sf_veritas/infra_details/kubernetes/get_details.py +7 -0
  47. sf_veritas/infra_details/running_on/__init__.py +17 -0
  48. sf_veritas/infra_details/running_on/kubernetes.py +11 -0
  49. sf_veritas/interceptors.py +543 -0
  50. sf_veritas/libsfnettee.so +0 -0
  51. sf_veritas/local_env_detect.py +118 -0
  52. sf_veritas/package_metadata.py +6 -0
  53. sf_veritas/patches/__init__.py +0 -0
  54. sf_veritas/patches/_patch_tracker.py +74 -0
  55. sf_veritas/patches/concurrent_futures.py +19 -0
  56. sf_veritas/patches/constants.py +1 -0
  57. sf_veritas/patches/exceptions.py +82 -0
  58. sf_veritas/patches/multiprocessing.py +32 -0
  59. sf_veritas/patches/network_libraries/__init__.py +99 -0
  60. sf_veritas/patches/network_libraries/aiohttp.py +294 -0
  61. sf_veritas/patches/network_libraries/curl_cffi.py +363 -0
  62. sf_veritas/patches/network_libraries/http_client.py +670 -0
  63. sf_veritas/patches/network_libraries/httpcore.py +580 -0
  64. sf_veritas/patches/network_libraries/httplib2.py +315 -0
  65. sf_veritas/patches/network_libraries/httpx.py +557 -0
  66. sf_veritas/patches/network_libraries/niquests.py +218 -0
  67. sf_veritas/patches/network_libraries/pycurl.py +399 -0
  68. sf_veritas/patches/network_libraries/requests.py +595 -0
  69. sf_veritas/patches/network_libraries/ssl_socket.py +822 -0
  70. sf_veritas/patches/network_libraries/tornado.py +360 -0
  71. sf_veritas/patches/network_libraries/treq.py +270 -0
  72. sf_veritas/patches/network_libraries/urllib_request.py +483 -0
  73. sf_veritas/patches/network_libraries/utils.py +598 -0
  74. sf_veritas/patches/os.py +17 -0
  75. sf_veritas/patches/threading.py +231 -0
  76. sf_veritas/patches/web_frameworks/__init__.py +54 -0
  77. sf_veritas/patches/web_frameworks/aiohttp.py +798 -0
  78. sf_veritas/patches/web_frameworks/async_websocket_consumer.py +337 -0
  79. sf_veritas/patches/web_frameworks/blacksheep.py +532 -0
  80. sf_veritas/patches/web_frameworks/bottle.py +513 -0
  81. sf_veritas/patches/web_frameworks/cherrypy.py +683 -0
  82. sf_veritas/patches/web_frameworks/cors_utils.py +122 -0
  83. sf_veritas/patches/web_frameworks/django.py +963 -0
  84. sf_veritas/patches/web_frameworks/eve.py +401 -0
  85. sf_veritas/patches/web_frameworks/falcon.py +931 -0
  86. sf_veritas/patches/web_frameworks/fastapi.py +738 -0
  87. sf_veritas/patches/web_frameworks/flask.py +526 -0
  88. sf_veritas/patches/web_frameworks/klein.py +501 -0
  89. sf_veritas/patches/web_frameworks/litestar.py +616 -0
  90. sf_veritas/patches/web_frameworks/pyramid.py +440 -0
  91. sf_veritas/patches/web_frameworks/quart.py +841 -0
  92. sf_veritas/patches/web_frameworks/robyn.py +708 -0
  93. sf_veritas/patches/web_frameworks/sanic.py +874 -0
  94. sf_veritas/patches/web_frameworks/starlette.py +742 -0
  95. sf_veritas/patches/web_frameworks/strawberry.py +1446 -0
  96. sf_veritas/patches/web_frameworks/tornado.py +485 -0
  97. sf_veritas/patches/web_frameworks/utils.py +170 -0
  98. sf_veritas/print_override.py +13 -0
  99. sf_veritas/regular_data_transmitter.py +444 -0
  100. sf_veritas/request_interceptor.py +401 -0
  101. sf_veritas/request_utils.py +550 -0
  102. sf_veritas/segfault_handler.py +116 -0
  103. sf_veritas/server_status.py +1 -0
  104. sf_veritas/shutdown_flag.py +11 -0
  105. sf_veritas/subprocess_startup.py +3 -0
  106. sf_veritas/test_cli.py +145 -0
  107. sf_veritas/thread_local.py +1319 -0
  108. sf_veritas/timeutil.py +114 -0
  109. sf_veritas/transmit_exception_to_sailfish.py +28 -0
  110. sf_veritas/transmitter.py +132 -0
  111. sf_veritas/types.py +47 -0
  112. sf_veritas/unified_interceptor.py +1678 -0
  113. sf_veritas/utils.py +39 -0
  114. sf_veritas-0.11.10.dist-info/METADATA +97 -0
  115. sf_veritas-0.11.10.dist-info/RECORD +141 -0
  116. sf_veritas-0.11.10.dist-info/WHEEL +5 -0
  117. sf_veritas-0.11.10.dist-info/entry_points.txt +2 -0
  118. sf_veritas-0.11.10.dist-info/top_level.txt +1 -0
  119. sf_veritas.libs/libbrotlicommon-6ce2a53c.so.1.0.6 +0 -0
  120. sf_veritas.libs/libbrotlidec-811d1be3.so.1.0.6 +0 -0
  121. sf_veritas.libs/libcom_err-730ca923.so.2.1 +0 -0
  122. sf_veritas.libs/libcrypt-52aca757.so.1.1.0 +0 -0
  123. sf_veritas.libs/libcrypto-bdaed0ea.so.1.1.1k +0 -0
  124. sf_veritas.libs/libcurl-eaa3cf66.so.4.5.0 +0 -0
  125. sf_veritas.libs/libgssapi_krb5-323bbd21.so.2.2 +0 -0
  126. sf_veritas.libs/libidn2-2f4a5893.so.0.3.6 +0 -0
  127. sf_veritas.libs/libk5crypto-9a74ff38.so.3.1 +0 -0
  128. sf_veritas.libs/libkeyutils-2777d33d.so.1.6 +0 -0
  129. sf_veritas.libs/libkrb5-a55300e8.so.3.3 +0 -0
  130. sf_veritas.libs/libkrb5support-e6594cfc.so.0.1 +0 -0
  131. sf_veritas.libs/liblber-2-d20824ef.4.so.2.10.9 +0 -0
  132. sf_veritas.libs/libldap-2-cea2a960.4.so.2.10.9 +0 -0
  133. sf_veritas.libs/libnghttp2-39367a22.so.14.17.0 +0 -0
  134. sf_veritas.libs/libpcre2-8-516f4c9d.so.0.7.1 +0 -0
  135. sf_veritas.libs/libpsl-99becdd3.so.5.3.1 +0 -0
  136. sf_veritas.libs/libsasl2-7de4d792.so.3.0.0 +0 -0
  137. sf_veritas.libs/libselinux-d0805dcb.so.1 +0 -0
  138. sf_veritas.libs/libssh-c11d285b.so.4.8.7 +0 -0
  139. sf_veritas.libs/libssl-60250281.so.1.1.1k +0 -0
  140. sf_veritas.libs/libunistring-05abdd40.so.2.1.0 +0 -0
  141. sf_veritas.libs/libuuid-95b83d40.so.1.3.0 +0 -0
sf_veritas/__init__.py ADDED
@@ -0,0 +1,46 @@
1
+ # Note: LD_PRELOAD must be set manually by user for C library mode
2
+ # The C library (libsfnettee.so) is available but requires explicit LD_PRELOAD configuration
3
+
4
+ # Install C-level crash handler FIRST (catches crashes before Python can)
5
+ import sys
6
+ try:
7
+ sys.stderr.write("[__init__] Attempting to load C crash handler...\n")
8
+ sys.stderr.flush()
9
+ from . import _sfcrashhandler
10
+ sys.stderr.write("[__init__] C crash handler module loaded, installing...\n")
11
+ sys.stderr.flush()
12
+ _sfcrashhandler.install()
13
+ sys.stderr.write("[__init__] C crash handler installed successfully\n")
14
+ sys.stderr.flush()
15
+ except Exception as e:
16
+ import traceback
17
+ sys.stderr.write(f"[WARNING] Failed to install C crash handler: {e}\n")
18
+ traceback.print_exc(file=sys.stderr)
19
+ sys.stderr.flush()
20
+
21
+ # Install Python-level segfault handler as backup
22
+ try:
23
+ from . import segfault_handler # noqa: F401
24
+ except Exception:
25
+ pass # Silently fail if handler can't be installed
26
+
27
+ from .function_span_profiler import (
28
+ skip_tracing, # Backward compatibility
29
+ skip_function_tracing,
30
+ skip_network_tracing,
31
+ capture_function_spans,
32
+ )
33
+ from .package_metadata import __version__
34
+ from .transmit_exception_to_sailfish import transmit_exception_to_sailfish
35
+ from .unified_interceptor import setup_interceptors, reinitialize_after_fork
36
+
37
+ __all__ = [
38
+ "setup_interceptors",
39
+ "transmit_exception_to_sailfish",
40
+ "skip_tracing", # Backward compatibility
41
+ "skip_function_tracing",
42
+ "skip_network_tracing",
43
+ "capture_function_spans",
44
+ "reinitialize_after_fork",
45
+ "__version__",
46
+ ]
@@ -0,0 +1,73 @@
1
+ """
2
+ Auto-detection and configuration of LD_PRELOAD mode.
3
+
4
+ This module automatically detects if libsfnettee.so is available in the package
5
+ and sets the LD_PRELOAD environment variable if it's not already set. This enables
6
+ LD_PRELOAD mode automatically without requiring manual configuration.
7
+ """
8
+
9
+ import os
10
+ import sys
11
+
12
+
13
+ def _auto_enable_ld_preload() -> bool:
14
+ """
15
+ Check if LD_PRELOAD mode is active.
16
+
17
+ This function checks if the C library (libsfnettee.so) is loaded via LD_PRELOAD.
18
+ It does NOT attempt to automatically enable it - users must set LD_PRELOAD themselves.
19
+
20
+ To enable high-performance C library mode, set LD_PRELOAD before starting Python:
21
+ export LD_PRELOAD=/path/to/site-packages/sf_veritas/libsfnettee.so
22
+ python your_app.py
23
+
24
+ Or in your Dockerfile entrypoint:
25
+ ENV LD_PRELOAD=/usr/local/lib/python3.12/site-packages/sf_veritas/libsfnettee.so
26
+
27
+ Returns:
28
+ True if LD_PRELOAD mode is active (C library loaded)
29
+ False if not active (will use Python patches)
30
+ """
31
+ # Check if LD_PRELOAD is already set with libsfnettee.so
32
+ current_ld_preload = os.getenv("LD_PRELOAD", "")
33
+ if "libsfnettee.so" in current_ld_preload or "_sfteepreload" in current_ld_preload:
34
+ if os.getenv("SF_DEBUG", "false").lower() == "true":
35
+ sys.stderr.write(f"[sf_veritas] ✓ C library active via LD_PRELOAD: {current_ld_preload}\n")
36
+ sys.stderr.flush()
37
+ return True
38
+
39
+ # Not active - check if library exists and print helpful message
40
+ try:
41
+ package_dir = os.path.dirname(os.path.abspath(__file__))
42
+ libsfnettee_path = os.path.join(package_dir, "libsfnettee.so")
43
+
44
+ if os.path.isfile(libsfnettee_path):
45
+ if os.getenv("SF_DEBUG", "false").lower() == "true":
46
+ sys.stderr.write(f"[sf_veritas] C library available but not loaded (using Python patches)\n")
47
+ sys.stderr.write(f"[sf_veritas] For better performance, set LD_PRELOAD before starting Python:\n")
48
+ sys.stderr.write(f"[sf_veritas] export LD_PRELOAD={libsfnettee_path}\n")
49
+ sys.stderr.flush()
50
+ else:
51
+ if os.getenv("SF_DEBUG", "false").lower() == "true":
52
+ sys.stderr.write(f"[sf_veritas] C library not found at {libsfnettee_path}\n")
53
+ sys.stderr.write(f"[sf_veritas] Using Python patches (slower but works)\n")
54
+ sys.stderr.flush()
55
+ except Exception:
56
+ pass
57
+
58
+ return False
59
+
60
+
61
+ # Check if LD_PRELOAD mode is active
62
+ _LD_PRELOAD_ACTIVE = _auto_enable_ld_preload()
63
+
64
+ # Enable Python SSL mode when LD_PRELOAD is active (default ON)
65
+ # This tells the C library to disable its SSL hooks (Python handles HTTPS, C handles HTTP)
66
+ if _LD_PRELOAD_ACTIVE:
67
+ # Default to '1' (C SSL hooks disabled) unless explicitly overridden
68
+ if 'SF_SSL_PYTHON_MODE' not in os.environ:
69
+ os.environ['SF_SSL_PYTHON_MODE'] = '1'
70
+
71
+ if os.getenv("SF_DEBUG", "false").lower() == "true":
72
+ sys.stderr.write("[sf_veritas] ✓ Python SSL mode enabled (C handles HTTP, Python handles HTTPS)\n")
73
+ sys.stderr.flush()
sf_veritas/_sfconfig.c ADDED
@@ -0,0 +1,162 @@
1
+ // Python C extension module to configure the C library
2
+ // This provides a clean, secure interface using dlsym to find runtime symbols
3
+ #define PY_SSIZE_T_CLEAN
4
+ #include <Python.h>
5
+ #include <dlfcn.h>
6
+ #include <stdlib.h>
7
+ #include <stdio.h>
8
+
9
+ // Function pointers for the C library functions
10
+ typedef void (*sf_set_sink_url_t)(const char *url);
11
+ typedef void (*sf_set_api_key_t)(const char *key);
12
+ typedef void (*sf_set_service_uuid_t)(const char *uuid);
13
+ typedef void (*sf_initialize_t)(void);
14
+
15
+ static sf_set_sink_url_t sf_set_sink_url_ptr = NULL;
16
+ static sf_set_api_key_t sf_set_api_key_ptr = NULL;
17
+ static sf_set_service_uuid_t sf_set_service_uuid_ptr = NULL;
18
+ static sf_initialize_t sf_initialize_ptr = NULL;
19
+ static int symbols_resolved = 0;
20
+
21
+ // Lazy symbol resolution - called on first use of any function
22
+ static void ensure_symbols_resolved(void) {
23
+ if (symbols_resolved) {
24
+ return; // Already resolved
25
+ }
26
+
27
+ // Clear any previous dlsym errors
28
+ dlerror();
29
+
30
+ // Use RTLD_DEFAULT to search all loaded libraries (including LD_PRELOAD)
31
+ sf_set_sink_url_ptr = (sf_set_sink_url_t)dlsym(RTLD_DEFAULT, "sf_set_sink_url");
32
+ const char *err1 = dlerror();
33
+
34
+ sf_set_api_key_ptr = (sf_set_api_key_t)dlsym(RTLD_DEFAULT, "sf_set_api_key");
35
+ const char *err2 = dlerror();
36
+
37
+ sf_set_service_uuid_ptr = (sf_set_service_uuid_t)dlsym(RTLD_DEFAULT, "sf_set_service_uuid");
38
+ const char *err3 = dlerror();
39
+
40
+ sf_initialize_ptr = (sf_initialize_t)dlsym(RTLD_DEFAULT, "sf_initialize");
41
+ const char *err4 = dlerror();
42
+
43
+ // Debug output to help diagnose symbol resolution issues
44
+ if (!sf_set_sink_url_ptr || !sf_set_api_key_ptr || !sf_set_service_uuid_ptr || !sf_initialize_ptr) {
45
+ const char *ld_preload = getenv("LD_PRELOAD");
46
+ fprintf(stderr, "[_sfconfig] Symbol resolution FAILED!\n");
47
+ fprintf(stderr, " LD_PRELOAD=%s\n", ld_preload ? ld_preload : "(not set)");
48
+ fprintf(stderr, " sf_set_sink_url: %s (%s)\n",
49
+ sf_set_sink_url_ptr ? "OK" : "FAILED", err1 ? err1 : "no error");
50
+ fprintf(stderr, " sf_set_api_key: %s (%s)\n",
51
+ sf_set_api_key_ptr ? "OK" : "FAILED", err2 ? err2 : "no error");
52
+ fprintf(stderr, " sf_set_service_uuid: %s (%s)\n",
53
+ sf_set_service_uuid_ptr ? "OK" : "FAILED", err3 ? err3 : "no error");
54
+ fprintf(stderr, " sf_initialize: %s (%s)\n",
55
+ sf_initialize_ptr ? "OK" : "FAILED", err4 ? err4 : "no error");
56
+ fflush(stderr);
57
+ }
58
+
59
+ symbols_resolved = 1;
60
+ }
61
+
62
+ // Python wrapper: sf_set_sink_url(url: str) -> None
63
+ static PyObject* py_sf_set_sink_url(PyObject* self, PyObject* args) {
64
+ const char *url;
65
+ if (!PyArg_ParseTuple(args, "s", &url)) {
66
+ return NULL;
67
+ }
68
+
69
+ // Lazy symbol resolution on first call
70
+ ensure_symbols_resolved();
71
+
72
+ if (!sf_set_sink_url_ptr) {
73
+ PyErr_SetString(PyExc_RuntimeError, "C library not loaded (LD_PRELOAD not active?)");
74
+ return NULL;
75
+ }
76
+ sf_set_sink_url_ptr(url);
77
+ Py_RETURN_NONE;
78
+ }
79
+
80
+ // Python wrapper: sf_set_api_key(key: str) -> None
81
+ static PyObject* py_sf_set_api_key(PyObject* self, PyObject* args) {
82
+ const char *key;
83
+ if (!PyArg_ParseTuple(args, "s", &key)) {
84
+ return NULL;
85
+ }
86
+
87
+ // Lazy symbol resolution on first call
88
+ ensure_symbols_resolved();
89
+
90
+ if (!sf_set_api_key_ptr) {
91
+ PyErr_SetString(PyExc_RuntimeError, "C library not loaded (LD_PRELOAD not active?)");
92
+ return NULL;
93
+ }
94
+ sf_set_api_key_ptr(key);
95
+ Py_RETURN_NONE;
96
+ }
97
+
98
+ // Python wrapper: sf_set_service_uuid(uuid: str) -> None
99
+ static PyObject* py_sf_set_service_uuid(PyObject* self, PyObject* args) {
100
+ const char *uuid;
101
+ if (!PyArg_ParseTuple(args, "s", &uuid)) {
102
+ return NULL;
103
+ }
104
+
105
+ // Lazy symbol resolution on first call
106
+ ensure_symbols_resolved();
107
+
108
+ if (!sf_set_service_uuid_ptr) {
109
+ PyErr_SetString(PyExc_RuntimeError, "C library not loaded (LD_PRELOAD not active?)");
110
+ return NULL;
111
+ }
112
+ sf_set_service_uuid_ptr(uuid);
113
+ Py_RETURN_NONE;
114
+ }
115
+
116
+ // Python wrapper: sf_initialize() -> None
117
+ static PyObject* py_sf_initialize(PyObject* self, PyObject* args) {
118
+ // Lazy symbol resolution on first call
119
+ ensure_symbols_resolved();
120
+
121
+ if (!sf_initialize_ptr) {
122
+ PyErr_SetString(PyExc_RuntimeError, "C library not loaded (LD_PRELOAD not active?)");
123
+ return NULL;
124
+ }
125
+ sf_initialize_ptr();
126
+ Py_RETURN_NONE;
127
+ }
128
+
129
+ // Method definitions
130
+ static PyMethodDef SfConfigMethods[] = {
131
+ {"set_sink_url", py_sf_set_sink_url, METH_VARARGS,
132
+ "Set the GraphQL endpoint URL for the C library"},
133
+ {"set_api_key", py_sf_set_api_key, METH_VARARGS,
134
+ "Set the API key for the C library"},
135
+ {"set_service_uuid", py_sf_set_service_uuid, METH_VARARGS,
136
+ "Set the service UUID for the C library"},
137
+ {"initialize", py_sf_initialize, METH_NOARGS,
138
+ "Initialize and activate the C library (sets SF_INITIALIZED=1)"},
139
+ {NULL, NULL, 0, NULL}
140
+ };
141
+
142
+ // Module definition
143
+ static struct PyModuleDef sfconfig_module = {
144
+ PyModuleDef_HEAD_INIT,
145
+ "_sfconfig",
146
+ "Configuration interface for the Sailfish C library",
147
+ -1,
148
+ SfConfigMethods
149
+ };
150
+
151
+ // Module initialization
152
+ PyMODINIT_FUNC PyInit__sfconfig(void) {
153
+ PyObject *module = PyModule_Create(&sfconfig_module);
154
+ if (module == NULL) {
155
+ return NULL;
156
+ }
157
+
158
+ // Symbol resolution is done lazily on first function call
159
+ // This ensures the C library is fully loaded before we try to find symbols
160
+
161
+ return module;
162
+ }
@@ -0,0 +1,267 @@
1
+ // C-level crash handler that prints registers and stack addresses
2
+ // This catches segfaults that happen in C code before Python can handle them
3
+
4
+ // Ensure we have write() and fsync() available
5
+ #ifndef _POSIX_C_SOURCE
6
+ #define _POSIX_C_SOURCE 200809L
7
+ #endif
8
+
9
+ // macOS requires _XOPEN_SOURCE for ucontext
10
+ #ifdef __APPLE__
11
+ #define _XOPEN_SOURCE 600
12
+ #endif
13
+
14
+ #include <Python.h>
15
+ #include <signal.h>
16
+ #include <stdio.h>
17
+ #include <stdlib.h>
18
+ #include <string.h>
19
+ #include <unistd.h>
20
+ #include <execinfo.h>
21
+ #include <sys/types.h>
22
+
23
+ // Platform-specific includes for register access
24
+ #if defined(__linux__)
25
+ #include <ucontext.h>
26
+ #include <sys/syscall.h>
27
+ #elif defined(__APPLE__)
28
+ #include <sys/ucontext.h>
29
+ #endif
30
+
31
+ // Get thread ID
32
+ static long gettid(void) {
33
+ #ifdef SYS_gettid
34
+ return (long)syscall(SYS_gettid);
35
+ #else
36
+ return (long)getpid();
37
+ #endif
38
+ }
39
+
40
+ // Signal handler that prints everything
41
+ static void crash_handler(int sig, siginfo_t *si, void *ctx) {
42
+ ucontext_t *uc = (ucontext_t *)ctx;
43
+ void *backtrace_buffer[100];
44
+ int backtrace_size;
45
+ char **bt_symbols;
46
+ int i;
47
+
48
+ // Make stderr unbuffered to ensure output appears
49
+ setvbuf(stderr, NULL, _IONBF, 0);
50
+
51
+ // Print to stderr directly (unbuffered)
52
+ const char *sig_name =
53
+ sig == SIGSEGV ? "SIGSEGV" :
54
+ sig == SIGABRT ? "SIGABRT" :
55
+ sig == SIGBUS ? "SIGBUS" :
56
+ sig == SIGFPE ? "SIGFPE" :
57
+ sig == SIGILL ? "SIGILL" : "UNKNOWN";
58
+
59
+ // Write directly to fd 2 (stderr) to bypass buffering entirely
60
+ const char *header = "\n\n=== CRASH HANDLER TRIGGERED ===\n";
61
+ write(2, header, strlen(header));
62
+
63
+ fprintf(stderr, "\n");
64
+ fprintf(stderr, "================================================================================\n");
65
+ fprintf(stderr, "CRASH DETECTED: Signal %d (%s)\n", sig, sig_name);
66
+ fprintf(stderr, "================================================================================\n");
67
+ fprintf(stderr, "Process ID: %d\n", getpid());
68
+ fprintf(stderr, "Thread ID: %ld\n", gettid());
69
+ fprintf(stderr, "Signal code: %d\n", si->si_code);
70
+ fprintf(stderr, "Fault addr: %p\n", si->si_addr);
71
+ fprintf(stderr, "\n");
72
+
73
+ // Print registers (platform-specific)
74
+ #if defined(__linux__) && defined(__x86_64__)
75
+ fprintf(stderr, "--- x86_64 Registers (Linux) ---\n");
76
+ fprintf(stderr, "RIP: 0x%016llx RSP: 0x%016llx RBP: 0x%016llx\n",
77
+ (unsigned long long)uc->uc_mcontext.gregs[REG_RIP],
78
+ (unsigned long long)uc->uc_mcontext.gregs[REG_RSP],
79
+ (unsigned long long)uc->uc_mcontext.gregs[REG_RBP]);
80
+ fprintf(stderr, "RAX: 0x%016llx RBX: 0x%016llx RCX: 0x%016llx\n",
81
+ (unsigned long long)uc->uc_mcontext.gregs[REG_RAX],
82
+ (unsigned long long)uc->uc_mcontext.gregs[REG_RBX],
83
+ (unsigned long long)uc->uc_mcontext.gregs[REG_RCX]);
84
+ fprintf(stderr, "RDX: 0x%016llx RSI: 0x%016llx RDI: 0x%016llx\n",
85
+ (unsigned long long)uc->uc_mcontext.gregs[REG_RDX],
86
+ (unsigned long long)uc->uc_mcontext.gregs[REG_RSI],
87
+ (unsigned long long)uc->uc_mcontext.gregs[REG_RDI]);
88
+ fprintf(stderr, "R8: 0x%016llx R9: 0x%016llx R10: 0x%016llx\n",
89
+ (unsigned long long)uc->uc_mcontext.gregs[REG_R8],
90
+ (unsigned long long)uc->uc_mcontext.gregs[REG_R9],
91
+ (unsigned long long)uc->uc_mcontext.gregs[REG_R10]);
92
+ fprintf(stderr, "R11: 0x%016llx R12: 0x%016llx R13: 0x%016llx\n",
93
+ (unsigned long long)uc->uc_mcontext.gregs[REG_R11],
94
+ (unsigned long long)uc->uc_mcontext.gregs[REG_R12],
95
+ (unsigned long long)uc->uc_mcontext.gregs[REG_R13]);
96
+ fprintf(stderr, "R14: 0x%016llx R15: 0x%016llx\n",
97
+ (unsigned long long)uc->uc_mcontext.gregs[REG_R14],
98
+ (unsigned long long)uc->uc_mcontext.gregs[REG_R15]);
99
+ #elif defined(__linux__) && defined(__aarch64__)
100
+ fprintf(stderr, "--- ARM64 Registers (Linux) ---\n");
101
+ fprintf(stderr, "PC: 0x%016llx SP: 0x%016llx FP: 0x%016llx\n",
102
+ (unsigned long long)uc->uc_mcontext.pc,
103
+ (unsigned long long)uc->uc_mcontext.sp,
104
+ (unsigned long long)uc->uc_mcontext.regs[29]);
105
+ for (i = 0; i < 29; i += 3) {
106
+ fprintf(stderr, "X%-2d: 0x%016llx ", i, (unsigned long long)uc->uc_mcontext.regs[i]);
107
+ if (i + 1 < 29)
108
+ fprintf(stderr, "X%-2d: 0x%016llx ", i+1, (unsigned long long)uc->uc_mcontext.regs[i+1]);
109
+ if (i + 2 < 29)
110
+ fprintf(stderr, "X%-2d: 0x%016llx", i+2, (unsigned long long)uc->uc_mcontext.regs[i+2]);
111
+ fprintf(stderr, "\n");
112
+ }
113
+ #elif defined(__APPLE__) && defined(__x86_64__)
114
+ fprintf(stderr, "--- x86_64 Registers (macOS) ---\n");
115
+ fprintf(stderr, "RIP: 0x%016llx RSP: 0x%016llx RBP: 0x%016llx\n",
116
+ (unsigned long long)uc->uc_mcontext->__ss.__rip,
117
+ (unsigned long long)uc->uc_mcontext->__ss.__rsp,
118
+ (unsigned long long)uc->uc_mcontext->__ss.__rbp);
119
+ fprintf(stderr, "RAX: 0x%016llx RBX: 0x%016llx RCX: 0x%016llx\n",
120
+ (unsigned long long)uc->uc_mcontext->__ss.__rax,
121
+ (unsigned long long)uc->uc_mcontext->__ss.__rbx,
122
+ (unsigned long long)uc->uc_mcontext->__ss.__rcx);
123
+ fprintf(stderr, "RDX: 0x%016llx RSI: 0x%016llx RDI: 0x%016llx\n",
124
+ (unsigned long long)uc->uc_mcontext->__ss.__rdx,
125
+ (unsigned long long)uc->uc_mcontext->__ss.__rsi,
126
+ (unsigned long long)uc->uc_mcontext->__ss.__rdi);
127
+ fprintf(stderr, "R8: 0x%016llx R9: 0x%016llx R10: 0x%016llx\n",
128
+ (unsigned long long)uc->uc_mcontext->__ss.__r8,
129
+ (unsigned long long)uc->uc_mcontext->__ss.__r9,
130
+ (unsigned long long)uc->uc_mcontext->__ss.__r10);
131
+ fprintf(stderr, "R11: 0x%016llx R12: 0x%016llx R13: 0x%016llx\n",
132
+ (unsigned long long)uc->uc_mcontext->__ss.__r11,
133
+ (unsigned long long)uc->uc_mcontext->__ss.__r12,
134
+ (unsigned long long)uc->uc_mcontext->__ss.__r13);
135
+ fprintf(stderr, "R14: 0x%016llx R15: 0x%016llx\n",
136
+ (unsigned long long)uc->uc_mcontext->__ss.__r14,
137
+ (unsigned long long)uc->uc_mcontext->__ss.__r15);
138
+ #elif defined(__APPLE__) && defined(__aarch64__)
139
+ fprintf(stderr, "--- ARM64 Registers (macOS) ---\n");
140
+ fprintf(stderr, "PC: 0x%016llx SP: 0x%016llx FP: 0x%016llx\n",
141
+ (unsigned long long)__darwin_arm_thread_state64_get_pc(uc->uc_mcontext->__ss),
142
+ (unsigned long long)__darwin_arm_thread_state64_get_sp(uc->uc_mcontext->__ss),
143
+ (unsigned long long)__darwin_arm_thread_state64_get_fp(uc->uc_mcontext->__ss));
144
+ for (i = 0; i < 29; i += 3) {
145
+ fprintf(stderr, "X%-2d: 0x%016llx ", i, (unsigned long long)uc->uc_mcontext->__ss.__x[i]);
146
+ if (i + 1 < 29)
147
+ fprintf(stderr, "X%-2d: 0x%016llx ", i+1, (unsigned long long)uc->uc_mcontext->__ss.__x[i+1]);
148
+ if (i + 2 < 29)
149
+ fprintf(stderr, "X%-2d: 0x%016llx", i+2, (unsigned long long)uc->uc_mcontext->__ss.__x[i+2]);
150
+ fprintf(stderr, "\n");
151
+ }
152
+ #else
153
+ fprintf(stderr, "--- Registers (architecture not recognized) ---\n");
154
+ (void)uc; // Suppress unused variable warning
155
+ #endif
156
+ fprintf(stderr, "\n");
157
+
158
+ // Print native backtrace
159
+ fprintf(stderr, "--- Native Stack Trace (C level) ---\n");
160
+ backtrace_size = backtrace(backtrace_buffer, 100);
161
+ bt_symbols = backtrace_symbols(backtrace_buffer, backtrace_size);
162
+
163
+ if (bt_symbols) {
164
+ for (i = 0; i < backtrace_size; i++) {
165
+ fprintf(stderr, "[%2d] %s\n", i, bt_symbols[i]);
166
+ }
167
+ free(bt_symbols);
168
+ } else {
169
+ fprintf(stderr, "Failed to get backtrace symbols\n");
170
+ }
171
+ fprintf(stderr, "\n");
172
+
173
+ // Print raw stack memory
174
+ fprintf(stderr, "--- Stack Memory (32 bytes from fault) ---\n");
175
+ unsigned char *fault_ptr = (unsigned char *)si->si_addr;
176
+ fprintf(stderr, "Fault address: %p\n", fault_ptr);
177
+
178
+ // Try to read memory around fault address (may fail)
179
+ // Print stack pointer area instead
180
+ #if defined(__linux__) && defined(__x86_64__)
181
+ unsigned long long *sp = (unsigned long long *)uc->uc_mcontext.gregs[REG_RSP];
182
+ #elif defined(__linux__) && defined(__aarch64__)
183
+ unsigned long long *sp = (unsigned long long *)uc->uc_mcontext.sp;
184
+ #elif defined(__APPLE__) && defined(__x86_64__)
185
+ unsigned long long *sp = (unsigned long long *)uc->uc_mcontext->__ss.__rsp;
186
+ #elif defined(__APPLE__) && defined(__aarch64__)
187
+ unsigned long long *sp = (unsigned long long *)__darwin_arm_thread_state64_get_sp(uc->uc_mcontext->__ss);
188
+ #else
189
+ unsigned long long *sp = NULL;
190
+ #endif
191
+
192
+ if (sp) {
193
+ fprintf(stderr, "Stack at RSP/SP (%p):\n", sp);
194
+ for (i = 0; i < 4; i++) {
195
+ fprintf(stderr, " [SP+%2d] 0x%016llx\n", i*8, (unsigned long long)sp[i]);
196
+ }
197
+ }
198
+ fprintf(stderr, "\n");
199
+
200
+ fprintf(stderr, "================================================================================\n");
201
+ fprintf(stderr, "Use addr2line to decode addresses:\n");
202
+ fprintf(stderr, " addr2line -e /path/to/_sffuncspan.*.so <address>\n");
203
+ fprintf(stderr, "================================================================================\n");
204
+ fprintf(stderr, "\n");
205
+
206
+ fflush(stderr);
207
+ fsync(2); // Force write to disk
208
+
209
+ const char *footer = "\n=== END CRASH HANDLER ===\n\n";
210
+ write(2, footer, strlen(footer));
211
+
212
+ // Re-raise signal with default handler (generates core dump)
213
+ signal(sig, SIG_DFL);
214
+ raise(sig);
215
+ }
216
+
217
+ // Install crash handler
218
+ static PyObject *install_crash_handler(PyObject *self, PyObject *args) {
219
+ struct sigaction sa;
220
+ memset(&sa, 0, sizeof(sa));
221
+ sa.sa_sigaction = crash_handler;
222
+ sa.sa_flags = SA_SIGINFO | SA_RESTART;
223
+ sigemptyset(&sa.sa_mask);
224
+
225
+ if (sigaction(SIGSEGV, &sa, NULL) == -1) {
226
+ PyErr_SetString(PyExc_RuntimeError, "Failed to install SIGSEGV handler");
227
+ return NULL;
228
+ }
229
+ if (sigaction(SIGABRT, &sa, NULL) == -1) {
230
+ PyErr_SetString(PyExc_RuntimeError, "Failed to install SIGABRT handler");
231
+ return NULL;
232
+ }
233
+ if (sigaction(SIGBUS, &sa, NULL) == -1) {
234
+ PyErr_SetString(PyExc_RuntimeError, "Failed to install SIGBUS handler");
235
+ return NULL;
236
+ }
237
+ if (sigaction(SIGFPE, &sa, NULL) == -1) {
238
+ PyErr_SetString(PyExc_RuntimeError, "Failed to install SIGFPE handler");
239
+ return NULL;
240
+ }
241
+ if (sigaction(SIGILL, &sa, NULL) == -1) {
242
+ PyErr_SetString(PyExc_RuntimeError, "Failed to install SIGILL handler");
243
+ return NULL;
244
+ }
245
+
246
+ fprintf(stderr, "[_sfcrashhandler] C-level crash handlers installed (PID=%d)\n", getpid());
247
+ fflush(stderr);
248
+
249
+ Py_RETURN_NONE;
250
+ }
251
+
252
+ static PyMethodDef crash_handler_methods[] = {
253
+ {"install", install_crash_handler, METH_NOARGS, "Install C-level crash handler"},
254
+ {NULL, NULL, 0, NULL}
255
+ };
256
+
257
+ static struct PyModuleDef crash_handler_module = {
258
+ PyModuleDef_HEAD_INIT,
259
+ "_sfcrashhandler",
260
+ "C-level crash handler for debugging segfaults",
261
+ -1,
262
+ crash_handler_methods
263
+ };
264
+
265
+ PyMODINIT_FUNC PyInit__sfcrashhandler(void) {
266
+ return PyModule_Create(&crash_handler_module);
267
+ }