Skip to content

Commit

Permalink
Remove ddtrace frames from stacks
Browse files Browse the repository at this point in the history
  • Loading branch information
estringana committed Aug 2, 2024
1 parent 4b3e1bf commit 996e2ab
Show file tree
Hide file tree
Showing 4 changed files with 229 additions and 15 deletions.
65 changes: 52 additions & 13 deletions appsec/src/extension/backtrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

static const int NO_LIMIT = 0;
static const double STACK_DEFAULT_TOP_PERCENTAGE = 0.25;
static const char *QUALIFIED_NAME_SEPARATOR = "::";

static zend_string *_frames_key;
static zend_string *_language_key;
Expand All @@ -36,26 +37,65 @@ bool php_backtrace_frame_to_datadog_backtrace_frame( // NOLINTNEXTLINE(bugprone-
zval *function =
zend_hash_str_find(frame, "function", sizeof("function") - 1);
zval *file = zend_hash_str_find(frame, "file", sizeof("file") - 1);
zval *class = zend_hash_str_find(frame, "class", sizeof("class") - 1);
zval id;
ZVAL_LONG(&id, index);

#ifdef TESTING
// In order to be able to test full path encoded everywhere lets set
// only the file name without path
char *file_name = strrchr(Z_STRVAL_P(file), '/');
Z_TRY_DELREF_P(file);
ZVAL_STRINGL(file, file_name + 1, strlen(file_name) - 1);
if (file) {
// In order to be able to test full path encoded everywhere lets set
// only the file name without path
char *file_name = strrchr(Z_STRVAL_P(file), '/');
Z_TRY_DELREF_P(file);
ZVAL_STRINGL(file, file_name + 1, strlen(file_name) - 1);
}
#endif

if (!function) {
return false;
}

// Remove tracer integration php code frames
if (strncmp(Z_STRVAL_P(function), LSTRARG("DDTrace")) == 0) {
return false;
}

array_init(datadog_backtrace_frame);
HashTable *datadog_backtrace_frame_ht = Z_ARRVAL_P(datadog_backtrace_frame);
zend_hash_add(datadog_backtrace_frame_ht, _frame_line, line);
zend_hash_add(datadog_backtrace_frame_ht, _frame_function, function);
zend_hash_add(datadog_backtrace_frame_ht, _frame_file, file);
zend_hash_add(datadog_backtrace_frame_ht, _id_key, &id);
if (line) {
zend_hash_add(datadog_backtrace_frame_ht, _frame_line, line);
}

int qualified_name_size = Z_STRLEN_P(function);
int qualified_name_separator_len = strlen(QUALIFIED_NAME_SEPARATOR);
qualified_name_size +=
class ? Z_STRLEN_P(class) + qualified_name_separator_len : 0;
char *qualified_name = safe_emalloc(qualified_name_size, 1, 1);
int position = 0;

if (class) {
memcpy(qualified_name, Z_STRVAL_P(class), Z_STRLEN_P(class));
position = Z_STRLEN_P(class);
memcpy(&qualified_name[position], QUALIFIED_NAME_SEPARATOR,
qualified_name_separator_len);
position += 2;
}

memcpy(
&qualified_name[position], Z_STRVAL_P(function), Z_STRLEN_P(function));

qualified_name[qualified_name_size] = '\0';

Z_TRY_ADDREF_P(function);
Z_TRY_ADDREF_P(file);
zval zv_qualified_name;
ZVAL_STRING(&zv_qualified_name, qualified_name);
zend_hash_add(
datadog_backtrace_frame_ht, _frame_function, &zv_qualified_name);
efree(qualified_name);

if (file) {
zend_hash_add(datadog_backtrace_frame_ht, _frame_file, file);
Z_TRY_ADDREF_P(file);
}
zend_hash_add(datadog_backtrace_frame_ht, _id_key, &id);

return true;
}
Expand Down Expand Up @@ -96,7 +136,6 @@ void php_backtrace_to_datadog_backtrace(
tmp, &new_frame, index)) {
continue;
}

