Skip to content

Commit

Permalink
Merge branch 'main' into juanjux/ddprof-python-module
Browse files Browse the repository at this point in the history
  • Loading branch information
juanjux authored Oct 25, 2024
2 parents e39d99d + d3485f2 commit 2480b57
Show file tree
Hide file tree
Showing 9 changed files with 115 additions and 103 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ class ThreadSpanLinks
ThreadSpanLinks& operator=(ThreadSpanLinks const&) = delete;

void link_span(uint64_t thread_id, uint64_t span_id, uint64_t local_root_span_id, std::string span_type);

const Span* get_active_span_from_thread_id(uint64_t thread_id);
void reset();

static void postfork_child();

Expand All @@ -48,8 +48,6 @@ class ThreadSpanLinks
// Private Constructor/Destructor
ThreadSpanLinks() = default;
~ThreadSpanLinks() = default;

void reset();
};

}
15 changes: 13 additions & 2 deletions ddtrace/internal/datadog/profiling/stack_v2/src/stack_v2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ stack_v2_stop(PyObject* self, PyObject* args)
(void)self;
(void)args;
Sampler::get().stop();
// Explicitly clear ThreadSpanLinks. The memory should be cleared up
// when the program exits as ThreadSpanLinks is a static singleton instance.
// However, this was necessary to make sure that the state is not shared
// across tests, as the tests are run in the same process.
ThreadSpanLinks::get_instance().reset();
Py_RETURN_NONE;
}

Expand Down Expand Up @@ -91,7 +96,7 @@ _stack_v2_link_span(PyObject* self, PyObject* args, PyObject* kwargs)
uint64_t thread_id;
uint64_t span_id;
uint64_t local_root_span_id;
const char* span_type;
const char* span_type = nullptr;

PyThreadState* state = PyThreadState_Get();

Expand All @@ -104,10 +109,16 @@ _stack_v2_link_span(PyObject* self, PyObject* args, PyObject* kwargs)
static const char* const_kwlist[] = { "span_id", "local_root_span_id", "span_type", NULL };
static char** kwlist = const_cast<char**>(const_kwlist);

if (!PyArg_ParseTupleAndKeywords(args, kwargs, "KKs", kwlist, &span_id, &local_root_span_id, &span_type)) {
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "KKz", kwlist, &span_id, &local_root_span_id, &span_type)) {
return NULL;
}

// From Python, span_type is a string or None, and when given None, it is passed as a nullptr.
static const std::string empty_string = "";
if (span_type == nullptr) {
span_type = empty_string.c_str();
}

ThreadSpanLinks::get_instance().link_span(thread_id, span_id, local_root_span_id, std::string(span_type));

Py_RETURN_NONE;
Expand Down
5 changes: 4 additions & 1 deletion ddtrace/settings/asm.py
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ class ASMConfig(Env):
def __init__(self):
super().__init__()
# Is one click available?
self._asm_can_be_enabled = APPSEC_ENV not in os.environ and tracer_config._remote_config_enabled
self._eval_asm_can_be_enabled()
# Only for deprecation phase
if self._automatic_login_events_mode and APPSEC.AUTO_USER_INSTRUMENTATION_MODE not in os.environ:
self._auto_user_instrumentation_local_mode = self._automatic_login_events_mode
Expand All @@ -228,6 +228,9 @@ def reset(self):
"""For testing puposes, reset the configuration to its default values given current environment variables."""
self.__init__()

def _eval_asm_can_be_enabled(self):
self._asm_can_be_enabled = APPSEC_ENV not in os.environ and tracer_config._remote_config_enabled

@property
def _api_security_feature_active(self) -> bool:
return self._asm_libddwaf_available and self._asm_enabled and self._api_security_enabled
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
fixes:
- |
profiling: resolves an issue where endpoint profiling for stack v2 throws
``TypeError`` exception when it is given a ``Span`` with ``None`` span_type.
16 changes: 8 additions & 8 deletions tests/appsec/appsec/test_remoteconfiguration.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,19 +99,19 @@ def test_rc_activation_states_on(tracer, appsec_enabled, rc_value, remote_config
],
)
def test_rc_activation_states_off(tracer, appsec_enabled, rc_value, remote_config_worker):
with override_env({APPSEC.ENV: appsec_enabled}), override_global_config(dict(_asm_enabled=True)):
with override_env({APPSEC.ENV: appsec_enabled}):
if appsec_enabled == "":
del os.environ[APPSEC.ENV]
else:
with override_global_config(dict(_asm_enabled=True)):
tracer.configure(appsec_enabled=asbool(appsec_enabled))

