Skip to content

Commit 2e2cb67

Browse files
authored
chore(iast): avoid exception when no relevant frame is found (#13346)
Follow up to #13272: - Avoid an exception when no relevant frame is found, return a tuple of `None` objects instead. This was a regression in #13272.
1 parent 6810265 commit 2e2cb67

File tree

3 files changed

+51
-0
lines changed

3 files changed

+51
-0
lines changed

ddtrace/appsec/_iast/_stacktrace.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,9 @@ get_file_and_line(PyObject* Py_UNUSED(module), PyObject* Py_UNUSED(args))
310310

311311
exit:
312312
FRAME_XDECREF(frame);
313+
if (!result) {
314+
result = PyTuple_Pack(4, Py_None, Py_None, Py_None, Py_None);
315+
}
313316
in_stacktrace = 0;
314317
return result;
315318
}

ddtrace/appsec/_iast/taint_sinks/_base.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,8 @@ def _compute_file_line(cls) -> Tuple[Optional[str], Optional[int], Optional[str]
139139
return file_name, line_number, function_name, class_name
140140

141141
file_name, line_number, function_name, class_name = frame_info
142+
if not file_name:
143+
return None, None, None, None
142144

143145
file_name = cls._rel_path(file_name)
144146
if not file_name:
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#!/usr/bin/env python3
2+
3+
import sys
4+
5+
import pytest
6+
7+
from ddtrace.appsec._iast._stacktrace import get_info_frame
8+
9+
10+
def test_stacktrace():
11+
file, line, function, class_ = get_info_frame()
12+
import traceback
13+
14+
traceback.print_stack()
15+
assert file is not None
16+
assert file.endswith("test_stacktrace.py")
17+
assert line is not None
18+
assert function == "test_stacktrace"
19+
assert class_ is not None
20+
21+
22+
async def test_stacktrace_async():
23+
async def _inner():
24+
return get_info_frame()
25+
26+
file, line, function, class_ = await _inner()
27+
assert file is not None
28+
assert file.endswith("test_stacktrace.py")
29+
assert line is not None
30+
assert function == "_inner"
31+
assert class_ is not None
32+
33+
34+
@pytest.mark.skipif(sys.version_info < (3, 9, 0), reason="Test compatible with Python 3.9+")
35+
async def test_stacktrace_async_no_relevant_frame():
36+
"""
37+
In the absence of any non-ddtrace and non-stdlib frame in the stacktrace, no frame is returned.
38+
(And no exception is raised).
39+
"""
40+
import asyncio
41+
42+
file, line, function, class_ = await asyncio.to_thread(get_info_frame)
43+
assert file is None
44+
assert line is None
45+
assert function is None
46+
assert class_ is None

0 commit comments

Comments
 (0)