zend_hash_next_index_insert_new(datadog_backtrace_ht, &new_frame);
if (--top == 0) {
break;
Expand Down
3 changes: 1 addition & 2 deletions appsec/src/extension/commands_helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -422,9 +422,8 @@ static void _command_process_redirect_parameters(mpack_node_t root)
}
static void _command_process_stack_trace_parameters(mpack_node_t root)
{
int expected_nodes = 1;
size_t count = mpack_node_map_count(root);
for (size_t i = 0; i < count && expected_nodes > 0; i++) {
for (size_t i = 0; i < count; i++) {
mpack_node_t key = mpack_node_map_key_at(root, i);
mpack_node_t value = mpack_node_map_value_at(root, i);
if (dd_mpack_node_lstr_eq(key, "stack_id")) {
Expand Down
93 changes: 93 additions & 0 deletions appsec/tests/extension/generate_backtrace_06.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
--TEST--
Backtrace do not contains datadog frames
--ENV--
DD_TRACE_GENERATE_ROOT_SPAN=0
--INI--
extension=ddtrace.so
--FILE--
<?php
namespace DDTrace {
use function datadog\appsec\testing\generate_backtrace;

class SomeIntegration {
public function init()
{
install_hook("ltrim", self::hooked_function(), null);
}

private static function hooked_function()
{
return static function (HookData $hook) {
var_dump(generate_backtrace("some id"));
};
}
}
}
namespace {
include __DIR__ . '/inc/ddtrace_version.php';

ddtrace_version_at_least('0.79.0');

function two($param01, $param02)
{
var_dump(ltrim(" Verify the wrapped function works"));
}

function one($param01)
{
two($param01, "other");
}

$integration = new DDTrace\SomeIntegration();
$integration->init();

DDTrace\start_span();
$root = DDTrace\active_span();
one("foo01");
}

?>
--EXPECTF--
array(3) {
["language"]=>
string(3) "php"
["id"]=>
string(7) "some id"
["frames"]=>
array(3) {
[0]=>
array(4) {
["line"]=>
int(26)
["function"]=>
string(5) "ltrim"
["file"]=>
string(25) "generate_backtrace_06.php"
["id"]=>
int(1)
}
[1]=>
array(4) {
["line"]=>
int(31)
["function"]=>
string(3) "two"
["file"]=>
string(25) "generate_backtrace_06.php"
["id"]=>
int(2)
}
[2]=>
array(4) {
["line"]=>
int(39)
["function"]=>
string(3) "one"
["file"]=>
string(25) "generate_backtrace_06.php"
["id"]=>
int(3)
}
}
}
string(33) "Verify the wrapped function works"
83 changes: 83 additions & 0 deletions appsec/tests/extension/generate_backtrace_07.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
--TEST--
Functions are fully qualified names
--ENV--
DD_TRACE_GENERATE_ROOT_SPAN=0
--INI--
extension=ddtrace.so
--FILE--
<?php
namespace Some\NameSpace {
use function datadog\appsec\testing\generate_backtrace;

class Foo {
static function three () {
var_dump(generate_backtrace("some id"));
}

function two($param01, $param02)
{
self::three();
}

function one($param01)
{
$this->two($param01, "other");
}
}
}

namespace {
include __DIR__ . '/inc/ddtrace_version.php';

ddtrace_version_at_least('0.79.0');

DDTrace\start_span();
$root = DDTrace\active_span();

$class = new Some\NameSpace\Foo();
$class->one("foo01");
}
?>
--EXPECTF--
array(3) {
["language"]=>
string(3) "php"
["id"]=>
string(7) "some id"
["frames"]=>
array(3) {
[0]=>
array(4) {
["line"]=>
int(12)
["function"]=>
string(25) "Some\NameSpace\Foo::three"
["file"]=>
string(25) "generate_backtrace_07.php"
["id"]=>
int(0)
}
[1]=>
array(4) {
["line"]=>
int(17)
["function"]=>
string(23) "Some\NameSpace\Foo::two"
["file"]=>
string(25) "generate_backtrace_07.php"
["id"]=>
int(1)
}
[2]=>
array(4) {
["line"]=>
int(31)
["function"]=>
string(23) "Some\NameSpace\Foo::one"
["file"]=>
string(25) "generate_backtrace_07.php"
["id"]=>
int(2)
}
}
}

0 comments on commit 996e2ab

Please sign in to comment.