rc_config = {"config": {"asm": {"enabled": True}}}
if rc_value is False:
rc_config = {}
rc_config = {"config": {"asm": {"enabled": True}}}
if rc_value is False:
rc_config = {}

_appsec_callback(rc_config, tracer)
result = _set_and_get_appsec_tags(tracer)
assert result is None
_appsec_callback(rc_config, tracer)
result = _set_and_get_appsec_tags(tracer)
assert result is None


@pytest.mark.parametrize(
Expand Down
30 changes: 15 additions & 15 deletions tests/appsec/iast/aspects/test_add_aspect.py
Original file line number Diff line number Diff line change
Expand Up @@ -269,24 +269,24 @@ def test_taint_object_error_with_no_context(log_level, iast_debug, caplog):
source_origin=OriginType.PARAMETER,
)

ranges_result = get_tainted_ranges(result)
assert len(ranges_result) == 0
ranges_result = get_tainted_ranges(result)
assert len(ranges_result) == 0

assert not any(record.message.startswith("Tainting object error") for record in caplog.records), [
record.message for record in caplog.records
]
assert not any("[IAST] Tainted Map" in record.message for record in caplog.records)
assert not any(record.message.startswith("Tainting object error") for record in caplog.records), [
record.message for record in caplog.records
]
assert not any("[IAST] Tainted Map" in record.message for record in caplog.records)

_start_iast_context_and_oce()
result = taint_pyobject(
pyobject=string_to_taint,
source_name="test_add_aspect_tainting_left_hand",
source_value=string_to_taint,
source_origin=OriginType.PARAMETER,
)
_start_iast_context_and_oce()
result = taint_pyobject(
pyobject=string_to_taint,
source_name="test_add_aspect_tainting_left_hand",
source_value=string_to_taint,
source_origin=OriginType.PARAMETER,
)

ranges_result = get_tainted_ranges(result)
assert len(ranges_result) == 1
ranges_result = get_tainted_ranges(result)
assert len(ranges_result) == 1


@pytest.mark.skip_iast_check_logs
Expand Down
29 changes: 17 additions & 12 deletions tests/profiling/collector/pprof_utils.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import ctypes
from enum import Enum
import glob
import os
import re
import typing

Expand Down Expand Up @@ -273,20 +274,24 @@ def assert_lock_event(profile, sample: pprof_pb2.Sample, expected_event: LockEve


# helper function to check whether the expected stack event is present in the samples
def has_sample_with_locations(
profile, samples: typing.List[pprof_pb2.Sample], expected_locations: typing.List[StackLocation]
) -> bool:
for sample in samples:
for location_id, expected_location in zip(sample.location_id, expected_locations):
def has_sample_with_locations(profile, expected_locations: typing.List[StackLocation]) -> bool:
for sample_idx, sample in enumerate(profile.sample):
# in a sample there can be multiple locations, we need to check
# whether there's a consecutive subsequence of locations that match
# the expected locations
expected_location_idx = 0
for location_id in sample.location_id:
location = get_location_with_id(profile, location_id)
function = get_function_with_id(profile, location.line[0].function_id)
if profile.string_table[function.name] != expected_location.function_name:
continue
if not profile.string_table[function.filename].endswith(expected_location.filename):
continue

return True

function_name = profile.string_table[function.name]
filename = os.path.basename(profile.string_table[function.filename])
if (
function_name.endswith(expected_locations[expected_location_idx].function_name)
and filename == expected_locations[expected_location_idx].filename
):
expected_location_idx += 1
if expected_location_idx == len(expected_locations):
return True
return False


Expand Down
Loading

0 comments on commit 2480b57

Please sign in to comment.