Skip to content

[ci] Don't run python setup.py test in CI since we now use Tox#41

Merged
elijahandrews merged 1 commit intomasterfrom
elijah/only-tox
Aug 4, 2016
Merged

[ci] Don't run python setup.py test in CI since we now use Tox#41
elijahandrews merged 1 commit intomasterfrom
elijah/only-tox

Conversation

@elijahandrews
Copy link
Copy Markdown
Contributor

Since we started running CI tests using tox, we've also been running python setup.py test as part of the test step. It seems that if no test step is specified in circle.yml, it will run python setup.py test by default.

@clutchski

@clutchski
Copy link
Copy Markdown
Contributor

+1

@elijahandrews elijahandrews merged commit 6a73488 into master Aug 4, 2016
@elijahandrews elijahandrews deleted the elijah/only-tox branch August 4, 2016 16:17
gh-worker-dd-mergequeue-cf854d Bot pushed a commit that referenced this pull request Apr 8, 2026
)

## Description

https://datadoghq.atlassian.net/browse/PROF-13112

This fixes a rare segmentation fault that could occur when a profiled application forks.

#### Stack trace

```
#0 0x0000ffffaf48f6d0 free
#1 0x0000ffffae4367e4 core::ptr::drop_in_place<indexmap::set::IndexSet<libdd_profiling::internal::stack_trace::StackTrace,core::hash::BuildHasherDefault<rustc_hash::FxHasher>>>::hbe422e96ad1ad3f9
#2 0x0000ffffae436478 core::ptr::drop_in_place<libdd_profiling::internal::profile::Profile>::h4a6aee0579496bfb
#3 0x0000ffffae43e244 ddog_prof_Profile_drop
#4 0x0000ffff9fe5a724 Datadog::Profile::postfork_child
#5 0x0000ffffaf4b8804 __libc_fork
#6 0x0000ffffaf6bf058 os_fork_impl (/usr/src/python/./Modules/posixmodule.c:7757)
#7 0x0000ffffaf6bf058 os_fork (/usr/src/python/./Modules/clinic/posixmodule.c.h:3986)
#8 0x0000ffffaf725d2c cfunction_vectorcall_NOARGS (/usr/src/python/Objects/methodobject.c:481:24)
#9 0x0000ffffaf72f420 PyCFunction_Call (/usr/src/python/Objects/call.c:387:12)
#10 0x0000ffffaf72f420 _PyEval_EvalFrameDefault (/usr/src/python/Python/bytecodes.c:3263:26)
#11 0x0000ffffaf750430 _PyObject_VectorcallTstate (/usr/src/python/./Include/internal/pycore_call.h:92:11)
#12 0x0000ffffaf750430 object_vacall (/usr/src/python/Objects/call.c:850:14)
#13 0x0000ffffaf7cf1b8 PyObject_CallFunctionObjArgs (/usr/src/python/Objects/call.c:957:14)
#14 0x0000ffffae18453c WraptFunctionWrapperBase_call (/project/src/wrapt/_wrappers.c:2455:14)
#15 0x0000ffffaf7225c4 _PyObject_MakeTpCall (/usr/src/python/Objects/call.c:240:18)
#16 0x0000ffffaf72db54 _PyEval_EvalFrameDefault (/usr/src/python/Python/bytecodes.c:2715:19)
#17 0x0000ffffaf725b60 _PyFunction_Vectorcall (/usr/src/python/Objects/call.c:419:16)
#18 0x0000ffffaf725b60 _PyObject_FastCallDictTstate (/usr/src/python/Objects/call.c:133:15)
#19 0x0000ffffaf75b928 _PyObject_Call_Prepend (/usr/src/python/Objects/call.c:508:24)
#20 0x0000ffffaf75b928 slot_tp_init (/usr/src/python/Objects/typeobject.c:9026:15)
#21 0x0000ffffaf722878 type_call (/usr/src/python/Objects/typeobject.c:1679:19)
#22 0x0000ffffaf7225c4 _PyObject_MakeTpCall (/usr/src/python/Objects/call.c:240:18)
#23 0x0000ffffaf72db54 _PyEval_EvalFrameDefault (/usr/src/python/Python/bytecodes.c:2715:19)
#24 0x0000ffffaf775c74 _PyFunction_Vectorcall (/usr/src/python/Objects/call.c:419:16)
#25 0x0000ffffaf775c74 _PyObject_VectorcallTstate (/usr/src/python/./Include/internal/pycore_call.h:92:11)
#26 0x0000ffffaf775c74 method_vectorcall (/usr/src/python/Objects/classobject.c:91:18)
#27 0x0000ffffaf72f420 PyCFunction_Call (/usr/src/python/Objects/call.c:387:12)
#28 0x0000ffffaf72f420 _PyEval_EvalFrameDefault (/usr/src/python/Python/bytecodes.c:3263:26)
#29 0x0000ffffaf7745a4 _PyEval_EvalFrame (/usr/src/python/./Include/internal/pycore_ceval.h:89:16)
#30 0x0000ffffaf7745a4 gen_send_ex2 (/usr/src/python/Objects/genobject.c:230:14)
#31 0x0000ffffaf78cf48 gen_iternext (/usr/src/python/Objects/genobject.c:603:9)
#32 0x0000ffffaf78cf48 builtin_next_impl (/usr/src/python/Python/bltinmodule.c:1510)
#33 0x0000ffffaf78cf48 builtin_next (/usr/src/python/Python/clinic/bltinmodule.c.h:730)
#34 0x0000ffffaf730b30 _PyEval_EvalFrameDefault (/usr/src/python/Python/bytecodes.c:2938:20)
#35 0x0000ffffaf775d28 _PyFunction_Vectorcall (/usr/src/python/Objects/call.c:419:16)
#36 0x0000ffffaf775d28 _PyObject_VectorcallTstate (/usr/src/python/./Include/internal/pycore_call.h:92:11)
#37 0x0000ffffaf775d28 method_vectorcall (/usr/src/python/Objects/classobject.c:61:18)
#38 0x0000ffffaf75f614 _PyVectorcall_Call (/usr/src/python/Objects/call.c:283:24)
#39 0x0000ffffaf72f420 PyCFunction_Call (/usr/src/python/Objects/call.c:387:12)
#40 0x0000ffffaf72f420 _PyEval_EvalFrameDefault (/usr/src/python/Python/bytecodes.c:3263:26)
#41 0x0000ffffaf775d28 _PyFunction_Vectorcall (/usr/src/python/Objects/call.c:419:16)
#42 0x0000ffffaf775d28 _PyObject_VectorcallTstate (/usr/src/python/./Include/internal/pycore_call.h:92:11)
#43 0x0000ffffaf775d28 method_vectorcall (/usr/src/python/Objects/classobject.c:61:18)
#44 0x0000ffffaf75f614 _PyVectorcall_Call (/usr/src/python/Objects/call.c:283:24)
#45 0x0000ffffaf72f420 PyCFunction_Call (/usr/src/python/Objects/call.c:387:12)
#46 0x0000ffffaf72f420 _PyEval_EvalFrameDefault (/usr/src/python/Python/bytecodes.c:3263:26)
#47 0x0000ffffaf725bd8 _PyObject_FastCallDictTstate (/usr/src/python/Objects/call.c:144:15)
#48 0x0000ffffaf75bc30 _PyObject_Call_Prepend (/usr/src/python/Objects/call.c:508:24)
#49 0x0000ffffaf831e40 slot_tp_call (/usr/src/python/Objects/typeobject.c:8782)
#50 0x0000ffffaf722678 _PyObject_MakeTpCall (/usr/src/python/Objects/call.c:240:18)
#51 0x0000ffffaf72db54 _PyEval_EvalFrameDefault (/usr/src/python/Python/bytecodes.c:2715:19)
#52 0x0000ffffaf7cb914 PyEval_EvalCode (/usr/src/python/Python/ceval.c:578:21)
#53 0x0000ffffaf7f6af8 builtin_exec_impl (/usr/src/python/Python/bltinmodule.c:1096)
#54 0x0000ffffaf7f6af8 builtin_exec (/usr/src/python/Python/clinic/bltinmodule.c.h:586)
#55 0x0000ffffaf74844c cfunction_vectorcall_FASTCALL_KEYWORDS (/usr/src/python/Objects/methodobject.c:438:24)
#56 0x0000ffffaf747804 _PyObject_VectorcallTstate (/usr/src/python/./Include/internal/pycore_call.h:92:11)
#57 0x0000ffffaf747804 PyObject_Vectorcall (/usr/src/python/Objects/call.c:325:12)
#58 0x0000ffffaf72db54 _PyEval_EvalFrameDefault (/usr/src/python/Python/bytecodes.c:2715:19)
#59 0x0000ffffaf811728 pymain_run_module (/usr/src/python/Modules/main.c:300)
#60 0x0000ffffaf810a78 pymain_run_python (/usr/src/python/Modules/main.c:627)
#61 0x0000ffffaf810a78 Py_RunMain (/usr/src/python/Modules/main.c:713)
#62 0x0000ffffaf7b321c Py_BytesMain (/usr/src/python/Modules/main.c:767:12)
#63 0x0000ffffaf427818 __libc_start_main
#64 0x0000aaaae4960870 _start
```

#### Root cause

The root cause of this crash seems to be unfortunate timing on fork. What happened was that, due to ordering of fork handlers, `stack`'s post-fork hook would run _before_ `dd_wrapper`'s. On multi-core systems where we got unlucky, because `stack`'s post-fork hook would restart the Sampling Thread, this meant the Sampling Thread could start before `dd_wrapper`'s post-fork hook had completed (or even before it had started).  
As a result, `dd_wrapper` would (try to) reset the `Profile` object that the Sampling Thread was writing to through the `Sample` APIs, resulting in a race and all kinds of fun memory issues, such as this crash.  
Note that the other way around could also happen, where the Sampling Thread could try to write to the `Profile` object that had already been dropped/freed by `dd_wrapper`. 

#### Are other Profilers impacted?

AFAIK, other Profilers shouldn't be impacted as they run in the Main Thread, so I think the risk that they may be writing to the Profile before it's ready post-fork is effectively inexistent.

#### Is registering this _at library load time_ OK?

As far as I can tell, there is no risk in registering that post-fork hook at library load time, instead of when the Stack Profiler is started. What `stack_atfork_child` is calling `stack_postfork_cleanup`, which we already did at library load time [meaning it's safe to do even when the Profiler doesn't run], then calling `Sampler::restart_after_fork`, which only restarts the Profiler if it was running pre-fork (which in an app that does not use the Profiler is a no-op).

Co-authored-by: thomas.kowalski <thomas.kowalski@datadoghq.com>
gh-worker-dd-mergequeue-cf854d Bot pushed a commit that referenced this pull request Apr 9, 2026
## What is this PR?

This PR fixes a crash in `ddtrace` discovered by Crash Tracking where we crash in garbage collection. While this definitely does sound like a Python bug and not a `ddtrace` one, we need to fix this for existing versions of Python and in the meantime until Python fixes it itself. 

The crash is in `PyObject_GC_UnTrack`, called from the dealloc path of a HAMT node that `PyContextVar_Set` is trying to free via `Py_DECREF`.  If that HAMT node's memory is already unmapped, the `PyObject_GC_UnTrack` write faults.

```
Error UnixSignal: Process terminated with SEGV_MAPERR (SIGSEGV)
#0  0x00007fc92c3dd27f PyObject_GC_UnTrack
#1  0x00007fc92c4e1448 PyContextVar_Set
#2  0x00007fc92c3f3546 _PyEval_EvalFrameDefault
#3  0x00007fc92c3fbce7 PyObject_Vectorcall
#4  0x00007fc92c3f039b _PyEval_EvalFrameDefault
#5  0x00007fc92c3f2f38 _PyEval_EvalFrameDefault
#6  0x00007fc92c3f2f38 _PyEval_EvalFrameDefault
#7  0x00007fc92c3f2f38 _PyEval_EvalFrameDefault
#8  0x00007fc92c3f2f38 _PyEval_EvalFrameDefault
#9  0x00007fc92c44e25f PyIter_Send
#10 0x00007fc92c3f2f38 _PyEval_EvalFrameDefault
#11 0x00007fc92c3f2f38 _PyEval_EvalFrameDefault
#12 0x00007fc92c3f2f38 _PyEval_EvalFrameDefault
#13 0x00007fc92c3f2f38 _PyEval_EvalFrameDefault
#14 0x00007fc92c3f2f38 _PyEval_EvalFrameDefault
#15 0x00007fc92c3f2f38 _PyEval_EvalFrameDefault
#16 0x00007fc92c3f2f38 _PyEval_EvalFrameDefault
#17 0x00007fc92c3f2f38 _PyEval_EvalFrameDefault
#18 0x00007fc92c3f2f38 _PyEval_EvalFrameDefault
#19 0x00007fc92c3f2f38 _PyEval_EvalFrameDefault
#20 0x00007fc92c3f2f38 _PyEval_EvalFrameDefault
#21 0x00007fc92c3f2f38 _PyEval_EvalFrameDefault
#22 0x00007fc92c3f2f38 _PyEval_EvalFrameDefault
#23 0x00007fc92c3f2f38 _PyEval_EvalFrameDefault
#24 0x00007fc92c3f2f38 _PyEval_EvalFrameDefault
#25 0x00007fc92c3f2f38 _PyEval_EvalFrameDefault
#26 0x00007fc92c3f2f38 _PyEval_EvalFrameDefault
#27 0x00007fc92c3f2f38 _PyEval_EvalFrameDefault
#28 0x00007fc92c3f2f38 _PyEval_EvalFrameDefault
#29 0x00007fc92c3f2f38 _PyEval_EvalFrameDefault
#30 0x00007fc92c3f2f38 _PyEval_EvalFrameDefault
#31 0x00007fc92c3f2f38 _PyEval_EvalFrameDefault
#32 0x00007fc92c3f2f38 _PyEval_EvalFrameDefault
#33 0x00007fc92c3f2f38 _PyEval_EvalFrameDefault
#34 0x00007fc8f1f854ff __Pyx_PyObject_Call (/project/uvloop/loop.c:191431:15)
#35 0x00007fc8f204f948 __pyx_f_6uvloop_4loop_6Handle__run (/project/uvloop/loop.c:66901:25)
#36 0x00007fc8f2053f7c __pyx_f_6uvloop_4loop_4Loop__on_idle (/project/uvloop/loop.c:17975:25)
#37 0x00007fc8f204f9a6 __pyx_f_6uvloop_4loop_6Handle__run (/project/uvloop/loop.c:66927:24)
#38 0x00007fc8f2051047 __pyx_f_6uvloop_4loop_cb_idle_callback (/project/uvloop/loop.c:87335:19)
#39 0x00007fc8f20687d1 uv__run_idle (/project/build/libuv-x86_64/src/unix/loop-watcher.c:68:1)
#40 0x00007fc8f2065b07 uv_run (/project/build/libuv-x86_64/src/unix/core.c:439:5)
#41 0x00007fc8f1fb83a0 __pyx_f_6uvloop_4loop_4Loop__Loop__run (/project/uvloop/loop.c:18458:23)
#42 0x00007fc8f1ff612d __pyx_f_6uvloop_4loop_4Loop__run (/project/uvloop/loop.c:18876:18)
#43 0x00007fc8f1ff1e85 __pyx_pf_6uvloop_4loop_4Loop_24run_forever (/project/uvloop/loop.c:31528:18)
#44 0x00007fc8f1ff1e85 __pyx_pw_6uvloop_4loop_4Loop_25run_forever (/project/uvloop/loop.c:31331:13)
#45 0x00007fc92c3ec26e PyObject_VectorcallMethod
#46 0x00007fc92c3f039b _PyEval_EvalFrameDefault
#47 0x00007fc92c47474c PyEval_EvalCode
#48 0x00007fc92c4a24a7 _PyRun_SimpleFileObject
#49 0x00007fc92c4a1b38 _PyRun_AnyFileObject
#50 0x00007fc92c49c3be Py_RunMain
#51 0x00007fc92c46461b Py_BytesMain
#52 0x00007fc92c067d65 __libc_start_main
#53 0x0000559068986071 _start
```

