Skip to content

Commit 78a8fa3

Browse files
authored
refactor(appsec): move _stacktrace from _iast to _shared package (#17329)
## Summary - Move the native `_stacktrace` C extension from `ddtrace/appsec/_iast/` to `ddtrace/appsec/_shared/` so it can be reused by both IAST and SCA without creating a dependency from SCA into IAST internals. - Update all imports, build configuration (`setup.py`), and test references to use the new `ddtrace.appsec._shared._stacktrace` path. Split out from #17156 to keep PRs incremental and reviewable. > **Important:** Before merging this PR, DataDog/datadog-lambda-python#761 must be merged first, since `datadog-lambda-python` imports `ddtrace.appsec._iast._stacktrace` and needs to be updated to the new path. ## Test plan - [ ] Existing IAST stacktrace tests pass (`tests/appsec/iast/test_stacktrace.py`) - [ ] IAST memcheck tests pass (`tests/appsec/iast_memcheck/test_iast_mem_check.py`) - [ ] Architecture loading module test passes (`tests/appsec/architectures/test_appsec_loading_modules.py`) - [ ] Serverless import test passes (`tests/internal/test_serverless.py`) - [ ] Native C extension builds correctly from new path 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: alberto.vara <alberto.vara@datadoghq.com>
1 parent 621c7b1 commit 78a8fa3

13 files changed

Lines changed: 27 additions & 39 deletions

File tree

ddtrace/appsec/_iast/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ def enable_iast_propagation():
199199
from ddtrace.appsec._iast._ast.ast_patching import _should_iast_patch
200200
from ddtrace.appsec._iast._loader import _exec_iast_patched_module
201201
from ddtrace.appsec._iast._taint_tracking import initialize_native_state
202+
from ddtrace.appsec._shared._stacktrace import get_info_frame # noqa: F401
202203

203204
global _iast_propagation_enabled
204205
if _iast_propagation_enabled:

ddtrace/appsec/_iast/_stacktrace.pyi

Lines changed: 0 additions & 1 deletion
This file was deleted.

ddtrace/appsec/_patch_utils.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@
1515

1616
log = get_logger(__name__)
1717

18+
# Lazy-cached reference to avoid loading _stacktrace (a C extension used only
19+
# by IAST) when _patch_utils is imported by non-IAST code paths.
20+
_get_info_frame = None
21+
1822
# Cached paths for relativizing file paths (computed once at import time).
1923
_CWD = os.path.abspath(os.getcwd())
2024
_PURELIB_PATH = sysconfig.get_path("purelib") or ""
@@ -52,12 +56,12 @@ def get_caller_frame_info() -> tuple:
5256
5357
Returns (None, None, None, None) when no relevant frame is found.
5458
"""
55-
try:
56-
from ddtrace.appsec._iast._stacktrace import get_info_frame
57-
except ImportError:
58-
return None, None, None, None
59+
global _get_info_frame
60+
if _get_info_frame is None:
61+
from ddtrace.appsec._shared._stacktrace import get_info_frame
5962

60-
frame_info = get_info_frame()
63+
_get_info_frame = get_info_frame
64+
frame_info = _get_info_frame()
6165
if not frame_info or frame_info[0] in ("", -1, None):
6266
return None, None, None, None
6367

ddtrace/appsec/_shared/__init__.py

Whitespace-only changes.
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -359,7 +359,7 @@ static PyMethodDef StacktraceMethods[] = { { "get_info_frame",
359359
{ NULL, NULL, 0, NULL } };
360360

361361
static struct PyModuleDef stacktrace = { PyModuleDef_HEAD_INIT,
362-
"ddtrace.appsec._iast._stacktrace",
362+
"ddtrace.appsec._shared._stacktrace",
363363
"stacktrace module",
364364
-1,
365365
StacktraceMethods };
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from typing import Optional
2+
3+
def get_info_frame() -> tuple[Optional[str], Optional[int], Optional[str], Optional[str]]: ...

setup.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1275,9 +1275,9 @@ def get_exts_for(name):
12751275
if platform.system() not in ("Windows", ""):
12761276
ext_modules.append(
12771277
Extension(
1278-
"ddtrace.appsec._iast._stacktrace",
1278+
"ddtrace.appsec._shared._stacktrace",
12791279
sources=[
1280-
"ddtrace/appsec/_iast/_stacktrace.c",
1280+
"ddtrace/appsec/_shared/_stacktrace.c",
12811281
],
12821282
extra_compile_args=extra_compile_args + debug_compile_args + fast_build_args,
12831283
)

tests/appsec/architectures/test_appsec_loading_modules.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
MODULE_IAST_ONLY = [
1818
"ddtrace.appsec._iast",
1919
"ddtrace.appsec._iast._taint_tracking._native",
20+
"ddtrace.appsec._shared._stacktrace",
2021
]
2122

2223

tests/appsec/iast/test_stacktrace.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#!/usr/bin/env python3
22

3-
from ddtrace.appsec._iast._stacktrace import get_info_frame
3+
from ddtrace.appsec._shared._stacktrace import get_info_frame
44

55

66
def test_stacktrace():

tests/appsec/iast_memcheck/fixtures/stacktrace.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import os
22

3-
from ddtrace.appsec._iast._stacktrace import get_info_frame
3+
from ddtrace.appsec._shared._stacktrace import get_info_frame
44

55

66
CWD = os.path.abspath(os.getcwd())

0 commit comments

Comments
 (0)