Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 1 addition & 12 deletions ddtrace/profiling/collector/_memalloc_tb.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@
/* A string containing "<unknown>" just in case we can't store the real function
* or file name. */
static PyObject* unknown_name = NULL;
/* A string containing "" */
static PyObject* empty_string = NULL;

#define TRACEBACK_SIZE(NFRAME) (sizeof(traceback_t) + sizeof(frame_t) * (NFRAME - 1))

Expand Down Expand Up @@ -135,12 +133,6 @@ memalloc_tb_init(uint16_t max_nframe)
PyUnicode_InternInPlace(&unknown_name);
}

if (empty_string == NULL) {
empty_string = PyUnicode_FromString("");
if (empty_string == NULL)
return -1;
PyUnicode_InternInPlace(&empty_string);
}
return 0;
}

Expand Down Expand Up @@ -297,7 +289,7 @@ traceback_to_tuple(traceback_t* tb)
PyObject* stack = PyTuple_New(tb->nframe);

for (uint16_t nframe = 0; nframe < tb->nframe; nframe++) {
PyObject* frame_tuple = PyTuple_New(4);
PyObject* frame_tuple = PyTuple_New(3);

frame_t* frame = &tb->frames[nframe];

Expand All @@ -306,9 +298,6 @@ traceback_to_tuple(traceback_t* tb)
PyTuple_SET_ITEM(frame_tuple, 1, PyLong_FromUnsignedLong(frame->lineno));
Py_INCREF(frame->name);
PyTuple_SET_ITEM(frame_tuple, 2, frame->name);
/* Class name */
Py_INCREF(empty_string);
PyTuple_SET_ITEM(frame_tuple, 3, empty_string);

// Try to set the class. If we cannot (e.g., if the sofile is reloaded
// without module initialization), then this will result in an error if
Expand Down
29 changes: 2 additions & 27 deletions ddtrace/profiling/collector/_traceback.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -8,31 +8,6 @@ from ddtrace.profiling.event import DDFrame
log = get_logger(__name__)


cpdef _extract_class_name(frame):
# type: (...) -> str
"""Extract class name from a frame, if possible.

:param frame: The frame object.
"""
code = frame.f_code
if code.co_argcount > 0:
# Retrieve the name of the first argument, if the code object has any
argname = code.co_varnames[0]
try:
value = frame.f_locals[argname]
except Exception:
log.debug("Unable to extract class name from frame %r", frame, exc_info=True)
return ""
try:
if argname == "self":
return object.__getattribute__(type(value), "__name__") # use type() and object.__getattribute__ to avoid side-effects
if argname == "cls":
return object.__getattribute__(value, "__name__")
except AttributeError:
return ""
return ""


cpdef traceback_to_frames(traceback, max_nframes):
"""Serialize a Python traceback object into a list of tuple of (filename, lineno, function_name).

Expand All @@ -48,7 +23,7 @@ cpdef traceback_to_frames(traceback, max_nframes):
frame = tb.tb_frame
code = frame.f_code
lineno = 0 if frame.f_lineno is None else frame.f_lineno
frames.insert(0, DDFrame(code.co_filename, lineno, code.co_name, _extract_class_name(frame)))
frames.insert(0, DDFrame(code.co_filename, lineno, code.co_name))
nframes += 1
tb = tb.tb_next
return frames, nframes
Expand Down Expand Up @@ -92,7 +67,7 @@ cpdef pyframe_to_frames(frame, max_nframes):
return [], 0

lineno = 0 if frame.f_lineno is None else frame.f_lineno
frames.append(DDFrame(code.co_filename, lineno, code.co_name, _extract_class_name(frame)))
frames.append(DDFrame(code.co_filename, lineno, code.co_name))
nframes += 1
frame = frame.f_back
return frames, nframes
3 changes: 0 additions & 3 deletions ddtrace/profiling/collector/stack.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,6 @@ cdef stack_collect(ignore_profiler, thread_time, max_nframes, interval, wall_tim
handle.push_threadinfo(thread_id, thread_native_id, thread_name)
handle.push_task_id(task_id)
handle.push_task_name(task_name)
handle.push_class_name(frames[0].class_name)
for frame in frames:
handle.push_frame(frame.function_name, frame.file_name, 0, frame.lineno)
handle.flush_sample()
Expand All @@ -330,7 +329,6 @@ cdef stack_collect(ignore_profiler, thread_time, max_nframes, interval, wall_tim
handle.push_cputime( cpu_time, 1)
handle.push_walltime( wall_time, 1)
handle.push_threadinfo(thread_id, thread_native_id, thread_name)
handle.push_class_name(frames[0].class_name)
for frame in frames:
handle.push_frame(frame.function_name, frame.file_name, 0, frame.lineno)
handle.push_span(span)
Expand All @@ -346,7 +344,6 @@ cdef stack_collect(ignore_profiler, thread_time, max_nframes, interval, wall_tim
handle.push_monotonic_ns(now_ns)
handle.push_threadinfo(thread_id, thread_native_id, thread_name)
handle.push_exceptioninfo(exc_type, 1)
handle.push_class_name(frames[0].class_name)
for frame in frames:
handle.push_frame(frame.function_name, frame.file_name, 0, frame.lineno)
handle.push_span(span)
Expand Down
2 changes: 1 addition & 1 deletion ddtrace/profiling/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
import typing


DDFrame = namedtuple("DDFrame", ["file_name", "lineno", "function_name", "class_name"])
DDFrame = namedtuple("DDFrame", ["file_name", "lineno", "function_name"])
StackTraceType = typing.List[DDFrame]
5 changes: 5 additions & 0 deletions releasenotes/notes/profiling-f_locals-c345ca501ca9b74f.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
fixes:
- |
profiling: Fixes a segmentation fault caused by accessing ``frame.f_locals``
while trying to retrieve class name of a ``PyFrameObject``.
9 changes: 2 additions & 7 deletions tests/profiling/collector/test_memalloc.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,11 +90,10 @@ def test_iter_events():
__file__,
_ALLOC_LINE_NUMBER,
"<listcomp>" if sys.version_info < (3, 12) else "_allocate_1k",
"",
):
assert thread_id == threading.main_thread().ident
if sys.version_info < (3, 12) and len(stack) > 1:
assert stack[1] == DDFrame(__file__, _ALLOC_LINE_NUMBER, "_allocate_1k", "")
assert stack[1] == DDFrame(__file__, _ALLOC_LINE_NUMBER, "_allocate_1k")
object_count += sample.count

assert object_count >= 1000
Expand Down Expand Up @@ -156,12 +155,11 @@ def test_iter_events_multi_thread():
__file__,
_ALLOC_LINE_NUMBER,
"<listcomp>" if sys.version_info < (3, 12) else "_allocate_1k",
"",
):
if thread_id == threading.main_thread().ident:
count_object += sample.count
if sys.version_info < (3, 12) and len(stack) > 1:
assert stack[1] == DDFrame(__file__, _ALLOC_LINE_NUMBER, "_allocate_1k", "")
assert stack[1] == DDFrame(__file__, _ALLOC_LINE_NUMBER, "_allocate_1k")
elif thread_id == t.ident:
count_thread += sample.count
entry = 2 if sys.version_info < (3, 12) else 1
Expand Down Expand Up @@ -205,7 +203,6 @@ def _test_heap_impl(collector, max_nframe):
__file__,
_ALLOC_LINE_NUMBER,
"<listcomp>" if sys.version_info < (3, 12) else "_allocate_1k",
"",
):
break
else:
Expand All @@ -229,7 +226,6 @@ def _test_heap_impl(collector, max_nframe):
__file__,
_ALLOC_LINE_NUMBER,
"<listcomp>" if sys.version_info < (3, 12) else "_allocate_1k",
"",
):
break
else:
Expand Down Expand Up @@ -258,7 +254,6 @@ def _test_heap_impl(collector, max_nframe):
__file__,
_ALLOC_LINE_NUMBER,
"<listcomp>" if sys.version_info < (3, 12) else "_allocate_1k",
"",
)
and stack[entry].function_name == "_test_heap_impl"
):
Expand Down
6 changes: 2 additions & 4 deletions tests/profiling/collector/test_stack.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,11 +114,9 @@ def _find_sleep_event(events, class_name):

for e in events:
for frame in e.frames:
if frame[0] == __file__.replace(".pyc", ".py") and frame[2] == "sleep_class" and frame[3] == class_name:
if frame[0] == __file__.replace(".pyc", ".py") and frame[2] == "sleep_class":
class_method_found = True
elif (
frame[0] == __file__.replace(".pyc", ".py") and frame[2] == "sleep_instance" and frame[3] == class_name
):
elif frame[0] == __file__.replace(".pyc", ".py") and frame[2] == "sleep_instance":
class_classmethod_found = True

if class_method_found and class_classmethod_found:
Expand Down
4 changes: 2 additions & 2 deletions tests/profiling/collector/test_traceback.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@ def test_check_traceback_to_frames():

this_file = __file__.replace(".pyc", ".py")
assert frames == [
(this_file, 7, "_x", ""),
(this_file, 15, "test_check_traceback_to_frames", ""),
(this_file, 7, "_x"),
(this_file, 15, "test_check_traceback_to_frames"),
]
Loading