The crash happens in `PyObject_GC_UnTrack`, called from the dealloc path of a HAMT node that `PyContextVar_Set` is trying to free via `Py_DECREF`.  If that HAMT node's memory is already unmapped, the `PyObject_GC_UnTrack` write faults.

## Root Cause

`BaseWrappingContext.__enter__`  does this...

```python
def __enter__(self) -> "BaseWrappingContext":
    token: Token = self._storage.set({})          # 1. create new HAMT entry
    self._storage.get()["__dd_wrapping_context_token__"] = token  # 2. store Token in dict
    return self
```

- Step 1 stores a fresh `{}` dict in the context's HAMT under `self._storage`
- Step 2 puts the `Token` returned by `set()` into that same dict.

A `Token` object holds `tok_ctx`, which is a strong reference to the `PyContext` that was active when `set` was called (i.e. `ts->context`).

This creates the following reference cycle:

```
ts->context
  └─▶ ctx_vars (HAMT root)
        └─▶ ... HAMT nodes ...
              └─▶ dict  {"__dd_wrapping_context_token__": token}
                    └─▶ token  (PyContextToken)
                          └─▶ tok_ctx  ────────────────▶ ts->context  ⟲
```

Now, `PyContextVar_Set` is **not atomic**.  Its simplified CPython implementation is:

```c
static PyObject *
contextvar_set(PyContextVar *var, PyObject *val) {
    PyContext *ts_ctx = ts->context;
    PyObject *new_hamt = _PyHamt_Assoc(ts_ctx->ctx_vars, var, val);
    Py_DECREF(ts_ctx->ctx_vars);   // ← old HAMT root refcount decremented here
    ts_ctx->ctx_vars = new_hamt;
    ...
}
```

At `Py_DECREF(ts_ctx->ctx_vars)`:

1. The old HAMT root's refcount drops.  If it reaches 0, `_Py_Dealloc` is called, which calls `hamt_tp_dealloc` which calls `PyObject_GC_UnTrack(old_hamt)`.
2. Inside `_Py_Dealloc` the old HAMT decrefs its children (intermediate nodes).
3. Those node decrefs cascade.  A leaf node that is now only referenced by the *old* HAMT (not the new one) reaches refcount 0 and is also freed, its    memory potentially returned to the OS.
4. Meanwhile `ts_ctx->ctx_vars` still points to the (now freed) old root until    line 3 of the snippet above executes.
5. If the Python cyclic GC fires at the wrong moment -- triggered by another    allocation during the HAMT rebuild -- it may traverse the cycle above, see    the Token's `tok_ctx` pointing at `ts->context`, and interfere with    refcounts, causing a node to be collected prematurely.
6. `PyObject_GC_UnTrack` is then called on a node whose memory is already    unmapped which results in **SEGV_MAPERR**.

## Proposed Fix

Store the **previous value** of `_storage` in the dict instead of the `Token`. Restore it with `set` rather than `reset`. In other words:

```python
def __enter__(self) -> "BaseWrappingContext":
    prev = self._storage.get()
    self._storage.set({"__dd_wrapping_context_prev__": prev})
    # Token returned by set() is discarded immediately → refcount 0 → freed
    return self

def _pop_storage(self) -> dict[str, t.Any]:
    storage = self._storage.get()
    self._storage.set(storage.pop("__dd_wrapping_context_prev__"))
    return storage
```

The `Token` object is now ephemeral: it is returned by `set`, never stored anywhere, and freed immediately when the local expression is evaluated.  Nothing inside the HAMT ever holds a `Token`, so the cycle is gone.

### Correctness

`reset(token)` and `set(prev_value)` are equivalent for this use-case:

- Both restore `_storage` to its value before `__enter__` was called.
- `reset()` additionally validates that the context hasn't changed since the   token was created, raising `ValueError` if it has.  That guard is not needed   here because `BaseWrappingContext` fully controls the enter/exit lifecycle.
- Nested and recursive calls continue to work correctly: each `__enter__`   pushes a new dict that records the prior one; each `_pop_storage` pops it.


Co-authored-by: thomas.kowalski <thomas.kowalski@datadoghq.com>
gh-worker-dd-mergequeue-cf854d Bot pushed a commit that referenced this pull request Apr 20, 2026
## Description

This PR fixes a crash coming from IAST due to an inconsistent reference count contract between `new_pyobject_id` and its callers, where the callers would expect a new owned reference like it [already does today](https://github.com/DataDog/dd-trace-py/blob/c02775f9db03c05f90356181323d000b86aba7da/ddtrace/appsec/_iast/_taint_tracking/utils/string_utils.cpp#L169-L171) but some code paths were missing the `Py_INCREF`, causing segmentation faults (see [example usage](https://github.com/DataDog/dd-trace-py/blob/c02775f9db03c05f90356181323d000b86aba7da/ddtrace/appsec/_iast/_taint_tracking/aspects/aspect_operator_add.cpp#L30-L31)). 

This error has been around at least since 3.11.0 and is currently causing approximately [50k errors per week](https://app.datadoghq.com/error-tracking/issue/01522162-6bf3-11f0-b96b-da7ad0900002?query=%28%40tags.severity%3Acrash%20OR%20severity%3Acrash%20OR%20signum%3A%2A%20OR%20%40error.is_crash%3Atrue%29%20%40lib_language%3Apython&index=&tb=%40org_id&from_ts=1775841064700&to_ts=1776445864700&live=true). 

```
Error UnixSignal: Process terminated with SEGV_MAPERR (SIGSEGV)
#0   0x000061335a8b72d4 PyType_IsSubtype (/usr/src/python/Objects/typeobject.c:2126:1)
#1   0x000061335a89e11c PyObject_TypeCheck (/usr/src/python/./Include/object.h:381:36)
#2   0x000061335a89e11c object_isinstance (/usr/src/python/Objects/abstract.c:2571:18)
#3   0x000061335a89cbeb object_recursive_isinstance (/usr/src/python/Objects/abstract.c:2606:16)
#4   0x000061335a89cbeb object_recursive_isinstance (/usr/src/python/Objects/abstract.c:2628:17)
#5   0x000061335a89cbeb object_recursive_isinstance (/usr/src/python/Objects/abstract.c:2602:1)
#6   0x000061335a89cbeb PyObject_IsInstance (/usr/src/python/Objects/abstract.c:2670:12)
#7   0x000061335a8c89ed _PyEval_EvalFrameDefault (/usr/src/python/Python/bytecodes.c:3036:26)
#8   0x000061335a98fd11 _PyObject_VectorcallTstate (/usr/src/python/./Include/internal/pycore_call.h:92:11)
#9   0x000061335a884945 partial_vectorcall (/usr/src/python/./Modules/_functoolsmodule.c:267:11)
#10  0x000061335a8a0bf4 _PyObject_VectorcallTstate (/usr/src/python/./Include/internal/pycore_call.h:92:11)
#11  0x000061335a8a0bf4 object_vacall (/usr/src/python/Objects/call.c:850:14)
#12  0x000061335a8fdf8e PyObject_CallFunctionObjArgs (/usr/src/python/Objects/call.c:957:14)
#13  0x000074f48affeb28 WraptBoundFunctionWrapper_call (/project/src/wrapt/_wrappers.c:3024:18)
#14  0x000061335a8a12e2 PyObject_Call
#15  0x000061335a8cb1a9 _PyEval_EvalFrameDefault (/usr/src/python/Python/bytecodes.c:3263:26)
#16  0x000061335a8a3ba6 _PyEval_EvalFrame (/usr/src/python/./Include/internal/pycore_ceval.h:89:16)
#17  0x000061335a8a3ba6 gen_send_ex2 (/usr/src/python/Objects/genobject.c:230:14)
#18  0x000074f48d48bdc7 task_step_impl (/usr/src/python/./Modules/_asynciomodule.c:2869:22)
#19  0x000074f48d48c5a2 task_step (/usr/src/python/./Modules/_asynciomodule.c:3188:11)
#20  0x000061335a8af877 cfunction_vectorcall_O (/usr/src/python/Objects/methodobject.c:509:24)
#21  0x000074f48a434f69 __Pyx_PyObject_Call (/project/uvloop/loop.c:191431:15)
#22  0x000074f48a434f69 __pyx_f_6uvloop_4loop_6Handle__run (/project/uvloop/loop.c:66901:25)
#23  0x000074f48a43a96b __pyx_f_6uvloop_4loop_4Loop__on_idle (/project/uvloop/loop.c:17975:25)
#24  0x000074f48a434e52 __pyx_f_6uvloop_4loop_6Handle__run (/project/uvloop/loop.c:66927:24)
#25  0x000074f48a436c88 __pyx_f_6uvloop_4loop_cb_idle_callback (/project/uvloop/loop.c:87335:19)
#26  0x000074f48a452311 uv__run_idle (/project/build/libuv-x86_64/src/unix/loop-watcher.c:68:1)
#27  0x000074f48a44f647 uv_run (/project/build/libuv-x86_64/src/unix/core.c:439:5)
#28  0x000074f48a370db5 __pyx_f_6uvloop_4loop_4Loop__Loop__run (/project/uvloop/loop.c:18458:23)
#29  0x000074f48a3d8e50 __pyx_f_6uvloop_4loop_4Loop__run (/project/uvloop/loop.c:18876:18)
#30  0x000074f48a3e9cf0 __pyx_pf_6uvloop_4loop_4Loop_24run_forever (/project/uvloop/loop.c:31528:18)
#31  0x000074f48a3e9cf0 __pyx_pw_6uvloop_4loop_4Loop_25run_forever (/project/uvloop/loop.c:31331:13)
#32  0x000061335a8a159c _PyObject_VectorcallTstate (/usr/src/python/./Include/internal/pycore_call.h:92:11)
#33  0x000061335a8a159c PyObject_VectorcallMethod (/usr/src/python/Objects/call.c:887:24)
#34  0x000074f48a3edd60 __pyx_pf_6uvloop_4loop_4Loop_44run_until_complete (/project/uvloop/loop.c:33768:23)
#35  0x000074f48a3ef591 __pyx_pw_6uvloop_4loop_4Loop_45run_until_complete (/project/uvloop/loop.c:33318:13)
#36  0x000061335a8a0a18 _PyObject_VectorcallTstate (/usr/src/python/./Include/internal/pycore_call.h:92:11)
#37  0x000061335a8a0a18 PyObject_Vectorcall (/usr/src/python/Objects/call.c:325:12)
#38  0x000061335a8c7807 _PyEval_EvalFrameDefault (/usr/src/python/Python/bytecodes.c:2715:19)
#39  0x000061335a8a3ba6 _PyEval_EvalFrame (/usr/src/python/./Include/internal/pycore_ceval.h:89:16)
#40  0x000061335a8a3ba6 gen_send_ex2 (/usr/src/python/Objects/genobject.c:230:14)
#41  0x000074f48d48bdc7 task_step_impl (/usr/src/python/./Modules/_asynciomodule.c:2869:22)
#42  0x000074f48d48c5a2 task_step (/usr/src/python/./Modules/_asynciomodule.c:3188:11)
#43  0x000061335a8a06fe _PyObject_MakeTpCall (/usr/src/python/Objects/call.c:240:18)
#44  0x000061335a82380c _PyObject_VectorcallTstate (/usr/src/python/./Include/internal/pycore_call.h:90:16)
#45  0x000061335a82380c context_run (/usr/src/python/Python/context.c:668:29)
#46  0x000061335a912d7b cfunction_vectorcall_FASTCALL_KEYWORDS (/usr/src/python/Objects/methodobject.c:438:24)
#47  0x000061335a8cb1a9 _PyEval_EvalFrameDefault (/usr/src/python/Python/bytecodes.c:3263:26)
#48  0x000061335a94a4b9 PyEval_EvalCode (/usr/src/python/Python/ceval.c:578:21)
#49  0x000061335a96852c run_eval_code_obj (/usr/src/python/Python/pythonrun.c:1722:9)
#50  0x000061335a9684a4 run_mod (/usr/src/python/Python/pythonrun.c:1743:19)
#51  0x000061335a968061 pyrun_file (/usr/src/python/Python/pythonrun.c:1643:15)
#52  0x000061335a967ea7 _PyRun_SimpleFileObject (/usr/src/python/Python/pythonrun.c:433:13)
#53  0x000061335a967cc7 _PyRun_AnyFileObject (/usr/src/python/Python/pythonrun.c:78:15)
#54  0x000061335a972230 pymain_run_file_obj (/usr/src/python/Modules/main.c:360:15)
#55  0x000061335a972230 pymain_run_file (/usr/src/python/Modules/main.c:379:15)
#56  0x000061335a972230 pymain_run_python (/usr/src/python/Modules/main.c:633:21)
#57  0x000061335a972230 Py_RunMain (/usr/src/python/Modules/main.c:713:5)
#58  0x000061335a971dbd Py_BytesMain (/usr/src/python/Modules/main.c:767:12)
#59  0x000074f48e000e40 __libc_start_main
#60  0x000061335a8ea2d5 _start
```

Co-authored-by: thomas.kowalski <thomas.kowalski@datadoghq.com>
github-actions Bot added a commit that referenced this pull request Apr 21, 2026
## Description

This PR fixes a crash coming from IAST due to an inconsistent reference count contract between `new_pyobject_id` and its callers, where the callers would expect a new owned reference like it [already does today](https://github.com/DataDog/dd-trace-py/blob/c02775f9db03c05f90356181323d000b86aba7da/ddtrace/appsec/_iast/_taint_tracking/utils/string_utils.cpp#L169-L171) but some code paths were missing the `Py_INCREF`, causing segmentation faults (see [example usage](https://github.com/DataDog/dd-trace-py/blob/c02775f9db03c05f90356181323d000b86aba7da/ddtrace/appsec/_iast/_taint_tracking/aspects/aspect_operator_add.cpp#L30-L31)).

This error has been around at least since 3.11.0 and is currently causing approximately [50k errors per week](https://app.datadoghq.com/error-tracking/issue/01522162-6bf3-11f0-b96b-da7ad0900002?query=%28%40tags.severity%3Acrash%20OR%20severity%3Acrash%20OR%20signum%3A%2A%20OR%20%40error.is_crash%3Atrue%29%20%40lib_language%3Apython&index=&tb=%40org_id&from_ts=1775841064700&to_ts=1776445864700&live=true).

```
Error UnixSignal: Process terminated with SEGV_MAPERR (SIGSEGV)
#0   0x000061335a8b72d4 PyType_IsSubtype (/usr/src/python/Objects/typeobject.c:2126:1)
#1   0x000061335a89e11c PyObject_TypeCheck (/usr/src/python/./Include/object.h:381:36)
#2   0x000061335a89e11c object_isinstance (/usr/src/python/Objects/abstract.c:2571:18)
#3   0x000061335a89cbeb object_recursive_isinstance (/usr/src/python/Objects/abstract.c:2606:16)
#4   0x000061335a89cbeb object_recursive_isinstance (/usr/src/python/Objects/abstract.c:2628:17)
#5   0x000061335a89cbeb object_recursive_isinstance (/usr/src/python/Objects/abstract.c:2602:1)
#6   0x000061335a89cbeb PyObject_IsInstance (/usr/src/python/Objects/abstract.c:2670:12)
#7   0x000061335a8c89ed _PyEval_EvalFrameDefault (/usr/src/python/Python/bytecodes.c:3036:26)
#8   0x000061335a98fd11 _PyObject_VectorcallTstate (/usr/src/python/./Include/internal/pycore_call.h:92:11)
#9   0x000061335a884945 partial_vectorcall (/usr/src/python/./Modules/_functoolsmodule.c:267:11)
#10  0x000061335a8a0bf4 _PyObject_VectorcallTstate (/usr/src/python/./Include/internal/pycore_call.h:92:11)
#11  0x000061335a8a0bf4 object_vacall (/usr/src/python/Objects/call.c:850:14)
#12  0x000061335a8fdf8e PyObject_CallFunctionObjArgs (/usr/src/python/Objects/call.c:957:14)
#13  0x000074f48affeb28 WraptBoundFunctionWrapper_call (/project/src/wrapt/_wrappers.c:3024:18)
#14  0x000061335a8a12e2 PyObject_Call
#15  0x000061335a8cb1a9 _PyEval_EvalFrameDefault (/usr/src/python/Python/bytecodes.c:3263:26)
#16  0x000061335a8a3ba6 _PyEval_EvalFrame (/usr/src/python/./Include/internal/pycore_ceval.h:89:16)
#17  0x000061335a8a3ba6 gen_send_ex2 (/usr/src/python/Objects/genobject.c:230:14)
#18  0x000074f48d48bdc7 task_step_impl (/usr/src/python/./Modules/_asynciomodule.c:2869:22)
#19  0x000074f48d48c5a2 task_step (/usr/src/python/./Modules/_asynciomodule.c:3188:11)
#20  0x000061335a8af877 cfunction_vectorcall_O (/usr/src/python/Objects/methodobject.c:509:24)
#21  0x000074f48a434f69 __Pyx_PyObject_Call (/project/uvloop/loop.c:191431:15)
#22  0x000074f48a434f69 __pyx_f_6uvloop_4loop_6Handle__run (/project/uvloop/loop.c:66901:25)
#23  0x000074f48a43a96b __pyx_f_6uvloop_4loop_4Loop__on_idle (/project/uvloop/loop.c:17975:25)
#24  0x000074f48a434e52 __pyx_f_6uvloop_4loop_6Handle__run (/project/uvloop/loop.c:66927:24)
#25  0x000074f48a436c88 __pyx_f_6uvloop_4loop_cb_idle_callback (/project/uvloop/loop.c:87335:19)
#26  0x000074f48a452311 uv__run_idle (/project/build/libuv-x86_64/src/unix/loop-watcher.c:68:1)
#27  0x000074f48a44f647 uv_run (/project/build/libuv-x86_64/src/unix/core.c:439:5)
#28  0x000074f48a370db5 __pyx_f_6uvloop_4loop_4Loop__Loop__run (/project/uvloop/loop.c:18458:23)
#29  0x000074f48a3d8e50 __pyx_f_6uvloop_4loop_4Loop__run (/project/uvloop/loop.c:18876:18)
#30  0x000074f48a3e9cf0 __pyx_pf_6uvloop_4loop_4Loop_24run_forever (/project/uvloop/loop.c:31528:18)
#31  0x000074f48a3e9cf0 __pyx_pw_6uvloop_4loop_4Loop_25run_forever (/project/uvloop/loop.c:31331:13)
#32  0x000061335a8a159c _PyObject_VectorcallTstate (/usr/src/python/./Include/internal/pycore_call.h:92:11)
#33  0x000061335a8a159c PyObject_VectorcallMethod (/usr/src/python/Objects/call.c:887:24)
#34  0x000074f48a3edd60 __pyx_pf_6uvloop_4loop_4Loop_44run_until_complete (/project/uvloop/loop.c:33768:23)
#35  0x000074f48a3ef591 __pyx_pw_6uvloop_4loop_4Loop_45run_until_complete (/project/uvloop/loop.c:33318:13)
#36  0x000061335a8a0a18 _PyObject_VectorcallTstate (/usr/src/python/./Include/internal/pycore_call.h:92:11)
#37  0x000061335a8a0a18 PyObject_Vectorcall (/usr/src/python/Objects/call.c:325:12)
#38  0x000061335a8c7807 _PyEval_EvalFrameDefault (/usr/src/python/Python/bytecodes.c:2715:19)
#39  0x000061335a8a3ba6 _PyEval_EvalFrame (/usr/src/python/./Include/internal/pycore_ceval.h:89:16)
#40  0x000061335a8a3ba6 gen_send_ex2 (/usr/src/python/Objects/genobject.c:230:14)
#41  0x000074f48d48bdc7 task_step_impl (/usr/src/python/./Modules/_asynciomodule.c:2869:22)
#42  0x000074f48d48c5a2 task_step (/usr/src/python/./Modules/_asynciomodule.c:3188:11)
#43  0x000061335a8a06fe _PyObject_MakeTpCall (/usr/src/python/Objects/call.c:240:18)
#44  0x000061335a82380c _PyObject_VectorcallTstate (/usr/src/python/./Include/internal/pycore_call.h:90:16)
#45  0x000061335a82380c context_run (/usr/src/python/Python/context.c:668:29)
#46  0x000061335a912d7b cfunction_vectorcall_FASTCALL_KEYWORDS (/usr/src/python/Objects/methodobject.c:438:24)
#47  0x000061335a8cb1a9 _PyEval_EvalFrameDefault (/usr/src/python/Python/bytecodes.c:3263:26)
#48  0x000061335a94a4b9 PyEval_EvalCode (/usr/src/python/Python/ceval.c:578:21)
#49  0x000061335a96852c run_eval_code_obj (/usr/src/python/Python/pythonrun.c:1722:9)
#50  0x000061335a9684a4 run_mod (/usr/src/python/Python/pythonrun.c:1743:19)
#51  0x000061335a968061 pyrun_file (/usr/src/python/Python/pythonrun.c:1643:15)
#52  0x000061335a967ea7 _PyRun_SimpleFileObject (/usr/src/python/Python/pythonrun.c:433:13)
#53  0x000061335a967cc7 _PyRun_AnyFileObject (/usr/src/python/Python/pythonrun.c:78:15)
#54  0x000061335a972230 pymain_run_file_obj (/usr/src/python/Modules/main.c:360:15)
#55  0x000061335a972230 pymain_run_file (/usr/src/python/Modules/main.c:379:15)
#56  0x000061335a972230 pymain_run_python (/usr/src/python/Modules/main.c:633:21)
#57  0x000061335a972230 Py_RunMain (/usr/src/python/Modules/main.c:713:5)
#58  0x000061335a971dbd Py_BytesMain (/usr/src/python/Modules/main.c:767:12)
#59  0x000074f48e000e40 __libc_start_main
#60  0x000061335a8ea2d5 _start
```

Co-authored-by: thomas.kowalski <thomas.kowalski@datadoghq.com>
(cherry picked from commit 36bf68b)

Co-authored-by: Thomas Kowalski <thomas.kowalski@datadoghq.com>
github-actions Bot added a commit that referenced this pull request Apr 21, 2026
## Description

This PR fixes a crash coming from IAST due to an inconsistent reference count contract between `new_pyobject_id` and its callers, where the callers would expect a new owned reference like it [already does today](https://github.com/DataDog/dd-trace-py/blob/c02775f9db03c05f90356181323d000b86aba7da/ddtrace/appsec/_iast/_taint_tracking/utils/string_utils.cpp#L169-L171) but some code paths were missing the `Py_INCREF`, causing segmentation faults (see [example usage](https://github.com/DataDog/dd-trace-py/blob/c02775f9db03c05f90356181323d000b86aba7da/ddtrace/appsec/_iast/_taint_tracking/aspects/aspect_operator_add.cpp#L30-L31)).

This error has been around at least since 3.11.0 and is currently causing approximately [50k errors per week](https://app.datadoghq.com/error-tracking/issue/01522162-6bf3-11f0-b96b-da7ad0900002?query=%28%40tags.severity%3Acrash%20OR%20severity%3Acrash%20OR%20signum%3A%2A%20OR%20%40error.is_crash%3Atrue%29%20%40lib_language%3Apython&index=&tb=%40org_id&from_ts=1775841064700&to_ts=1776445864700&live=true).

```
Error UnixSignal: Process terminated with SEGV_MAPERR (SIGSEGV)
#0   0x000061335a8b72d4 PyType_IsSubtype (/usr/src/python/Objects/typeobject.c:2126:1)
#1   0x000061335a89e11c PyObject_TypeCheck (/usr/src/python/./Include/object.h:381:36)
#2   0x000061335a89e11c object_isinstance (/usr/src/python/Objects/abstract.c:2571:18)
#3   0x000061335a89cbeb object_recursive_isinstance (/usr/src/python/Objects/abstract.c:2606:16)
#4   0x000061335a89cbeb object_recursive_isinstance (/usr/src/python/Objects/abstract.c:2628:17)
#5   0x000061335a89cbeb object_recursive_isinstance (/usr/src/python/Objects/abstract.c:2602:1)
#6   0x000061335a89cbeb PyObject_IsInstance (/usr/src/python/Objects/abstract.c:2670:12)
#7   0x000061335a8c89ed _PyEval_EvalFrameDefault (/usr/src/python/Python/bytecodes.c:3036:26)
#8   0x000061335a98fd11 _PyObject_VectorcallTstate (/usr/src/python/./Include/internal/pycore_call.h:92:11)
#9   0x000061335a884945 partial_vectorcall (/usr/src/python/./Modules/_functoolsmodule.c:267:11)
#10  0x000061335a8a0bf4 _PyObject_VectorcallTstate (/usr/src/python/./Include/internal/pycore_call.h:92:11)
#11  0x000061335a8a0bf4 object_vacall (/usr/src/python/Objects/call.c:850:14)
#12  0x000061335a8fdf8e PyObject_CallFunctionObjArgs (/usr/src/python/Objects/call.c:957:14)
#13  0x000074f48affeb28 WraptBoundFunctionWrapper_call (/project/src/wrapt/_wrappers.c:3024:18)
#14  0x000061335a8a12e2 PyObject_Call
#15  0x000061335a8cb1a9 _PyEval_EvalFrameDefault (/usr/src/python/Python/bytecodes.c:3263:26)
#16  0x000061335a8a3ba6 _PyEval_EvalFrame (/usr/src/python/./Include/internal/pycore_ceval.h:89:16)
#17  0x000061335a8a3ba6 gen_send_ex2 (/usr/src/python/Objects/genobject.c:230:14)
#18  0x000074f48d48bdc7 task_step_impl (/usr/src/python/./Modules/_asynciomodule.c:2869:22)
#19  0x000074f48d48c5a2 task_step (/usr/src/python/./Modules/_asynciomodule.c:3188:11)
#20  0x000061335a8af877 cfunction_vectorcall_O (/usr/src/python/Objects/methodobject.c:509:24)
#21  0x000074f48a434f69 __Pyx_PyObject_Call (/project/uvloop/loop.c:191431:15)
#22  0x000074f48a434f69 __pyx_f_6uvloop_4loop_6Handle__run (/project/uvloop/loop.c:66901:25)
#23  0x000074f48a43a96b __pyx_f_6uvloop_4loop_4Loop__on_idle (/project/uvloop/loop.c:17975:25)
#24  0x000074f48a434e52 __pyx_f_6uvloop_4loop_6Handle__run (/project/uvloop/loop.c:66927:24)
#25  0x000074f48a436c88 __pyx_f_6uvloop_4loop_cb_idle_callback (/project/uvloop/loop.c:87335:19)
#26  0x000074f48a452311 uv__run_idle (/project/build/libuv-x86_64/src/unix/loop-watcher.c:68:1)
#27  0x000074f48a44f647 uv_run (/project/build/libuv-x86_64/src/unix/core.c:439:5)
#28  0x000074f48a370db5 __pyx_f_6uvloop_4loop_4Loop__Loop__run (/project/uvloop/loop.c:18458:23)
#29  0x000074f48a3d8e50 __pyx_f_6uvloop_4loop_4Loop__run (/project/uvloop/loop.c:18876:18)
#30  0x000074f48a3e9cf0 __pyx_pf_6uvloop_4loop_4Loop_24run_forever (/project/uvloop/loop.c:31528:18)
#31  0x000074f48a3e9cf0 __pyx_pw_6uvloop_4loop_4Loop_25run_forever (/project/uvloop/loop.c:31331:13)
#32  0x000061335a8a159c _PyObject_VectorcallTstate (/usr/src/python/./Include/internal/pycore_call.h:92:11)
#33  0x000061335a8a159c PyObject_VectorcallMethod (/usr/src/python/Objects/call.c:887:24)
#34  0x000074f48a3edd60 __pyx_pf_6uvloop_4loop_4Loop_44run_until_complete (/project/uvloop/loop.c:33768:23)
#35  0x000074f48a3ef591 __pyx_pw_6uvloop_4loop_4Loop_45run_until_complete (/project/uvloop/loop.c:33318:13)
#36  0x000061335a8a0a18 _PyObject_VectorcallTstate (/usr/src/python/./Include/internal/pycore_call.h:92:11)
#37  0x000061335a8a0a18 PyObject_Vectorcall (/usr/src/python/Objects/call.c:325:12)
#38  0x000061335a8c7807 _PyEval_EvalFrameDefault (/usr/src/python/Python/bytecodes.c:2715:19)
#39  0x000061335a8a3ba6 _PyEval_EvalFrame (/usr/src/python/./Include/internal/pycore_ceval.h:89:16)
#40  0x000061335a8a3ba6 gen_send_ex2 (/usr/src/python/Objects/genobject.c:230:14)
#41  0x000074f48d48bdc7 task_step_impl (/usr/src/python/./Modules/_asynciomodule.c:2869:22)
#42  0x000074f48d48c5a2 task_step (/usr/src/python/./Modules/_asynciomodule.c:3188:11)
#43  0x000061335a8a06fe _PyObject_MakeTpCall (/usr/src/python/Objects/call.c:240:18)
#44  0x000061335a82380c _PyObject_VectorcallTstate (/usr/src/python/./Include/internal/pycore_call.h:90:16)
#45  0x000061335a82380c context_run (/usr/src/python/Python/context.c:668:29)
#46  0x000061335a912d7b cfunction_vectorcall_FASTCALL_KEYWORDS (/usr/src/python/Objects/methodobject.c:438:24)
#47  0x000061335a8cb1a9 _PyEval_EvalFrameDefault (/usr/src/python/Python/bytecodes.c:3263:26)
#48  0x000061335a94a4b9 PyEval_EvalCode (/usr/src/python/Python/ceval.c:578:21)
#49  0x000061335a96852c run_eval_code_obj (/usr/src/python/Python/pythonrun.c:1722:9)
#50  0x000061335a9684a4 run_mod (/usr/src/python/Python/pythonrun.c:1743:19)
#51  0x000061335a968061 pyrun_file (/usr/src/python/Python/pythonrun.c:1643:15)
#52  0x000061335a967ea7 _PyRun_SimpleFileObject (/usr/src/python/Python/pythonrun.c:433:13)
#53  0x000061335a967cc7 _PyRun_AnyFileObject (/usr/src/python/Python/pythonrun.c:78:15)
#54  0x000061335a972230 pymain_run_file_obj (/usr/src/python/Modules/main.c:360:15)
#55  0x000061335a972230 pymain_run_file (/usr/src/python/Modules/main.c:379:15)
#56  0x000061335a972230 pymain_run_python (/usr/src/python/Modules/main.c:633:21)
#57  0x000061335a972230 Py_RunMain (/usr/src/python/Modules/main.c:713:5)
#58  0x000061335a971dbd Py_BytesMain (/usr/src/python/Modules/main.c:767:12)
#59  0x000074f48e000e40 __libc_start_main
#60  0x000061335a8ea2d5 _start
```

Co-authored-by: thomas.kowalski <thomas.kowalski@datadoghq.com>
(cherry picked from commit 36bf68b)

Co-authored-by: Thomas Kowalski <thomas.kowalski@datadoghq.com>
github-actions Bot added a commit that referenced this pull request Apr 21, 2026
## Description

This PR fixes a crash coming from IAST due to an inconsistent reference count contract between `new_pyobject_id` and its callers, where the callers would expect a new owned reference like it [already does today](https://github.com/DataDog/dd-trace-py/blob/c02775f9db03c05f90356181323d000b86aba7da/ddtrace/appsec/_iast/_taint_tracking/utils/string_utils.cpp#L169-L171) but some code paths were missing the `Py_INCREF`, causing segmentation faults (see [example usage](https://github.com/DataDog/dd-trace-py/blob/c02775f9db03c05f90356181323d000b86aba7da/ddtrace/appsec/_iast/_taint_tracking/aspects/aspect_operator_add.cpp#L30-L31)).

This error has been around at least since 3.11.0 and is currently causing approximately [50k errors per week](https://app.datadoghq.com/error-tracking/issue/01522162-6bf3-11f0-b96b-da7ad0900002?query=%28%40tags.severity%3Acrash%20OR%20severity%3Acrash%20OR%20signum%3A%2A%20OR%20%40error.is_crash%3Atrue%29%20%40lib_language%3Apython&index=&tb=%40org_id&from_ts=1775841064700&to_ts=1776445864700&live=true).

```
Error UnixSignal: Process terminated with SEGV_MAPERR (SIGSEGV)
#0   0x000061335a8b72d4 PyType_IsSubtype (/usr/src/python/Objects/typeobject.c:2126:1)
#1   0x000061335a89e11c PyObject_TypeCheck (/usr/src/python/./Include/object.h:381:36)
#2   0x000061335a89e11c object_isinstance (/usr/src/python/Objects/abstract.c:2571:18)
#3   0x000061335a89cbeb object_recursive_isinstance (/usr/src/python/Objects/abstract.c:2606:16)
#4   0x000061335a89cbeb object_recursive_isinstance (/usr/src/python/Objects/abstract.c:2628:17)
#5   0x000061335a89cbeb object_recursive_isinstance (/usr/src/python/Objects/abstract.c:2602:1)
#6   0x000061335a89cbeb PyObject_IsInstance (/usr/src/python/Objects/abstract.c:2670:12)
#7   0x000061335a8c89ed _PyEval_EvalFrameDefault (/usr/src/python/Python/bytecodes.c:3036:26)
#8   0x000061335a98fd11 _PyObject_VectorcallTstate (/usr/src/python/./Include/internal/pycore_call.h:92:11)
#9   0x000061335a884945 partial_vectorcall (/usr/src/python/./Modules/_functoolsmodule.c:267:11)
#10  0x000061335a8a0bf4 _PyObject_VectorcallTstate (/usr/src/python/./Include/internal/pycore_call.h:92:11)
#11  0x000061335a8a0bf4 object_vacall (/usr/src/python/Objects/call.c:850:14)
#12  0x000061335a8fdf8e PyObject_CallFunctionObjArgs (/usr/src/python/Objects/call.c:957:14)
#13  0x000074f48affeb28 WraptBoundFunctionWrapper_call (/project/src/wrapt/_wrappers.c:3024:18)
#14  0x000061335a8a12e2 PyObject_Call
#15  0x000061335a8cb1a9 _PyEval_EvalFrameDefault (/usr/src/python/Python/bytecodes.c:3263:26)
#16  0x000061335a8a3ba6 _PyEval_EvalFrame (/usr/src/python/./Include/internal/pycore_ceval.h:89:16)
#17  0x000061335a8a3ba6 gen_send_ex2 (/usr/src/python/Objects/genobject.c:230:14)
#18  0x000074f48d48bdc7 task_step_impl (/usr/src/python/./Modules/_asynciomodule.c:2869:22)
#19  0x000074f48d48c5a2 task_step (/usr/src/python/./Modules/_asynciomodule.c:3188:11)
#20  0x000061335a8af877 cfunction_vectorcall_O (/usr/src/python/Objects/methodobject.c:509:24)
#21  0x000074f48a434f69 __Pyx_PyObject_Call (/project/uvloop/loop.c:191431:15)
#22  0x000074f48a434f69 __pyx_f_6uvloop_4loop_6Handle__run (/project/uvloop/loop.c:66901:25)
#23  0x000074f48a43a96b __pyx_f_6uvloop_4loop_4Loop__on_idle (/project/uvloop/loop.c:17975:25)
#24  0x000074f48a434e52 __pyx_f_6uvloop_4loop_6Handle__run (/project/uvloop/loop.c:66927:24)
#25  0x000074f48a436c88 __pyx_f_6uvloop_4loop_cb_idle_callback (/project/uvloop/loop.c:87335:19)
#26  0x000074f48a452311 uv__run_idle (/project/build/libuv-x86_64/src/unix/loop-watcher.c:68:1)
#27  0x000074f48a44f647 uv_run (/project/build/libuv-x86_64/src/unix/core.c:439:5)
#28  0x000074f48a370db5 __pyx_f_6uvloop_4loop_4Loop__Loop__run (/project/uvloop/loop.c:18458:23)
#29  0x000074f48a3d8e50 __pyx_f_6uvloop_4loop_4Loop__run (/project/uvloop/loop.c:18876:18)
#30  0x000074f48a3e9cf0 __pyx_pf_6uvloop_4loop_4Loop_24run_forever (/project/uvloop/loop.c:31528:18)
#31  0x000074f48a3e9cf0 __pyx_pw_6uvloop_4loop_4Loop_25run_forever (/project/uvloop/loop.c:31331:13)
#32  0x000061335a8a159c _PyObject_VectorcallTstate (/usr/src/python/./Include/internal/pycore_call.h:92:11)
#33  0x000061335a8a159c PyObject_VectorcallMethod (/usr/src/python/Objects/call.c:887:24)
#34  0x000074f48a3edd60 __pyx_pf_6uvloop_4loop_4Loop_44run_until_complete (/project/uvloop/loop.c:33768:23)
#35  0x000074f48a3ef591 __pyx_pw_6uvloop_4loop_4Loop_45run_until_complete (/project/uvloop/loop.c:33318:13)
#36  0x000061335a8a0a18 _PyObject_VectorcallTstate (/usr/src/python/./Include/internal/pycore_call.h:92:11)
#37  0x000061335a8a0a18 PyObject_Vectorcall (/usr/src/python/Objects/call.c:325:12)
#38  0x000061335a8c7807 _PyEval_EvalFrameDefault (/usr/src/python/Python/bytecodes.c:2715:19)
#39  0x000061335a8a3ba6 _PyEval_EvalFrame (/usr/src/python/./Include/internal/pycore_ceval.h:89:16)
#40  0x000061335a8a3ba6 gen_send_ex2 (/usr/src/python/Objects/genobject.c:230:14)
#41  0x000074f48d48bdc7 task_step_impl (/usr/src/python/./Modules/_asynciomodule.c:2869:22)
#42  0x000074f48d48c5a2 task_step (/usr/src/python/./Modules/_asynciomodule.c:3188:11)
#43  0x000061335a8a06fe _PyObject_MakeTpCall (/usr/src/python/Objects/call.c:240:18)
#44  0x000061335a82380c _PyObject_VectorcallTstate (/usr/src/python/./Include/internal/pycore_call.h:90:16)
#45  0x000061335a82380c context_run (/usr/src/python/Python/context.c:668:29)
#46  0x000061335a912d7b cfunction_vectorcall_FASTCALL_KEYWORDS (/usr/src/python/Objects/methodobject.c:438:24)
#47  0x000061335a8cb1a9 _PyEval_EvalFrameDefault (/usr/src/python/Python/bytecodes.c:3263:26)
#48  0x000061335a94a4b9 PyEval_EvalCode (/usr/src/python/Python/ceval.c:578:21)
#49  0x000061335a96852c run_eval_code_obj (/usr/src/python/Python/pythonrun.c:1722:9)
#50  0x000061335a9684a4 run_mod (/usr/src/python/Python/pythonrun.c:1743:19)
#51  0x000061335a968061 pyrun_file (/usr/src/python/Python/pythonrun.c:1643:15)
#52  0x000061335a967ea7 _PyRun_SimpleFileObject (/usr/src/python/Python/pythonrun.c:433:13)
#53  0x000061335a967cc7 _PyRun_AnyFileObject (/usr/src/python/Python/pythonrun.c:78:15)
#54  0x000061335a972230 pymain_run_file_obj (/usr/src/python/Modules/main.c:360:15)
#55  0x000061335a972230 pymain_run_file (/usr/src/python/Modules/main.c:379:15)
#56  0x000061335a972230 pymain_run_python (/usr/src/python/Modules/main.c:633:21)
#57  0x000061335a972230 Py_RunMain (/usr/src/python/Modules/main.c:713:5)
#58  0x000061335a971dbd Py_BytesMain (/usr/src/python/Modules/main.c:767:12)
#59  0x000074f48e000e40 __libc_start_main
#60  0x000061335a8ea2d5 _start
```

Co-authored-by: thomas.kowalski <thomas.kowalski@datadoghq.com>
(cherry picked from commit 36bf68b)

Co-authored-by: Thomas Kowalski <thomas.kowalski@datadoghq.com>
dubloom pushed a commit that referenced this pull request Apr 21, 2026
## Description

This PR fixes a crash coming from IAST due to an inconsistent reference count contract between `new_pyobject_id` and its callers, where the callers would expect a new owned reference like it [already does today](https://github.com/DataDog/dd-trace-py/blob/c02775f9db03c05f90356181323d000b86aba7da/ddtrace/appsec/_iast/_taint_tracking/utils/string_utils.cpp#L169-L171) but some code paths were missing the `Py_INCREF`, causing segmentation faults (see [example usage](https://github.com/DataDog/dd-trace-py/blob/c02775f9db03c05f90356181323d000b86aba7da/ddtrace/appsec/_iast/_taint_tracking/aspects/aspect_operator_add.cpp#L30-L31)). 

This error has been around at least since 3.11.0 and is currently causing approximately [50k errors per week](https://app.datadoghq.com/error-tracking/issue/01522162-6bf3-11f0-b96b-da7ad0900002?query=%28%40tags.severity%3Acrash%20OR%20severity%3Acrash%20OR%20signum%3A%2A%20OR%20%40error.is_crash%3Atrue%29%20%40lib_language%3Apython&index=&tb=%40org_id&from_ts=1775841064700&to_ts=1776445864700&live=true). 

```
Error UnixSignal: Process terminated with SEGV_MAPERR (SIGSEGV)
#0   0x000061335a8b72d4 PyType_IsSubtype (/usr/src/python/Objects/typeobject.c:2126:1)
#1   0x000061335a89e11c PyObject_TypeCheck (/usr/src/python/./Include/object.h:381:36)
#2   0x000061335a89e11c object_isinstance (/usr/src/python/Objects/abstract.c:2571:18)
#3   0x000061335a89cbeb object_recursive_isinstance (/usr/src/python/Objects/abstract.c:2606:16)
#4   0x000061335a89cbeb object_recursive_isinstance (/usr/src/python/Objects/abstract.c:2628:17)
#5   0x000061335a89cbeb object_recursive_isinstance (/usr/src/python/Objects/abstract.c:2602:1)
#6   0x000061335a89cbeb PyObject_IsInstance (/usr/src/python/Objects/abstract.c:2670:12)
#7   0x000061335a8c89ed _PyEval_EvalFrameDefault (/usr/src/python/Python/bytecodes.c:3036:26)
#8   0x000061335a98fd11 _PyObject_VectorcallTstate (/usr/src/python/./Include/internal/pycore_call.h:92:11)
#9   0x000061335a884945 partial_vectorcall (/usr/src/python/./Modules/_functoolsmodule.c:267:11)
#10  0x000061335a8a0bf4 _PyObject_VectorcallTstate (/usr/src/python/./Include/internal/pycore_call.h:92:11)
#11  0x000061335a8a0bf4 object_vacall (/usr/src/python/Objects/call.c:850:14)
#12  0x000061335a8fdf8e PyObject_CallFunctionObjArgs (/usr/src/python/Objects/call.c:957:14)
#13  0x000074f48affeb28 WraptBoundFunctionWrapper_call (/project/src/wrapt/_wrappers.c:3024:18)
#14  0x000061335a8a12e2 PyObject_Call
#15  0x000061335a8cb1a9 _PyEval_EvalFrameDefault (/usr/src/python/Python/bytecodes.c:3263:26)
#16  0x000061335a8a3ba6 _PyEval_EvalFrame (/usr/src/python/./Include/internal/pycore_ceval.h:89:16)
#17  0x000061335a8a3ba6 gen_send_ex2 (/usr/src/python/Objects/genobject.c:230:14)
#18  0x000074f48d48bdc7 task_step_impl (/usr/src/python/./Modules/_asynciomodule.c:2869:22)
#19  0x000074f48d48c5a2 task_step (/usr/src/python/./Modules/_asynciomodule.c:3188:11)
#20  0x000061335a8af877 cfunction_vectorcall_O (/usr/src/python/Objects/methodobject.c:509:24)
#21  0x000074f48a434f69 __Pyx_PyObject_Call (/project/uvloop/loop.c:191431:15)
#22  0x000074f48a434f69 __pyx_f_6uvloop_4loop_6Handle__run (/project/uvloop/loop.c:66901:25)
#23  0x000074f48a43a96b __pyx_f_6uvloop_4loop_4Loop__on_idle (/project/uvloop/loop.c:17975:25)
#24  0x000074f48a434e52 __pyx_f_6uvloop_4loop_6Handle__run (/project/uvloop/loop.c:66927:24)
#25  0x000074f48a436c88 __pyx_f_6uvloop_4loop_cb_idle_callback (/project/uvloop/loop.c:87335:19)
#26  0x000074f48a452311 uv__run_idle (/project/build/libuv-x86_64/src/unix/loop-watcher.c:68:1)
#27  0x000074f48a44f647 uv_run (/project/build/libuv-x86_64/src/unix/core.c:439:5)
#28  0x000074f48a370db5 __pyx_f_6uvloop_4loop_4Loop__Loop__run (/project/uvloop/loop.c:18458:23)
#29  0x000074f48a3d8e50 __pyx_f_6uvloop_4loop_4Loop__run (/project/uvloop/loop.c:18876:18)
#30  0x000074f48a3e9cf0 __pyx_pf_6uvloop_4loop_4Loop_24run_forever (/project/uvloop/loop.c:31528:18)
#31  0x000074f48a3e9cf0 __pyx_pw_6uvloop_4loop_4Loop_25run_forever (/project/uvloop/loop.c:31331:13)
#32  0x000061335a8a159c _PyObject_VectorcallTstate (/usr/src/python/./Include/internal/pycore_call.h:92:11)
#33  0x000061335a8a159c PyObject_VectorcallMethod (/usr/src/python/Objects/call.c:887:24)
#34  0x000074f48a3edd60 __pyx_pf_6uvloop_4loop_4Loop_44run_until_complete (/project/uvloop/loop.c:33768:23)
#35  0x000074f48a3ef591 __pyx_pw_6uvloop_4loop_4Loop_45run_until_complete (/project/uvloop/loop.c:33318:13)
#36  0x000061335a8a0a18 _PyObject_VectorcallTstate (/usr/src/python/./Include/internal/pycore_call.h:92:11)
#37  0x000061335a8a0a18 PyObject_Vectorcall (/usr/src/python/Objects/call.c:325:12)
#38  0x000061335a8c7807 _PyEval_EvalFrameDefault (/usr/src/python/Python/bytecodes.c:2715:19)
#39  0x000061335a8a3ba6 _PyEval_EvalFrame (/usr/src/python/./Include/internal/pycore_ceval.h:89:16)
#40  0x000061335a8a3ba6 gen_send_ex2 (/usr/src/python/Objects/genobject.c:230:14)
#41  0x000074f48d48bdc7 task_step_impl (/usr/src/python/./Modules/_asynciomodule.c:2869:22)
#42  0x000074f48d48c5a2 task_step (/usr/src/python/./Modules/_asynciomodule.c:3188:11)
#43  0x000061335a8a06fe _PyObject_MakeTpCall (/usr/src/python/Objects/call.c:240:18)
#44  0x000061335a82380c _PyObject_VectorcallTstate (/usr/src/python/./Include/internal/pycore_call.h:90:16)
#45  0x000061335a82380c context_run (/usr/src/python/Python/context.c:668:29)
#46  0x000061335a912d7b cfunction_vectorcall_FASTCALL_KEYWORDS (/usr/src/python/Objects/methodobject.c:438:24)
#47  0x000061335a8cb1a9 _PyEval_EvalFrameDefault (/usr/src/python/Python/bytecodes.c:3263:26)
#48  0x000061335a94a4b9 PyEval_EvalCode (/usr/src/python/Python/ceval.c:578:21)
#49  0x000061335a96852c run_eval_code_obj (/usr/src/python/Python/pythonrun.c:1722:9)
#50  0x000061335a9684a4 run_mod (/usr/src/python/Python/pythonrun.c:1743:19)
#51  0x000061335a968061 pyrun_file (/usr/src/python/Python/pythonrun.c:1643:15)
#52  0x000061335a967ea7 _PyRun_SimpleFileObject (/usr/src/python/Python/pythonrun.c:433:13)
#53  0x000061335a967cc7 _PyRun_AnyFileObject (/usr/src/python/Python/pythonrun.c:78:15)
#54  0x000061335a972230 pymain_run_file_obj (/usr/src/python/Modules/main.c:360:15)
#55  0x000061335a972230 pymain_run_file (/usr/src/python/Modules/main.c:379:15)
#56  0x000061335a972230 pymain_run_python (/usr/src/python/Modules/main.c:633:21)
#57  0x000061335a972230 Py_RunMain (/usr/src/python/Modules/main.c:713:5)
#58  0x000061335a971dbd Py_BytesMain (/usr/src/python/Modules/main.c:767:12)
#59  0x000074f48e000e40 __libc_start_main
#60  0x000061335a8ea2d5 _start
```

Co-authored-by: thomas.kowalski <thomas.kowalski@datadoghq.com>
gh-worker-dd-mergequeue-cf854d Bot pushed a commit that referenced this pull request Apr 23, 2026
…llocator (#17664)

## Description

This PR fixes a segmentation fault in the memory allocation profiler that occurs when a hook call races with `memalloc` start/stop operations. The issue arises from concurrent access to the saved allocator struct, which could be partially written while being read, resulting in`NULL` function pointers being dereferenced.  The key indicator in that case is that `#1 0x0000000000000000` frame -- we are trying to execute a null function pointer.

````
Error UnixSignal: Process terminated with SEGV_MAPERR (SIGSEGV)
#0   0x00007ff3c303a8d4  
#1   0x0000000000000000 memalloc_alloc (/go/src/github.com/DataDog/apm-reliability/dd-trace-py/ddtrace/profiling/collector/_memalloc.cpp:68)
#2   0x00007ff39dcb3b20 memalloc_alloc (/go/src/github.com/DataDog/apm-reliability/dd-trace-py/ddtrace/profiling/collector/_memalloc.cpp:68)
#3   0x00007ff39dcb3b20 memalloc_malloc(void*, unsigned long) (/go/src/github.com/DataDog/apm-reliability/dd-trace-py/ddtrace/profiling/collector/_memalloc.cpp:80)
#4   0x00007ff3c3087e1b PyUnicode_New 
#5   0x00007ff3c30889f4  
#6   0x00007ff3c3170c84  
#7   0x00007ff3c316b931  
#8   0x00007ff3c31aaac8  
#9   0x00007ff3c31033ac  
#10  0x00007ff3c310e2a6 PyObject_CallMethodObjArgs 
#11  0x00007ff3c310e46d  
#12  0x00007ff3c31a96c2  
#13  0x00007ff3c3102fd7 PyObject_Vectorcall 
#14  0x00007ff3c32335a2 _PyEval_EvalFrameDefault 
#15  0x00007ff3c323c094  
#16  0x00007ff3c3233dd3 _PyEval_EvalFrameDefault 
#17  0x00007ff3c323c094  
#18  0x00007ff3c30e997d PyObject_CallOneArg 
#19  0x00007ff3c306a480 _PyObject_GenericGetAttrWithDict 
#20  0x00007ff3c30c620d PyObject_GetAttr 
#21  0x00007ff3c32309e7 _PyEval_EvalFrameDefault 
#22  0x00007ff3c323c094  
#23  0x00007ff3c312880e  
#24  0x00007ff3c30e917c _PyObject_MakeTpCall 
#25  0x00007ff3c32335a2 _PyEval_EvalFrameDefault 
#26  0x00007ff3c323c094  
#27  0x00007ff3c312880e  
#28  0x00007ff3c30e917c _PyObject_MakeTpCall 
#29  0x00007ff3c32335a2 _PyEval_EvalFrameDefault 
#30  0x00007ff3c323c094  
#31  0x00007ff3c3233dd3 _PyEval_EvalFrameDefault 
#32  0x00007ff3c323c094  
#33  0x00007ff3c317d0fd  
#34  0x00007ff3c3233dd3 _PyEval_EvalFrameDefault 
#35  0x00007ff3c323c094  
#36  0x00007ff3c3233dd3 _PyEval_EvalFrameDefault 
#37  0x00007ff3c323c094  
#38  0x00007ff3c317d1b5  
#39  0x00007ff3c3102fd7 PyObject_Vectorcall 
#40  0x00007ff3c3232f4a _PyEval_EvalFrameDefault 
#41  0x00007ff3c3240da5  
#42  0x00007ff3c324112d  
#43  0x00007ff3c3233be1 _PyEval_EvalFrameDefault 
#44  0x00007ff3c323c094  
#45  0x00007ff3c317d1b5  
#46  0x00007ff3c3102fd7 PyObject_Vectorcall 
#47  0x00007ff3c3232f4a _PyEval_EvalFrameDefault 
#48  0x00007ff3c323c094  
#49  0x00007ff3c31033ac  
#50  0x00007ff3c310358d PyObject_CallFunctionObjArgs 
#51  0x00007ff3bf7eb91d WraptBoundFunctionWrapper_call (/project/src/wrapt/_wrappers.c:3750)
#52  0x00007ff3c3104055 _PyObject_Call 
#53  0x00007ff3c3233dd3 _PyEval_EvalFrameDefault 
#54  0x00007ff3c323c094  
#55  0x00007ff3c317d23c  
#56  0x00007ff3c3233dd3 _PyEval_EvalFrameDefault 
#57  0x00007ff3c323c094  
#58  0x00007ff3c310416f _PyObject_Call 
#59  0x00007ff3c3233dd3 _PyEval_EvalFrameDefault 
#60  0x00007ff3c3240da5  
#61  0x00007ff3c324112d  
#62  0x00007ff3c3233be1 _PyEval_EvalFrameDefault 
#63  0x00007ff3c323c094  
#64  0x00007ff3c317d1b5  
#65  0x00007ff3c3102fd7 PyObject_Vectorcall 
#66  0x00007ff3c3232f4a _PyEval_EvalFrameDefault 
#67  0x00007ff3c323c094  
#68  0x00007ff3c317d1b5  
#69  0x00007ff3c310416f _PyObject_Call 
#70  0x00007ff3c3233dd3 _PyEval_EvalFrameDefault 
#71  0x00007ff3c323c094  
#72  0x00007ff3c317d1b5  
#73  0x00007ff3c310416f _PyObject_Call 
#74  0x00007ff3c3233dd3 _PyEval_EvalFrameDefault 
#75  0x00007ff3c323c094  
#76  0x00007ff3c31033ac  
#77  0x00007ff3c310358d PyObject_CallFunctionObjArgs 
#78  0x00007ff3bf7eb91d WraptBoundFunctionWrapper_call (/project/src/wrapt/_wrappers.c:3750)
#79  0x00007ff3c30e917c _PyObject_MakeTpCall 
#80  0x00007ff3c32335a2 _PyEval_EvalFrameDefault 
#81  0x00007ff3c323c094  
#82  0x00007ff3c317d518  
#83  0x00007ff3c3155963  
#84  0x00007ff3c315393d  
#85  0x00007ff3c3233dd3 _PyEval_EvalFrameDefault 
#86  0x00007ff3c323c094  
#87  0x00007ff3c317d0fd  
#88  0x00007ff3c3233dd3 _PyEval_EvalFrameDefault 
#89  0x00007ff3c323c094  
#90  0x00007ff3c317d0fd  
#91  0x00007ff3c317d518  
#92  0x00007ff3c3233dd3 _PyEval_EvalFrameDefault 
#93  0x00007ff3c323c094  
#94  0x00007ff3c30e9371 _PyObject_FastCallDictTstate 
#95  0x00007ff3c30e958d _PyObject_Call_Prepend 
#96  0x00007ff3c3109150  
#97  0x00007ff3c3104055 _PyObject_Call 
#98  0x00007ff3c3233dd3 _PyEval_EvalFrameDefault 
#99  0x00007ff3c323c094  
#100 0x00007ff3c30e92f1 _PyObject_FastCallDictTstate 
#101 0x00007ff3c30e958d _PyObject_Call_Prepend 
#102 0x00007ff3c3109150  
#103 0x00007ff3c30e917c _PyObject_MakeTpCall 
#104 0x00007ff3c32335a2 _PyEval_EvalFrameDefault 
#105 0x00007ff3c323c094  
#106 0x00007ff3c30e92f1 _PyObject_FastCallDictTstate 
#107 0x00007ff3c30e958d _PyObject_Call_Prepend 
#108 0x00007ff3c3109150  
#109 0x00007ff3c30e917c _PyObject_MakeTpCall 
#110 0x00007ff3c32335a2 _PyEval_EvalFrameDefault 
#111 0x00007ff3c323c094  
#112 0x00007ff3c30e92f1 _PyObject_FastCallDictTstate 
#113 0x00007ff3c30e958d _PyObject_Call_Prepend 
#114 0x00007ff3c3109150  
#115 0x00007ff3c30e917c _PyObject_MakeTpCall 
#116 0x00007ff3c32335a2 _PyEval_EvalFrameDefault 
#117 0x00007ff3c323c094  
#118 0x00007ff3c30e92f1 _PyObject_FastCallDictTstate 
#119 0x00007ff3c30e958d _PyObject_Call_Prepend 
#120 0x00007ff3c3109150  
#121 0x00007ff3c30e917c _PyObject_MakeTpCall 
#122 0x00007ff3c32335a2 _PyEval_EvalFrameDefault 
#123 0x00007ff3c323c094  
#124 0x00007ff3c30e92f1 _PyObject_FastCallDictTstate 
#125 0x00007ff3c30e958d _PyObject_Call_Prepend 
#126 0x00007ff3c3109150  
#127 0x00007ff3c30e917c _PyObject_MakeTpCall 
#128 0x00007ff3c32335a2 _PyEval_EvalFrameDefault 
#129 0x00007ff3c323c094  
#130 0x00007ff3c30e92f1 _PyObject_FastCallDictTstate 
#131 0x00007ff3c30e958d _PyObject_Call_Prepend 
#132 0x00007ff3c3109150  
#133 0x00007ff3c30e917c _PyObject_MakeTpCall 
#134 0x00007ff3c32335a2 _PyEval_EvalFrameDefault 
#135 0x00007ff3c323c094  
#136 0x00007ff3c30e92f1 _PyObject_FastCallDictTstate 
#137 0x00007ff3c30e958d _PyObject_Call_Prepend 
#138 0x00007ff3c3109150  
#139 0x00007ff3c30e917c _PyObject_MakeTpCall 
#140 0x00007ff3c32335a2 _PyEval_EvalFrameDefault 
#141 0x00007ff3c323c094  
#142 0x00007ff3c30e92f1 _PyObject_FastCallDictTstate 
#143 0x00007ff3c30e958d _PyObject_Call_Prepend 
#144 0x00007ff3c3109150  
#145 0x00007ff3c30e917c _PyObject_MakeTpCall 
#146 0x00007ff3c32335a2 _PyEval_EvalFrameDefault 
#147 0x00007ff3c323c094  
#148 0x00007ff3c30e92f1 _PyObject_FastCallDictTstate 
#149 0x00007ff3c30e958d _PyObject_Call_Prepend 
#150 0x00007ff3c3109150  
#151 0x00007ff3c30e917c _PyObject_MakeTpCall 
#152 0x00007ff3c32335a2 _PyEval_EvalFrameDefault 
#153 0x00007ff3c323c094  
#154 0x00007ff3c30e92f1 _PyObject_FastCallDictTstate 
#155 0x00007ff3c30e958d _PyObject_Call_Prepend 
#156 0x00007ff3c3109150  
#157 0x00007ff3c30e917c _PyObject_MakeTpCall 
#158 0x00007ff3c32335a2 _PyEval_EvalFrameDefault 
#159 0x00007ff3c323c094  
#160 0x00007ff3c30e92f1 _PyObject_FastCallDictTstate 
#161 0x00007ff3c30e958d _PyObject_Call_Prepend 
#162 0x00007ff3c3109150  
#163 0x00007ff3c30e917c _PyObject_MakeTpCall 
#164 0x00007ff3c32335a2 _PyEval_EvalFrameDefault 
#165 0x00007ff3c323c094  
#166 0x00007ff3c30e92f1 _PyObject_FastCallDictTstate 
#167 0x00007ff3c30e958d _PyObject_Call_Prepend 
#168 0x00007ff3c3109150  
#169 0x00007ff3c30e917c _PyObject_MakeTpCall 
#170 0x00007ff3c32335a2 _PyEval_EvalFrameDefault 
#171 0x00007ff3c323c094  
#172 0x00007ff3c30e92f1 _PyObject_FastCallDictTstate 
#173 0x00007ff3c30e958d _PyObject_Call_Prepend 
#174 0x00007ff3c3109150  
#175 0x00007ff3c30e917c _PyObject_MakeTpCall 
#176 0x00007ff3c32335a2 _PyEval_EvalFrameDefault 
#177 0x00007ff3c323c094  
#178 0x00007ff3c30e92f1 _PyObject_FastCallDictTstate 
#179 0x00007ff3c30e958d _PyObject_Call_Prepend 
#180 0x00007ff3c3109150  
#181 0x00007ff3c30e917c _PyObject_MakeTpCall 
#182 0x00007ff3c32335a2 _PyEval_EvalFrameDefault 
#183 0x00007ff3c323c094  
#184 0x00007ff3c30e92f1 _PyObject_FastCallDictTstate 
#185 0x00007ff3c30e958d _PyObject_Call_Prepend 
#186 0x00007ff3c3109150  
#187 0x00007ff3c30e917c _PyObject_MakeTpCall 
#188 0x00007ff3c32335a2 _PyEval_EvalFrameDefault 
#189 0x00007ff3c323c094  
#190 0x00007ff3c3233dd3 _PyEval_EvalFrameDefault 
#191 0x00007ff3c323c094  
#192 0x00007ff3c30e92f1 _PyObject_FastCallDictTstate 
#193 0x00007ff3c30e958d _PyObject_Call_Prepend 
#194 0x00007ff3c3109150  
#195 0x00007ff3c30e917c _PyObject_MakeTpCall 
#196 0x00007ff3c32335a2 _PyEval_EvalFrameDefault 
#197 0x00007ff3c323c094  
#198 0x00007ff3c317d0fd  
#199 0x00007ff3c3233dd3 _PyEval_EvalFrameDefault 
#200 0x00007ff3c323c094  
#201 0x00007ff3c3233dd3 _PyEval_EvalFrameDefault 
#202 0x00007ff3c323c094  
#203 0x00007ff3c3233dd3 _PyEval_EvalFrameDefault 
#204 0x00007ff3c323c094  
#205 0x00007ff3c3233dd3 _PyEval_EvalFrameDefault 
#206 0x00007ff3c323c094  
#207 0x00007ff3c317d23c  
#208 0x00007ff3c31a7ec5  
#209 0x00007ff3c301ac77  
#210 0x00007ff3c357c573  
````

The fix implements two key changes.

1. **Hook functions (`memalloc_alloc`, `memalloc_realloc`)**: Snapshot the allocator struct locally before use and guard indirect function calls with `NULL` checks. This prevents crashes if a partially-written struct is observed during a start/stop race.

2. **Start/stop operations (`memalloc_start`, `memalloc_stop`)**: Use local variables and single assignments when publishing the allocator struct to `global_memalloc_ctx.pymem_allocator_obj`. This ensures concurrent hook calls observe either the old or new struct, never a partially-written intermediate state.

The real root cause is that `PyMem_GetAllocator` is not documented as atomic, and the struct could be read field-by-field while being written to concurrently.  By using local copies and single assignments, we ensure atomicity at the C level and prevent observation of inconsistent state.

Co-authored-by: thomas.kowalski <thomas.kowalski@datadoghq.com>
gh-worker-dd-mergequeue-cf854d Bot pushed a commit that referenced this pull request Apr 23, 2026
## Description

This PR fixes the following crash.

```
Error UnixSignal: Process terminated with SEGV_MAPERR (SIGSEGV)
#0   0x00005a87adf31055 dictkeys_get_index (/usr/src/python/Objects/dictobject.c:344:13)
#1   0x00005a87adf31055 unicodekeys_lookup_generic (/usr/src/python/Objects/dictobject.c:876:14)
#2   0x00005a87adf31055 _Py_dict_lookup (/usr/src/python/Objects/dictobject.c:1056:18)
#3   0x00005a87adf31055 PyDict_GetItemWithError (/usr/src/python/Objects/dictobject.c:1789:10)
#4   0x00007b2e6fc1a8e0 __pyx_pw_7ddtrace_8internal_9telemetry_18metrics_namespaces_15MetricNamespace_5add_metric
#5   0x00005a87ae00c955 _PyObject_VectorcallTstate (/usr/src/python/./Include/internal/pycore_call.h:92:11)
#6   0x00005a87ae00c955 PyObject_Vectorcall (/usr/src/python/Objects/call.c:299:12)
#7   0x00005a87ae05ee1d _PyEval_EvalFrameDefault (/usr/src/python/Python/ceval.c:4760:23)
#8   0x00005a87ae05e060 _PyEval_EvalFrame (/usr/src/python/./Include/internal/pycore_ceval.h:73:16)
#9   0x00005a87ae05e060 _PyEval_Vector (/usr/src/python/Python/ceval.c:6425:24)
#10  0x00005a87ae00d587 PyObject_Call
#11  0x00005a87ae061fd8 do_call_core (/usr/src/python/Python/ceval.c:7343:12)
#12  0x00005a87ae061fd8 _PyEval_EvalFrameDefault (/usr/src/python/Python/ceval.c:5367:22)
#13  0x00005a87ae05e060 _PyEval_EvalFrame (/usr/src/python/./Include/internal/pycore_ceval.h:73:16)
#14  0x00005a87ae05e060 _PyEval_Vector (/usr/src/python/Python/ceval.c:6425:24)
#15  0x00005a87ae00e0ba _PyObject_VectorcallTstate (/usr/src/python/./Include/internal/pycore_call.h:92:11)
#16  0x00005a87ae00e0ba method_vectorcall (/usr/src/python/Objects/classobject.c:59:18)
#17  0x00005a87ae00c955 _PyObject_VectorcallTstate (/usr/src/python/./Include/internal/pycore_call.h:92:11)
#18  0x00005a87ae00c955 PyObject_Vectorcall (/usr/src/python/Objects/call.c:299:12)
#19  0x00005a87ae05ee1d _PyEval_EvalFrameDefault (/usr/src/python/Python/ceval.c:4760:23)
#20  0x00005a87ae05e060 _PyEval_EvalFrame (/usr/src/python/./Include/internal/pycore_ceval.h:73:16)
#21  0x00005a87ae05e060 _PyEval_Vector (/usr/src/python/Python/ceval.c:6425:24)
#22  0x00005a87ae00d02f _PyFunction_Vectorcall (/usr/src/python/Objects/call.c:393:16)
#23  0x00005a87ae00d02f _PyObject_FastCallDictTstate (/usr/src/python/Objects/call.c:141:15)
#24  0x00005a87ae00d02f _PyObject_Call_Prepend (/usr/src/python/Objects/call.c:482:24)
#25  0x00005a87ae0bafd9 slot_tp_call (/usr/src/python/Objects/typeobject.c:7623:15)
#26  0x00005a87ae00c4d9 _PyObject_MakeTpCall (/usr/src/python/Objects/call.c:214:18)
#27  0x00005a87ae05ee1d _PyEval_EvalFrameDefault (/usr/src/python/Python/ceval.c:4760:23)
#28  0x00005a87ae05e060 _PyEval_EvalFrame (/usr/src/python/./Include/internal/pycore_ceval.h:73:16)
#29  0x00005a87ae05e060 _PyEval_Vector (/usr/src/python/Python/ceval.c:6425:24)
#30  0x00005a87ae00d02f _PyFunction_Vectorcall (/usr/src/python/Objects/call.c:393:16)
#31  0x00005a87ae00d02f _PyObject_FastCallDictTstate (/usr/src/python/Objects/call.c:141:15)
#32  0x00005a87ae00d02f _PyObject_Call_Prepend (/usr/src/python/Objects/call.c:482:24)
#33  0x00005a87ae041f7b slot_tp_init (/usr/src/python/Objects/typeobject.c:7854:15)
#34  0x00005a87ae040731 type_call (/usr/src/python/Objects/typeobject.c:1103:19)
#35  0x00005a87ae00c4d9 _PyObject_MakeTpCall (/usr/src/python/Objects/call.c:214:18)
#36  0x00005a87ae05ee1d _PyEval_EvalFrameDefault (/usr/src/python/Python/ceval.c:4760:23)
#37  0x00005a87ae05e060 _PyEval_EvalFrame (/usr/src/python/./Include/internal/pycore_ceval.h:73:16)
#38  0x00005a87ae05e060 _PyEval_Vector (/usr/src/python/Python/ceval.c:6425:24)
#39  0x00005a87ae00e134 _PyObject_VectorcallTstate (/usr/src/python/./Include/internal/pycore_call.h:92:11)
#40  0x00005a87ae00e134 method_vectorcall (/usr/src/python/Objects/classobject.c:89:18)
#41  0x00005a87ae00d587 PyObject_Call
#42  0x00005a87ae061fd8 do_call_core (/usr/src/python/Python/ceval.c:7343:12)
#43  0x00005a87ae061fd8 _PyEval_EvalFrameDefault (/usr/src/python/Python/ceval.c:5367:22)
#44  0x00005a87ae05e060 _PyEval_EvalFrame (/usr/src/python/./Include/internal/pycore_ceval.h:73:16)
#45  0x00005a87ae05e060 _PyEval_Vector (/usr/src/python/Python/ceval.c:6425:24)
#46  0x00005a87ae00d587 PyObject_Call
#47  0x00005a87ae061fd8 do_call_core (/usr/src/python/Python/ceval.c:7343:12)
#48  0x00005a87ae061fd8 _PyEval_EvalFrameDefault (/usr/src/python/Python/ceval.c:5367:22)
#49  0x00005a87ae05e060 _PyEval_EvalFrame (/usr/src/python/./Include/internal/pycore_ceval.h:73:16)
#50  0x00005a87ae05e060 _PyEval_Vector (/usr/src/python/Python/ceval.c:6425:24)
#51  0x00005a87ae00e04b _PyObject_VectorcallTstate (/usr/src/python/./Include/internal/pycore_call.h:92:11)
#52  0x00005a87ae00e04b method_vectorcall (/usr/src/python/Objects/classobject.c:67:20)
#53  0x00005a87ae00d587 PyObject_Call
#54  0x00005a87ae10e9b3 thread_run (/usr/src/python/./Modules/_threadmodule.c:1124:21)
#55  0x00005a87ae0f1098 pythread_wrapper (/usr/src/python/Python/thread_pthread.h:241:5)
#56  0x00007b2e71c49609 start_thread
#57  0x00007b2e71a14353 clone
```

Co-authored-by: brettlangdon <brett.langdon@datadoghq.com>
emmettbutler pushed a commit that referenced this pull request Apr 24, 2026
…llocator (#17664)

## Description

This PR fixes a segmentation fault in the memory allocation profiler that occurs when a hook call races with `memalloc` start/stop operations. The issue arises from concurrent access to the saved allocator struct, which could be partially written while being read, resulting in`NULL` function pointers being dereferenced.  The key indicator in that case is that `#1 0x0000000000000000` frame -- we are trying to execute a null function pointer.

````
Error UnixSignal: Process terminated with SEGV_MAPERR (SIGSEGV)
#0   0x00007ff3c303a8d4  
#1   0x0000000000000000 memalloc_alloc (/go/src/github.com/DataDog/apm-reliability/dd-trace-py/ddtrace/profiling/collector/_memalloc.cpp:68)
#2   0x00007ff39dcb3b20 memalloc_alloc (/go/src/github.com/DataDog/apm-reliability/dd-trace-py/ddtrace/profiling/collector/_memalloc.cpp:68)
#3   0x00007ff39dcb3b20 memalloc_malloc(void*, unsigned long) (/go/src/github.com/DataDog/apm-reliability/dd-trace-py/ddtrace/profiling/collector/_memalloc.cpp:80)
#4   0x00007ff3c3087e1b PyUnicode_New 
#5   0x00007ff3c30889f4  
#6   0x00007ff3c3170c84  
#7   0x00007ff3c316b931  
#8   0x00007ff3c31aaac8  
#9   0x00007ff3c31033ac  
#10  0x00007ff3c310e2a6 PyObject_CallMethodObjArgs 
#11  0x00007ff3c310e46d  
#12  0x00007ff3c31a96c2  
#13  0x00007ff3c3102fd7 PyObject_Vectorcall 
#14  0x00007ff3c32335a2 _PyEval_EvalFrameDefault 
#15  0x00007ff3c323c094  
#16  0x00007ff3c3233dd3 _PyEval_EvalFrameDefault 
#17  0x00007ff3c323c094  
#18  0x00007ff3c30e997d PyObject_CallOneArg 
#19  0x00007ff3c306a480 _PyObject_GenericGetAttrWithDict 
#20  0x00007ff3c30c620d PyObject_GetAttr 
#21  0x00007ff3c32309e7 _PyEval_EvalFrameDefault 
#22  0x00007ff3c323c094  
#23  0x00007ff3c312880e  
#24  0x00007ff3c30e917c _PyObject_MakeTpCall 
#25  0x00007ff3c32335a2 _PyEval_EvalFrameDefault 
#26  0x00007ff3c323c094  
#27  0x00007ff3c312880e  
#28  0x00007ff3c30e917c _PyObject_MakeTpCall 
#29  0x00007ff3c32335a2 _PyEval_EvalFrameDefault 
#30  0x00007ff3c323c094  
#31  0x00007ff3c3233dd3 _PyEval_EvalFrameDefault 
#32  0x00007ff3c323c094  
#33  0x00007ff3c317d0fd  
#34  0x00007ff3c3233dd3 _PyEval_EvalFrameDefault 
#35  0x00007ff3c323c094  
#36  0x00007ff3c3233dd3 _PyEval_EvalFrameDefault 
#37  0x00007ff3c323c094  
#38  0x00007ff3c317d1b5  
#39  0x00007ff3c3102fd7 PyObject_Vectorcall 
#40  0x00007ff3c3232f4a _PyEval_EvalFrameDefault 
#41  0x00007ff3c3240da5  
#42  0x00007ff3c324112d  
#43  0x00007ff3c3233be1 _PyEval_EvalFrameDefault 
#44  0x00007ff3c323c094  
#45  0x00007ff3c317d1b5  
#46  0x00007ff3c3102fd7 PyObject_Vectorcall 
#47  0x00007ff3c3232f4a _PyEval_EvalFrameDefault 
#48  0x00007ff3c323c094  
#49  0x00007ff3c31033ac  
#50  0x00007ff3c310358d PyObject_CallFunctionObjArgs 
#51  0x00007ff3bf7eb91d WraptBoundFunctionWrapper_call (/project/src/wrapt/_wrappers.c:3750)
#52  0x00007ff3c3104055 _PyObject_Call 
#53  0x00007ff3c3233dd3 _PyEval_EvalFrameDefault 
#54  0x00007ff3c323c094  
#55  0x00007ff3c317d23c  
#56  0x00007ff3c3233dd3 _PyEval_EvalFrameDefault 
#57  0x00007ff3c323c094  
#58  0x00007ff3c310416f _PyObject_Call 
#59  0x00007ff3c3233dd3 _PyEval_EvalFrameDefault 
#60  0x00007ff3c3240da5  
#61  0x00007ff3c324112d  
#62  0x00007ff3c3233be1 _PyEval_EvalFrameDefault 
#63  0x00007ff3c323c094  
#64  0x00007ff3c317d1b5  
#65  0x00007ff3c3102fd7 PyObject_Vectorcall 
#66  0x00007ff3c3232f4a _PyEval_EvalFrameDefault 
#67  0x00007ff3c323c094  
#68  0x00007ff3c317d1b5  
#69  0x00007ff3c310416f _PyObject_Call 
#70  0x00007ff3c3233dd3 _PyEval_EvalFrameDefault 
#71  0x00007ff3c323c094  
#72  0x00007ff3c317d1b5  
#73  0x00007ff3c310416f _PyObject_Call 
#74  0x00007ff3c3233dd3 _PyEval_EvalFrameDefault 
#75  0x00007ff3c323c094  
#76  0x00007ff3c31033ac  
#77  0x00007ff3c310358d PyObject_CallFunctionObjArgs 
#78  0x00007ff3bf7eb91d WraptBoundFunctionWrapper_call (/project/src/wrapt/_wrappers.c:3750)
#79  0x00007ff3c30e917c _PyObject_MakeTpCall 
#80  0x00007ff3c32335a2 _PyEval_EvalFrameDefault 
#81  0x00007ff3c323c094  
#82  0x00007ff3c317d518  
#83  0x00007ff3c3155963  
#84  0x00007ff3c315393d  
#85  0x00007ff3c3233dd3 _PyEval_EvalFrameDefault 
#86  0x00007ff3c323c094  
#87  0x00007ff3c317d0fd  
#88  0x00007ff3c3233dd3 _PyEval_EvalFrameDefault 
#89  0x00007ff3c323c094  
#90  0x00007ff3c317d0fd  
#91  0x00007ff3c317d518  
#92  0x00007ff3c3233dd3 _PyEval_EvalFrameDefault 
#93  0x00007ff3c323c094  
#94  0x00007ff3c30e9371 _PyObject_FastCallDictTstate 
#95  0x00007ff3c30e958d _PyObject_Call_Prepend 
#96  0x00007ff3c3109150  
#97  0x00007ff3c3104055 _PyObject_Call 
#98  0x00007ff3c3233dd3 _PyEval_EvalFrameDefault 
#99  0x00007ff3c323c094  
#100 0x00007ff3c30e92f1 _PyObject_FastCallDictTstate 
#101 0x00007ff3c30e958d _PyObject_Call_Prepend 
#102 0x00007ff3c3109150  
#103 0x00007ff3c30e917c _PyObject_MakeTpCall 
#104 0x00007ff3c32335a2 _PyEval_EvalFrameDefault 
#105 0x00007ff3c323c094  
#106 0x00007ff3c30e92f1 _PyObject_FastCallDictTstate 
#107 0x00007ff3c30e958d _PyObject_Call_Prepend 
#108 0x00007ff3c3109150  
#109 0x00007ff3c30e917c _PyObject_MakeTpCall 
#110 0x00007ff3c32335a2 _PyEval_EvalFrameDefault 
#111 0x00007ff3c323c094  
#112 0x00007ff3c30e92f1 _PyObject_FastCallDictTstate 
#113 0x00007ff3c30e958d _PyObject_Call_Prepend 
#114 0x00007ff3c3109150  
#115 0x00007ff3c30e917c _PyObject_MakeTpCall 
#116 0x00007ff3c32335a2 _PyEval_EvalFrameDefault 
#117 0x00007ff3c323c094  
#118 0x00007ff3c30e92f1 _PyObject_FastCallDictTstate 
#119 0x00007ff3c30e958d _PyObject_Call_Prepend 
#120 0x00007ff3c3109150  
#121 0x00007ff3c30e917c _PyObject_MakeTpCall 
#122 0x00007ff3c32335a2 _PyEval_EvalFrameDefault 
#123 0x00007ff3c323c094  
#124 0x00007ff3c30e92f1 _PyObject_FastCallDictTstate 
#125 0x00007ff3c30e958d _PyObject_Call_Prepend 
#126 0x00007ff3c3109150  
#127 0x00007ff3c30e917c _PyObject_MakeTpCall 
#128 0x00007ff3c32335a2 _PyEval_EvalFrameDefault 
#129 0x00007ff3c323c094  
#130 0x00007ff3c30e92f1 _PyObject_FastCallDictTstate 
#131 0x00007ff3c30e958d _PyObject_Call_Prepend 
#132 0x00007ff3c3109150  
#133 0x00007ff3c30e917c _PyObject_MakeTpCall 
#134 0x00007ff3c32335a2 _PyEval_EvalFrameDefault 
#135 0x00007ff3c323c094  
#136 0x00007ff3c30e92f1 _PyObject_FastCallDictTstate 
#137 0x00007ff3c30e958d _PyObject_Call_Prepend 
#138 0x00007ff3c3109150  
#139 0x00007ff3c30e917c _PyObject_MakeTpCall 
#140 0x00007ff3c32335a2 _PyEval_EvalFrameDefault 
#141 0x00007ff3c323c094  
#142 0x00007ff3c30e92f1 _PyObject_FastCallDictTstate 
#143 0x00007ff3c30e958d _PyObject_Call_Prepend 
#144 0x00007ff3c3109150  
#145 0x00007ff3c30e917c _PyObject_MakeTpCall 
#146 0x00007ff3c32335a2 _PyEval_EvalFrameDefault 
#147 0x00007ff3c323c094  
#148 0x00007ff3c30e92f1 _PyObject_FastCallDictTstate 
#149 0x00007ff3c30e958d _PyObject_Call_Prepend 
#150 0x00007ff3c3109150  
#151 0x00007ff3c30e917c _PyObject_MakeTpCall 
#152 0x00007ff3c32335a2 _PyEval_EvalFrameDefault 
#153 0x00007ff3c323c094  
#154 0x00007ff3c30e92f1 _PyObject_FastCallDictTstate 
#155 0x00007ff3c30e958d _PyObject_Call_Prepend 
#156 0x00007ff3c3109150  
#157 0x00007ff3c30e917c _PyObject_MakeTpCall 
#158 0x00007ff3c32335a2 _PyEval_EvalFrameDefault 
#159 0x00007ff3c323c094  
#160 0x00007ff3c30e92f1 _PyObject_FastCallDictTstate 
#161 0x00007ff3c30e958d _PyObject_Call_Prepend 
#162 0x00007ff3c3109150  
#163 0x00007ff3c30e917c _PyObject_MakeTpCall 
#164 0x00007ff3c32335a2 _PyEval_EvalFrameDefault 
#165 0x00007ff3c323c094  
#166 0x00007ff3c30e92f1 _PyObject_FastCallDictTstate 
#167 0x00007ff3c30e958d _PyObject_Call_Prepend 
#168 0x00007ff3c3109150  
#169 0x00007ff3c30e917c _PyObject_MakeTpCall 
#170 0x00007ff3c32335a2 _PyEval_EvalFrameDefault 
#171 0x00007ff3c323c094  
#172 0x00007ff3c30e92f1 _PyObject_FastCallDictTstate 
#173 0x00007ff3c30e958d _PyObject_Call_Prepend 
#174 0x00007ff3c3109150  
#175 0x00007ff3c30e917c _PyObject_MakeTpCall 
#176 0x00007ff3c32335a2 _PyEval_EvalFrameDefault 
#177 0x00007ff3c323c094  
#178 0x00007ff3c30e92f1 _PyObject_FastCallDictTstate 
#179 0x00007ff3c30e958d _PyObject_Call_Prepend 
#180 0x00007ff3c3109150  
#181 0x00007ff3c30e917c _PyObject_MakeTpCall 
#182 0x00007ff3c32335a2 _PyEval_EvalFrameDefault 
#183 0x00007ff3c323c094  
#184 0x00007ff3c30e92f1 _PyObject_FastCallDictTstate 
#185 0x00007ff3c30e958d _PyObject_Call_Prepend 
#186 0x00007ff3c3109150  
#187 0x00007ff3c30e917c _PyObject_MakeTpCall 
#188 0x00007ff3c32335a2 _PyEval_EvalFrameDefault 
#189 0x00007ff3c323c094  
#190 0x00007ff3c3233dd3 _PyEval_EvalFrameDefault 
#191 0x00007ff3c323c094  
#192 0x00007ff3c30e92f1 _PyObject_FastCallDictTstate 
#193 0x00007ff3c30e958d _PyObject_Call_Prepend 
#194 0x00007ff3c3109150  
#195 0x00007ff3c30e917c _PyObject_MakeTpCall 
#196 0x00007ff3c32335a2 _PyEval_EvalFrameDefault 
#197 0x00007ff3c323c094  
#198 0x00007ff3c317d0fd  
#199 0x00007ff3c3233dd3 _PyEval_EvalFrameDefault 
#200 0x00007ff3c323c094  
#201 0x00007ff3c3233dd3 _PyEval_EvalFrameDefault 
#202 0x00007ff3c323c094  
#203 0x00007ff3c3233dd3 _PyEval_EvalFrameDefault 
#204 0x00007ff3c323c094  
#205 0x00007ff3c3233dd3 _PyEval_EvalFrameDefault 
#206 0x00007ff3c323c094  
#207 0x00007ff3c317d23c  
#208 0x00007ff3c31a7ec5  
#209 0x00007ff3c301ac77  
#210 0x00007ff3c357c573  
````

The fix implements two key changes.

1. **Hook functions (`memalloc_alloc`, `memalloc_realloc`)**: Snapshot the allocator struct locally before use and guard indirect function calls with `NULL` checks. This prevents crashes if a partially-written struct is observed during a start/stop race.

2. **Start/stop operations (`memalloc_start`, `memalloc_stop`)**: Use local variables and single assignments when publishing the allocator struct to `global_memalloc_ctx.pymem_allocator_obj`. This ensures concurrent hook calls observe either the old or new struct, never a partially-written intermediate state.

The real root cause is that `PyMem_GetAllocator` is not documented as atomic, and the struct could be read field-by-field while being written to concurrently.  By using local copies and single assignments, we ensure atomicity at the C level and prevent observation of inconsistent state.

Co-authored-by: thomas.kowalski <thomas.kowalski@datadoghq.com>
emmettbutler pushed a commit that referenced this pull request Apr 24, 2026
## Description

This PR fixes the following crash.

```
Error UnixSignal: Process terminated with SEGV_MAPERR (SIGSEGV)
#0   0x00005a87adf31055 dictkeys_get_index (/usr/src/python/Objects/dictobject.c:344:13)
#1   0x00005a87adf31055 unicodekeys_lookup_generic (/usr/src/python/Objects/dictobject.c:876:14)
#2   0x00005a87adf31055 _Py_dict_lookup (/usr/src/python/Objects/dictobject.c:1056:18)
#3   0x00005a87adf31055 PyDict_GetItemWithError (/usr/src/python/Objects/dictobject.c:1789:10)
#4   0x00007b2e6fc1a8e0 __pyx_pw_7ddtrace_8internal_9telemetry_18metrics_namespaces_15MetricNamespace_5add_metric
#5   0x00005a87ae00c955 _PyObject_VectorcallTstate (/usr/src/python/./Include/internal/pycore_call.h:92:11)
#6   0x00005a87ae00c955 PyObject_Vectorcall (/usr/src/python/Objects/call.c:299:12)
#7   0x00005a87ae05ee1d _PyEval_EvalFrameDefault (/usr/src/python/Python/ceval.c:4760:23)
#8   0x00005a87ae05e060 _PyEval_EvalFrame (/usr/src/python/./Include/internal/pycore_ceval.h:73:16)
#9   0x00005a87ae05e060 _PyEval_Vector (/usr/src/python/Python/ceval.c:6425:24)
#10  0x00005a87ae00d587 PyObject_Call
#11  0x00005a87ae061fd8 do_call_core (/usr/src/python/Python/ceval.c:7343:12)
#12  0x00005a87ae061fd8 _PyEval_EvalFrameDefault (/usr/src/python/Python/ceval.c:5367:22)
#13  0x00005a87ae05e060 _PyEval_EvalFrame (/usr/src/python/./Include/internal/pycore_ceval.h:73:16)
#14  0x00005a87ae05e060 _PyEval_Vector (/usr/src/python/Python/ceval.c:6425:24)
#15  0x00005a87ae00e0ba _PyObject_VectorcallTstate (/usr/src/python/./Include/internal/pycore_call.h:92:11)
#16  0x00005a87ae00e0ba method_vectorcall (/usr/src/python/Objects/classobject.c:59:18)
#17  0x00005a87ae00c955 _PyObject_VectorcallTstate (/usr/src/python/./Include/internal/pycore_call.h:92:11)
#18  0x00005a87ae00c955 PyObject_Vectorcall (/usr/src/python/Objects/call.c:299:12)
#19  0x00005a87ae05ee1d _PyEval_EvalFrameDefault (/usr/src/python/Python/ceval.c:4760:23)
#20  0x00005a87ae05e060 _PyEval_EvalFrame (/usr/src/python/./Include/internal/pycore_ceval.h:73:16)
#21  0x00005a87ae05e060 _PyEval_Vector (/usr/src/python/Python/ceval.c:6425:24)
#22  0x00005a87ae00d02f _PyFunction_Vectorcall (/usr/src/python/Objects/call.c:393:16)
#23  0x00005a87ae00d02f _PyObject_FastCallDictTstate (/usr/src/python/Objects/call.c:141:15)
#24  0x00005a87ae00d02f _PyObject_Call_Prepend (/usr/src/python/Objects/call.c:482:24)
#25  0x00005a87ae0bafd9 slot_tp_call (/usr/src/python/Objects/typeobject.c:7623:15)
#26  0x00005a87ae00c4d9 _PyObject_MakeTpCall (/usr/src/python/Objects/call.c:214:18)
#27  0x00005a87ae05ee1d _PyEval_EvalFrameDefault (/usr/src/python/Python/ceval.c:4760:23)
#28  0x00005a87ae05e060 _PyEval_EvalFrame (/usr/src/python/./Include/internal/pycore_ceval.h:73:16)
#29  0x00005a87ae05e060 _PyEval_Vector (/usr/src/python/Python/ceval.c:6425:24)
#30  0x00005a87ae00d02f _PyFunction_Vectorcall (/usr/src/python/Objects/call.c:393:16)
#31  0x00005a87ae00d02f _PyObject_FastCallDictTstate (/usr/src/python/Objects/call.c:141:15)
#32  0x00005a87ae00d02f _PyObject_Call_Prepend (/usr/src/python/Objects/call.c:482:24)
#33  0x00005a87ae041f7b slot_tp_init (/usr/src/python/Objects/typeobject.c:7854:15)
#34  0x00005a87ae040731 type_call (/usr/src/python/Objects/typeobject.c:1103:19)
#35  0x00005a87ae00c4d9 _PyObject_MakeTpCall (/usr/src/python/Objects/call.c:214:18)
#36  0x00005a87ae05ee1d _PyEval_EvalFrameDefault (/usr/src/python/Python/ceval.c:4760:23)
#37  0x00005a87ae05e060 _PyEval_EvalFrame (/usr/src/python/./Include/internal/pycore_ceval.h:73:16)
#38  0x00005a87ae05e060 _PyEval_Vector (/usr/src/python/Python/ceval.c:6425:24)
#39  0x00005a87ae00e134 _PyObject_VectorcallTstate (/usr/src/python/./Include/internal/pycore_call.h:92:11)
#40  0x00005a87ae00e134 method_vectorcall (/usr/src/python/Objects/classobject.c:89:18)
#41  0x00005a87ae00d587 PyObject_Call
#42  0x00005a87ae061fd8 do_call_core (/usr/src/python/Python/ceval.c:7343:12)
#43  0x00005a87ae061fd8 _PyEval_EvalFrameDefault (/usr/src/python/Python/ceval.c:5367:22)
#44  0x00005a87ae05e060 _PyEval_EvalFrame (/usr/src/python/./Include/internal/pycore_ceval.h:73:16)
#45  0x00005a87ae05e060 _PyEval_Vector (/usr/src/python/Python/ceval.c:6425:24)
#46  0x00005a87ae00d587 PyObject_Call
#47  0x00005a87ae061fd8 do_call_core (/usr/src/python/Python/ceval.c:7343:12)
#48  0x00005a87ae061fd8 _PyEval_EvalFrameDefault (/usr/src/python/Python/ceval.c:5367:22)
#49  0x00005a87ae05e060 _PyEval_EvalFrame (/usr/src/python/./Include/internal/pycore_ceval.h:73:16)
#50  0x00005a87ae05e060 _PyEval_Vector (/usr/src/python/Python/ceval.c:6425:24)
#51  0x00005a87ae00e04b _PyObject_VectorcallTstate (/usr/src/python/./Include/internal/pycore_call.h:92:11)
#52  0x00005a87ae00e04b method_vectorcall (/usr/src/python/Objects/classobject.c:67:20)
#53  0x00005a87ae00d587 PyObject_Call
#54  0x00005a87ae10e9b3 thread_run (/usr/src/python/./Modules/_threadmodule.c:1124:21)
#55  0x00005a87ae0f1098 pythread_wrapper (/usr/src/python/Python/thread_pthread.h:241:5)
#56  0x00007b2e71c49609 start_thread
#57  0x00007b2e71a14353 clone
```

Co-authored-by: brettlangdon <brett.langdon@datadoghq.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants