ddtrace 1.16.0 → 1.18.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +86 -1
- data/ext/ddtrace_profiling_native_extension/clock_id_from_pthread.c +3 -0
- data/ext/ddtrace_profiling_native_extension/collectors_thread_context.c +8 -1
- data/ext/ddtrace_profiling_native_extension/extconf.rb +28 -10
- data/ext/ddtrace_profiling_native_extension/http_transport.c +5 -2
- data/ext/ddtrace_profiling_native_extension/private_vm_api_access.c +78 -18
- data/ext/ddtrace_profiling_native_extension/private_vm_api_access.h +6 -0
- data/ext/ddtrace_profiling_native_extension/profiling.c +1 -0
- data/ext/ddtrace_profiling_native_extension/stack_recorder.c +1 -3
- data/lib/datadog/appsec/component.rb +4 -1
- data/lib/datadog/appsec/configuration/settings.rb +4 -6
- data/lib/datadog/appsec/contrib/devise/patcher/registration_controller_patch.rb +2 -0
- data/lib/datadog/appsec/contrib/rack/gateway/response.rb +0 -46
- data/lib/datadog/appsec/contrib/rack/reactive/response.rb +0 -5
- data/lib/datadog/appsec/contrib/rack/request_middleware.rb +0 -10
- data/lib/datadog/appsec/processor/rule_loader.rb +60 -0
- data/lib/datadog/appsec/remote.rb +12 -9
- data/lib/datadog/core/configuration/settings.rb +1 -1
- data/lib/datadog/core/configuration.rb +4 -0
- data/lib/datadog/core/remote/worker.rb +1 -0
- data/lib/datadog/core/workers/async.rb +1 -0
- data/lib/datadog/kit/enable_core_dumps.rb +5 -6
- data/lib/datadog/opentelemetry/sdk/span_processor.rb +39 -8
- data/lib/datadog/opentelemetry/sdk/trace/span.rb +102 -3
- data/lib/datadog/opentracer/text_map_propagator.rb +2 -1
- data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +1 -0
- data/lib/datadog/profiling/collectors/idle_sampling_helper.rb +1 -0
- data/lib/datadog/profiling/component.rb +13 -5
- data/lib/datadog/tracing/configuration/ext.rb +3 -0
- data/lib/datadog/tracing/configuration/settings.rb +18 -3
- data/lib/datadog/tracing/contrib/concurrent_ruby/context_composite_executor_service.rb +1 -1
- data/lib/datadog/tracing/contrib/pg/configuration/settings.rb +5 -0
- data/lib/datadog/tracing/contrib/pg/instrumentation.rb +24 -0
- data/lib/datadog/tracing/distributed/datadog.rb +0 -1
- data/lib/datadog/tracing/distributed/propagation.rb +25 -4
- data/lib/datadog/tracing/trace_digest.rb +31 -0
- data/lib/datadog/tracing/workers.rb +1 -0
- data/lib/ddtrace/version.rb +1 -1
- metadata +7 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 69e775ab06a83ce14114a7287056e3d3fb575191b7ff6ccdc5c7b33f7fd58172
|
4
|
+
data.tar.gz: 13b607a4e29e516be4988dca7827eca09b79e968cf98e0641a155039d2ec3273
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d345e07c8b0a654974c51a7457b3fc6d3d7eb99226cfc5555d6bc8ee3e65b17b3782b1e582591be925297c09dd104108007b2081e28ee43c103f8f2fec3ffe5b
|
7
|
+
data.tar.gz: '085ea801f5fae16ed58cd79bab86839cd1aa23fa09261b39219264f603455633e19dbb8f60d647e407c7218d7d00052ef7b593405ec5af828af56ffecd58227d'
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,66 @@
|
|
2
2
|
|
3
3
|
## [Unreleased]
|
4
4
|
|
5
|
+
## [1.18.0] - 2023-12-07
|
6
|
+
|
7
|
+
### Added
|
8
|
+
|
9
|
+
* Tracing: Support lib injection for ARM64 architecture ([#3307][])
|
10
|
+
* Tracing: Add `error_handler` for `pg` instrumentation ([#3303][])
|
11
|
+
* Appsec: Enable "Trusted IPs", a.k.a passlist with optional monitoring ([#3229][])
|
12
|
+
|
13
|
+
### Changed
|
14
|
+
|
15
|
+
* Mark ddtrace threads as fork-safe ([#3279][])
|
16
|
+
* Bump `datadog-ci` dependency to 0.5.0 ([#3308][])
|
17
|
+
* Bump `debase-ruby_core_source` dependency to 3.2.3 ([#3284][])
|
18
|
+
* Profiling: Disable profiler on Ruby 3.3 when running with RUBY_MN_THREADS=1 ([#3259][])
|
19
|
+
* Profiling: Run without "no signals" workaround on passenger 6.0.19+ ([#3280][])
|
20
|
+
|
21
|
+
### Fixed
|
22
|
+
|
23
|
+
* Tracing: Fix `pg` instrumentation `enabled` settings ([#3271][])
|
24
|
+
* Profiling: Fix potential crash by importing upstream `rb_profile_frames` fix ([#3289][])
|
25
|
+
* Appsec: Call `devise` RegistrationsController block ([#3286][])
|
26
|
+
|
27
|
+
## [1.17.0] - 2023-11-22
|
28
|
+
|
29
|
+
For W3C Trace Context, this release adds [`tracecontext`](https://www.w3.org/TR/trace-context/) to the default trace propagation extraction and injection styles. The new defaults are:
|
30
|
+
* Extraction: `Datadog,b3multi,b3,tracecontext`
|
31
|
+
* Injection: `Datadog,tracecontext`
|
32
|
+
|
33
|
+
And to increase interoperability with `tracecontext`, 128-bit Trace ID generation is now the default.
|
34
|
+
|
35
|
+
For OpenTelemetry, this release adds support for converting [OpenTelemetry Trace Semantic Conventions](https://opentelemetry.io/docs/specs/semconv/general/trace/) into equivalent Datadog trace semantics. Also, it's now possible to configure top-level Datadog span fields using OpenTelemetry span attributes (https://github.com/DataDog/dd-trace-rb/pull/3262).
|
36
|
+
|
37
|
+
For CI Visibility, you can now manually create CI traces and spans with the [newly released API](https://github.com/DataDog/datadog-ci-rb/releases/tag/v0.4.0).
|
38
|
+
|
39
|
+
### Added
|
40
|
+
|
41
|
+
* OpenTelemetry: Parse OpenTelemetry semantic conventions to Datadog's ([#3273][])
|
42
|
+
* OpenTelemetry: Support span reserved attribute overrides ([#3262][])
|
43
|
+
* Tracing: Ensure W3C `tracestate` is always propagated ([#3255][])
|
44
|
+
|
45
|
+
### Changed
|
46
|
+
|
47
|
+
* Tracing: Set 128-bit trace_id to true by default ([#3266][])
|
48
|
+
* Tracing: Default trace propagation styles to `Datadog,b3multi,b3,tracecontext` ([#3248][],[#3267][])
|
49
|
+
* Ci-App: Upgraded `datadog-ci` dependency to 0.4 ([#3270][])
|
50
|
+
|
51
|
+
## [1.16.2] - 2023-11-10
|
52
|
+
|
53
|
+
This release reverts a change to appsec response body parsing that was introduced in [1.16.0 ](https://github.com/DataDog/dd-trace-rb/releases/tag/v1.16.0) that may cause memory leaks.
|
54
|
+
|
55
|
+
### Fixed
|
56
|
+
* Appsec: [Revert parse response body fix introduced in 1.16.0](https://github.com/DataDog/dd-trace-rb/pull/3153) ([#3252][])
|
57
|
+
|
58
|
+
## [1.16.1] - 2023-11-08
|
59
|
+
|
60
|
+
### Fixed
|
61
|
+
|
62
|
+
* Tracing: Fix `concurrent-ruby` future propagation without `active_trace` ([#3242][])
|
63
|
+
* Tracing: Fix host injection error handling ([#3240][])
|
64
|
+
|
5
65
|
## [1.16.0] - 2023-11-03
|
6
66
|
|
7
67
|
**This release includes a security change for the Tracing Redis integration:**
|
@@ -2620,7 +2680,11 @@ Release notes: https://github.com/DataDog/dd-trace-rb/releases/tag/v0.3.1
|
|
2620
2680
|
Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
|
2621
2681
|
|
2622
2682
|
|
2623
|
-
[Unreleased]: https://github.com/DataDog/dd-trace-rb/compare/v1.
|
2683
|
+
[Unreleased]: https://github.com/DataDog/dd-trace-rb/compare/v1.18.0...master
|
2684
|
+
[1.18.0]: https://github.com/DataDog/dd-trace-rb/compare/v1.17.0...v1.18.0
|
2685
|
+
[1.17.0]: https://github.com/DataDog/dd-trace-rb/compare/v1.16.2...v1.17.0
|
2686
|
+
[1.16.2]: https://github.com/DataDog/dd-trace-rb/compare/v1.16.1...v1.16.2
|
2687
|
+
[1.16.1]: https://github.com/DataDog/dd-trace-rb/compare/v1.16.0...v1.16.1
|
2624
2688
|
[1.16.0]: https://github.com/DataDog/dd-trace-rb/compare/v1.15.0...v1.16.0
|
2625
2689
|
[1.15.0]: https://github.com/DataDog/dd-trace-rb/compare/v1.14.0...v1.15.0
|
2626
2690
|
[1.14.0]: https://github.com/DataDog/dd-trace-rb/compare/v1.13.1...1.14.0
|
@@ -3829,8 +3893,29 @@ Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
|
|
3829
3893
|
[#3206]: https://github.com/DataDog/dd-trace-rb/issues/3206
|
3830
3894
|
[#3207]: https://github.com/DataDog/dd-trace-rb/issues/3207
|
3831
3895
|
[#3223]: https://github.com/DataDog/dd-trace-rb/issues/3223
|
3896
|
+
[#3229]: https://github.com/DataDog/dd-trace-rb/issues/3229
|
3832
3897
|
[#3234]: https://github.com/DataDog/dd-trace-rb/issues/3234
|
3833
3898
|
[#3235]: https://github.com/DataDog/dd-trace-rb/issues/3235
|
3899
|
+
[#3240]: https://github.com/DataDog/dd-trace-rb/issues/3240
|
3900
|
+
[#3242]: https://github.com/DataDog/dd-trace-rb/issues/3242
|
3901
|
+
[#3248]: https://github.com/DataDog/dd-trace-rb/issues/3248
|
3902
|
+
[#3252]: https://github.com/DataDog/dd-trace-rb/issues/3252
|
3903
|
+
[#3255]: https://github.com/DataDog/dd-trace-rb/issues/3255
|
3904
|
+
[#3259]: https://github.com/DataDog/dd-trace-rb/issues/3259
|
3905
|
+
[#3262]: https://github.com/DataDog/dd-trace-rb/issues/3262
|
3906
|
+
[#3266]: https://github.com/DataDog/dd-trace-rb/issues/3266
|
3907
|
+
[#3267]: https://github.com/DataDog/dd-trace-rb/issues/3267
|
3908
|
+
[#3270]: https://github.com/DataDog/dd-trace-rb/issues/3270
|
3909
|
+
[#3271]: https://github.com/DataDog/dd-trace-rb/issues/3271
|
3910
|
+
[#3273]: https://github.com/DataDog/dd-trace-rb/issues/3273
|
3911
|
+
[#3279]: https://github.com/DataDog/dd-trace-rb/issues/3279
|
3912
|
+
[#3280]: https://github.com/DataDog/dd-trace-rb/issues/3280
|
3913
|
+
[#3284]: https://github.com/DataDog/dd-trace-rb/issues/3284
|
3914
|
+
[#3286]: https://github.com/DataDog/dd-trace-rb/issues/3286
|
3915
|
+
[#3289]: https://github.com/DataDog/dd-trace-rb/issues/3289
|
3916
|
+
[#3303]: https://github.com/DataDog/dd-trace-rb/issues/3303
|
3917
|
+
[#3307]: https://github.com/DataDog/dd-trace-rb/issues/3307
|
3918
|
+
[#3308]: https://github.com/DataDog/dd-trace-rb/issues/3308
|
3834
3919
|
[@AdrianLC]: https://github.com/AdrianLC
|
3835
3920
|
[@Azure7111]: https://github.com/Azure7111
|
3836
3921
|
[@BabyGroot]: https://github.com/BabyGroot
|
@@ -25,6 +25,9 @@ void self_test_clock_id(void) {
|
|
25
25
|
// Safety: This function is assumed never to raise exceptions by callers
|
26
26
|
thread_cpu_time_id thread_cpu_time_id_for(VALUE thread) {
|
27
27
|
rb_nativethread_id_t thread_id = pthread_id_for(thread);
|
28
|
+
|
29
|
+
if (thread_id == 0) return (thread_cpu_time_id) {.valid = false};
|
30
|
+
|
28
31
|
clockid_t clock_id;
|
29
32
|
|
30
33
|
int error = pthread_getcpuclockid(thread_id, &clock_id);
|
@@ -1150,6 +1150,7 @@ void thread_context_collector_sample_allocation(VALUE self_instance, unsigned in
|
|
1150
1150
|
// Since this is stack allocated, be careful about moving it
|
1151
1151
|
ddog_CharSlice class_name;
|
1152
1152
|
ddog_CharSlice *optional_class_name = NULL;
|
1153
|
+
char imemo_type[100];
|
1153
1154
|
|
1154
1155
|
if (state->allocation_type_enabled) {
|
1155
1156
|
optional_class_name = &class_name;
|
@@ -1197,7 +1198,13 @@ void thread_context_collector_sample_allocation(VALUE self_instance, unsigned in
|
|
1197
1198
|
class_name = ruby_value_type_to_class_name(type);
|
1198
1199
|
}
|
1199
1200
|
} else if (type == RUBY_T_IMEMO) {
|
1200
|
-
|
1201
|
+
const char *imemo_string = imemo_kind(new_object);
|
1202
|
+
if (imemo_string != NULL) {
|
1203
|
+
snprintf(imemo_type, 100, "(VM Internal, T_IMEMO, %s)", imemo_string);
|
1204
|
+
class_name = (ddog_CharSlice) {.ptr = imemo_type, .len = strlen(imemo_type)};
|
1205
|
+
} else { // Ruby < 3
|
1206
|
+
class_name = DDOG_CHARSLICE_C("(VM Internal, T_IMEMO)");
|
1207
|
+
}
|
1201
1208
|
} else {
|
1202
1209
|
class_name = ruby_vm_type; // For other weird internal things we just use the VM type
|
1203
1210
|
}
|
@@ -81,10 +81,7 @@ end
|
|
81
81
|
|
82
82
|
# Because we can't control what compiler versions our customers use, shipping with -Werror by default is a no-go.
|
83
83
|
# But we can enable it in CI, so that we quickly spot any new warnings that just got introduced.
|
84
|
-
|
85
|
-
# @ivoanjo TODO: 3.3.0-preview releases are causing issues in CI because `have_header('vm_core.h')` below triggers warnings;
|
86
|
-
# I've chosen to disable `-Werror` for this Ruby version for now, and we can revisit this on a later 3.3 release.
|
87
|
-
add_compiler_flag '-Werror' if ENV['DDTRACE_CI'] == 'true' && !RUBY_DESCRIPTION.include?('3.3.0preview')
|
84
|
+
add_compiler_flag '-Werror' if ENV['DDTRACE_CI'] == 'true'
|
88
85
|
|
89
86
|
# Older gcc releases may not default to C99 and we need to ask for this. This is also used:
|
90
87
|
# * by upstream Ruby -- search for gnu99 in the codebase
|
@@ -102,9 +99,6 @@ add_compiler_flag '-Wno-declaration-after-statement'
|
|
102
99
|
# cause a segfault later. Let's ensure that never happens.
|
103
100
|
add_compiler_flag '-Werror-implicit-function-declaration'
|
104
101
|
|
105
|
-
# Warn on unused parameters to functions. Use `DDTRACE_UNUSED` to mark things as known-to-not-be-used.
|
106
|
-
add_compiler_flag '-Wunused-parameter'
|
107
|
-
|
108
102
|
# The native extension is not intended to expose any symbols/functions for other native libraries to use;
|
109
103
|
# the sole exception being `Init_ddtrace_profiling_native_extension` which needs to be visible for Ruby to call it when
|
110
104
|
# it `dlopen`s the library.
|
@@ -131,6 +125,9 @@ if RUBY_PLATFORM.include?('linux')
|
|
131
125
|
$defs << '-DHAVE_PTHREAD_GETCPUCLOCKID'
|
132
126
|
end
|
133
127
|
|
128
|
+
# On older Rubies, M:N threads were not available
|
129
|
+
$defs << '-DNO_MN_THREADS_AVAILABLE' if RUBY_VERSION < '3.3'
|
130
|
+
|
134
131
|
# On older Rubies, we did not need to include the ractor header (this was built into the MJIT header)
|
135
132
|
$defs << '-DNO_RACTOR_HEADER_INCLUDE' if RUBY_VERSION < '3.3'
|
136
133
|
|
@@ -152,12 +149,18 @@ $defs << '-DNO_PRIMITIVE_POP' if RUBY_VERSION < '3.2'
|
|
152
149
|
# On older Rubies, there was no tid member in the internal thread structure
|
153
150
|
$defs << '-DNO_THREAD_TID' if RUBY_VERSION < '3.1'
|
154
151
|
|
152
|
+
# On older Rubies, there was no jit_return member on the rb_control_frame_t struct
|
153
|
+
$defs << '-DNO_JIT_RETURN' if RUBY_VERSION < '3.1'
|
154
|
+
|
155
155
|
# On older Rubies, we need to use a backported version of this function. See private_vm_api_access.h for details.
|
156
156
|
$defs << '-DUSE_BACKPORTED_RB_PROFILE_FRAME_METHOD_NAME' if RUBY_VERSION < '3'
|
157
157
|
|
158
158
|
# On older Rubies, there are no Ractors
|
159
159
|
$defs << '-DNO_RACTORS' if RUBY_VERSION < '3'
|
160
160
|
|
161
|
+
# On older Rubies, rb_imemo_name did not exist
|
162
|
+
$defs << '-DNO_IMEMO_NAME' if RUBY_VERSION < '3'
|
163
|
+
|
161
164
|
# On older Rubies, objects would not move
|
162
165
|
$defs << '-DNO_T_MOVED' if RUBY_VERSION < '2.7'
|
163
166
|
|
@@ -238,6 +241,10 @@ if Datadog::Profiling::NativeExtensionHelpers::CAN_USE_MJIT_HEADER
|
|
238
241
|
# NOTE: This needs to come after all changes to $defs
|
239
242
|
create_header
|
240
243
|
|
244
|
+
# Warn on unused parameters to functions. Use `DDTRACE_UNUSED` to mark things as known-to-not-be-used.
|
245
|
+
# See the comment on the same flag below for why this is done last.
|
246
|
+
add_compiler_flag '-Wunused-parameter'
|
247
|
+
|
241
248
|
create_makefile EXTENSION_NAME
|
242
249
|
else
|
243
250
|
# The MJIT header was introduced on 2.6 and removed on 3.3; for other Rubies we rely on
|
@@ -253,9 +260,20 @@ else
|
|
253
260
|
Debase::RubyCoreSource
|
254
261
|
.create_makefile_with_core(
|
255
262
|
proc do
|
256
|
-
|
257
|
-
|
258
|
-
|
263
|
+
headers_available =
|
264
|
+
have_header('vm_core.h') &&
|
265
|
+
have_header('iseq.h') &&
|
266
|
+
(RUBY_VERSION < '3.3' || have_header('ractor_core.h'))
|
267
|
+
|
268
|
+
if headers_available
|
269
|
+
# Warn on unused parameters to functions. Use `DDTRACE_UNUSED` to mark things as known-to-not-be-used.
|
270
|
+
# This is added as late as possible because in some Rubies we support (e.g. 3.3), adding this flag before
|
271
|
+
# checking if internal VM headers are available causes those checks to fail because of this warning (and not
|
272
|
+
# because the headers are not available.)
|
273
|
+
add_compiler_flag '-Wunused-parameter'
|
274
|
+
end
|
275
|
+
|
276
|
+
headers_available
|
259
277
|
end,
|
260
278
|
EXTENSION_NAME,
|
261
279
|
)
|
@@ -16,7 +16,6 @@ static ID agent_id; // id of :agent in Ruby
|
|
16
16
|
|
17
17
|
static ID log_failure_to_process_tag_id; // id of :log_failure_to_process_tag in Ruby
|
18
18
|
|
19
|
-
static VALUE http_transport_class = Qnil;
|
20
19
|
static VALUE library_version_string = Qnil;
|
21
20
|
|
22
21
|
struct call_exporter_without_gvl_arguments {
|
@@ -54,7 +53,7 @@ static void interrupt_exporter_call(void *cancel_token);
|
|
54
53
|
static VALUE ddtrace_version(void);
|
55
54
|
|
56
55
|
void http_transport_init(VALUE profiling_module) {
|
57
|
-
http_transport_class = rb_define_class_under(profiling_module, "HttpTransport", rb_cObject);
|
56
|
+
VALUE http_transport_class = rb_define_class_under(profiling_module, "HttpTransport", rb_cObject);
|
58
57
|
|
59
58
|
rb_define_singleton_method(http_transport_class, "_native_validate_exporter", _native_validate_exporter, 1);
|
60
59
|
rb_define_singleton_method(http_transport_class, "_native_do_export", _native_do_export, 12);
|
@@ -180,6 +179,10 @@ static ddog_Vec_Tag convert_tags(VALUE tags_as_array) {
|
|
180
179
|
}
|
181
180
|
|
182
181
|
static VALUE log_failure_to_process_tag(VALUE err_details) {
|
182
|
+
VALUE datadog_module = rb_const_get(rb_cObject, rb_intern("Datadog"));
|
183
|
+
VALUE profiling_module = rb_const_get(datadog_module, rb_intern("Profiling"));
|
184
|
+
VALUE http_transport_class = rb_const_get(profiling_module, rb_intern("HttpTransport"));
|
185
|
+
|
183
186
|
return rb_funcall(http_transport_class, log_failure_to_process_tag_id, 1, err_details);
|
184
187
|
}
|
185
188
|
|
@@ -58,9 +58,12 @@ static inline rb_thread_t *thread_struct_from_object(VALUE thread) {
|
|
58
58
|
}
|
59
59
|
|
60
60
|
rb_nativethread_id_t pthread_id_for(VALUE thread) {
|
61
|
-
// struct rb_native_thread was introduced in Ruby 3.2
|
61
|
+
// struct rb_native_thread was introduced in Ruby 3.2: https://github.com/ruby/ruby/pull/5836
|
62
62
|
#ifndef NO_RB_NATIVE_THREAD
|
63
|
-
|
63
|
+
struct rb_native_thread* native_thread = thread_struct_from_object(thread)->nt;
|
64
|
+
// This can be NULL on Ruby 3.3 with MN threads (RUBY_MN_THREADS=1)
|
65
|
+
if (native_thread == NULL) return 0;
|
66
|
+
return native_thread->thread_id;
|
64
67
|
#else
|
65
68
|
return thread_struct_from_object(thread)->thread_id;
|
66
69
|
#endif
|
@@ -113,15 +116,16 @@ bool is_current_thread_holding_the_gvl(void) {
|
|
113
116
|
|
114
117
|
if (current_owner == NULL) return (current_gvl_owner) {.valid = false};
|
115
118
|
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
119
|
+
#ifndef NO_RB_NATIVE_THREAD
|
120
|
+
struct rb_native_thread* current_owner_native_thread = current_owner->nt;
|
121
|
+
|
122
|
+
// This can be NULL on Ruby 3.3 with MN threads (RUBY_MN_THREADS=1)
|
123
|
+
if (current_owner_native_thread == NULL) return (current_gvl_owner) {.valid = false};
|
124
|
+
|
125
|
+
return (current_gvl_owner) {.valid = true, .owner = current_owner_native_thread->thread_id};
|
126
|
+
#else
|
127
|
+
return (current_gvl_owner) {.valid = true, .owner = current_owner->thread_id};
|
128
|
+
#endif
|
125
129
|
}
|
126
130
|
#else
|
127
131
|
current_gvl_owner gvl_owner(void) {
|
@@ -182,7 +186,9 @@ uint64_t native_thread_id_for(VALUE thread) {
|
|
182
186
|
// The tid is only available on Ruby >= 3.1 + Linux (and FreeBSD). It's the same as `gettid()` aka the task id as seen in /proc
|
183
187
|
#if !defined(NO_THREAD_TID) && defined(RB_THREAD_T_HAS_NATIVE_ID)
|
184
188
|
#ifndef NO_RB_NATIVE_THREAD
|
185
|
-
|
189
|
+
struct rb_native_thread* native_thread = thread_struct_from_object(thread)->nt;
|
190
|
+
if (native_thread == NULL) rb_raise(rb_eRuntimeError, "BUG: rb_native_thread* is null. Is this Ruby running with RUBY_MN_THREADS=1?");
|
191
|
+
return native_thread->tid;
|
186
192
|
#else
|
187
193
|
return thread_struct_from_object(thread)->tid;
|
188
194
|
#endif
|
@@ -407,6 +413,7 @@ calc_lineno(const rb_iseq_t *iseq, const VALUE *pc)
|
|
407
413
|
// the `VALUE` returned by rb_profile_frames returns `(eval)` instead of the path of the file where the `eval`
|
408
414
|
// was called from.
|
409
415
|
// * Imported fix from https://github.com/ruby/ruby/pull/7116 to avoid sampling threads that are still being created
|
416
|
+
// * Imported fix from https://github.com/ruby/ruby/pull/8415 to avoid potential crash when using YJIT.
|
410
417
|
//
|
411
418
|
// What is rb_profile_frames?
|
412
419
|
// `rb_profile_frames` is a Ruby VM debug API added for use by profilers for sampling the stack trace of a Ruby thread.
|
@@ -442,12 +449,15 @@ int ddtrace_rb_profile_frames(VALUE thread, int start, int limit, VALUE *buff, i
|
|
442
449
|
// Modified from upstream: Instead of using `GET_EC` to collect info from the current thread,
|
443
450
|
// support sampling any thread (including the current) passed as an argument
|
444
451
|
rb_thread_t *th = thread_struct_from_object(thread);
|
445
|
-
#ifndef USE_THREAD_INSTEAD_OF_EXECUTION_CONTEXT // Modern Rubies
|
446
|
-
|
447
|
-
#else // Ruby < 2.5
|
448
|
-
|
449
|
-
#endif
|
452
|
+
#ifndef USE_THREAD_INSTEAD_OF_EXECUTION_CONTEXT // Modern Rubies
|
453
|
+
const rb_execution_context_t *ec = th->ec;
|
454
|
+
#else // Ruby < 2.5
|
455
|
+
const rb_thread_t *ec = th;
|
456
|
+
#endif
|
450
457
|
const rb_control_frame_t *cfp = ec->cfp, *end_cfp = RUBY_VM_END_CONTROL_FRAME(ec);
|
458
|
+
#ifndef NO_JIT_RETURN
|
459
|
+
const rb_control_frame_t *top = cfp;
|
460
|
+
#endif
|
451
461
|
const rb_callable_method_entry_t *cme;
|
452
462
|
|
453
463
|
// Avoid sampling dead threads
|
@@ -522,7 +532,20 @@ int ddtrace_rb_profile_frames(VALUE thread, int start, int limit, VALUE *buff, i
|
|
522
532
|
buff[i] = (VALUE)cfp->iseq;
|
523
533
|
}
|
524
534
|
|
525
|
-
|
535
|
+
// The topmost frame may not have an updated PC because the JIT
|
536
|
+
// may not have set one. The JIT compiler will update the PC
|
537
|
+
// before entering a new function (so that `caller` will work),
|
538
|
+
// so only the topmost frame could possibly have an out of date PC
|
539
|
+
#ifndef NO_JIT_RETURN
|
540
|
+
if (cfp == top && cfp->jit_return) {
|
541
|
+
lines[i] = 0;
|
542
|
+
} else {
|
543
|
+
lines[i] = calc_lineno(cfp->iseq, cfp->pc);
|
544
|
+
}
|
545
|
+
#else // Ruby < 3.1
|
546
|
+
lines[i] = calc_lineno(cfp->iseq, cfp->pc);
|
547
|
+
#endif
|
548
|
+
|
526
549
|
is_ruby_frame[i] = true;
|
527
550
|
i++;
|
528
551
|
}
|
@@ -811,3 +834,40 @@ VALUE invoke_location_for(VALUE thread, int *line_location) {
|
|
811
834
|
*line_location = NUM2INT(rb_iseq_first_lineno(iseq));
|
812
835
|
return rb_iseq_path(iseq);
|
813
836
|
}
|
837
|
+
|
838
|
+
void self_test_mn_enabled(void) {
|
839
|
+
#ifdef NO_MN_THREADS_AVAILABLE
|
840
|
+
return;
|
841
|
+
#else
|
842
|
+
if (ddtrace_get_ractor()->threads.sched.enable_mn_threads == true) {
|
843
|
+
rb_raise(rb_eRuntimeError, "Ruby VM is running with RUBY_MN_THREADS=1. This is not yet supported");
|
844
|
+
}
|
845
|
+
#endif
|
846
|
+
}
|
847
|
+
|
848
|
+
// Taken from upstream imemo.h at commit 6ebcf25de2859b5b6402b7e8b181066c32d0e0bf (November 2023, master branch)
|
849
|
+
// (See the Ruby project copyright and license above)
|
850
|
+
// to enable calling rb_imemo_name
|
851
|
+
//
|
852
|
+
// Modifications:
|
853
|
+
// * Added IMEMO_MASK define
|
854
|
+
// * Changed return type to int to avoid having to define `enum imemo_type`
|
855
|
+
static inline int ddtrace_imemo_type(VALUE imemo) {
|
856
|
+
// This mask is the same between Ruby 2.5 and 3.3-preview3. Furthermore, the intention of this method is to be used
|
857
|
+
// to call `rb_imemo_name` which correctly handles invalid numbers so even if the mask changes in the future, at most
|
858
|
+
// we'll get incorrect results (and never a VM crash)
|
859
|
+
#define IMEMO_MASK 0x0f
|
860
|
+
return (RBASIC(imemo)->flags >> FL_USHIFT) & IMEMO_MASK;
|
861
|
+
}
|
862
|
+
|
863
|
+
// Safety: This function assumes the object passed in is of the imemo type. But in the worst case, you'll just get
|
864
|
+
// a string that doesn't make any sense.
|
865
|
+
#ifndef NO_IMEMO_NAME
|
866
|
+
const char *imemo_kind(VALUE imemo) {
|
867
|
+
return rb_imemo_name(ddtrace_imemo_type(imemo));
|
868
|
+
}
|
869
|
+
#else
|
870
|
+
const char *imemo_kind(__attribute__((unused)) VALUE imemo) {
|
871
|
+
return NULL;
|
872
|
+
}
|
873
|
+
#endif
|
@@ -49,3 +49,9 @@ bool ddtrace_rb_ractor_main_p(void);
|
|
49
49
|
// This is what Ruby shows in `Thread#to_s`.
|
50
50
|
// The file is returned directly, and the line is recorded onto *line_location.
|
51
51
|
VALUE invoke_location_for(VALUE thread, int *line_location);
|
52
|
+
|
53
|
+
// Check if RUBY_MN_THREADS is enabled (aka main Ractor is not doing 1:1 threads)
|
54
|
+
void self_test_mn_enabled(void);
|
55
|
+
|
56
|
+
// Provides more specific information on what kind an imemo is
|
57
|
+
const char *imemo_kind(VALUE imemo);
|
@@ -129,8 +129,6 @@
|
|
129
129
|
static VALUE ok_symbol = Qnil; // :ok in Ruby
|
130
130
|
static VALUE error_symbol = Qnil; // :error in Ruby
|
131
131
|
|
132
|
-
static VALUE stack_recorder_class = Qnil;
|
133
|
-
|
134
132
|
// Note: Please DO NOT use `VALUE_STRING` anywhere else, instead use `DDOG_CHARSLICE_C`.
|
135
133
|
// `VALUE_STRING` is only needed because older versions of gcc (4.9.2, used in our Ruby 2.2 CI test images)
|
136
134
|
// tripped when compiling `enabled_value_types` using `-std=gnu99` due to the extra cast that is included in
|
@@ -217,7 +215,7 @@ static VALUE _native_record_endpoint(DDTRACE_UNUSED VALUE _self, VALUE recorder_
|
|
217
215
|
static void reset_profile(ddog_prof_Profile *profile, ddog_Timespec *start_time /* Can be null */);
|
218
216
|
|
219
217
|
void stack_recorder_init(VALUE profiling_module) {
|
220
|
-
stack_recorder_class = rb_define_class_under(profiling_module, "StackRecorder", rb_cObject);
|
218
|
+
VALUE stack_recorder_class = rb_define_class_under(profiling_module, "StackRecorder", rb_cObject);
|
221
219
|
// Hosts methods used for testing the native code using RSpec
|
222
220
|
VALUE testing_module = rb_define_module_under(stack_recorder_class, "Testing");
|
223
221
|
|
@@ -38,12 +38,15 @@ module Datadog
|
|
38
38
|
|
39
39
|
data = AppSec::Processor::RuleLoader.load_data(
|
40
40
|
ip_denylist: settings.appsec.ip_denylist,
|
41
|
-
user_id_denylist: settings.appsec.user_id_denylist
|
41
|
+
user_id_denylist: settings.appsec.user_id_denylist,
|
42
42
|
)
|
43
43
|
|
44
|
+
exclusions = AppSec::Processor::RuleLoader.load_exclusions(ip_passlist: settings.appsec.ip_passlist)
|
45
|
+
|
44
46
|
ruleset = AppSec::Processor::RuleMerger.merge(
|
45
47
|
rules: [rules],
|
46
48
|
data: data,
|
49
|
+
exclusions: exclusions,
|
47
50
|
)
|
48
51
|
|
49
52
|
processor = Processor.new(ruleset: ruleset)
|
@@ -54,6 +54,10 @@ module Datadog
|
|
54
54
|
o.default :recommended
|
55
55
|
end
|
56
56
|
|
57
|
+
option :ip_passlist do |o|
|
58
|
+
o.default []
|
59
|
+
end
|
60
|
+
|
57
61
|
option :ip_denylist do |o|
|
58
62
|
o.type :array
|
59
63
|
o.default []
|
@@ -188,12 +192,6 @@ module Datadog
|
|
188
192
|
end
|
189
193
|
end
|
190
194
|
end
|
191
|
-
|
192
|
-
option :parse_response_body do |o|
|
193
|
-
o.type :bool
|
194
|
-
o.env 'DD_API_SECURITY_PARSE_RESPONSE_BODY'
|
195
|
-
o.default true
|
196
|
-
end
|
197
195
|
end
|
198
196
|
end
|
199
197
|
end
|
@@ -19,55 +19,9 @@ module Datadog
|
|
19
19
|
@scope = scope
|
20
20
|
end
|
21
21
|
|
22
|
-
def parsed_body
|
23
|
-
return unless Datadog.configuration.appsec.parse_response_body
|
24
|
-
|
25
|
-
unless body.instance_of?(Array)
|
26
|
-
Datadog.logger.debug do
|
27
|
-
"Response body type unsupported: #{body.class}"
|
28
|
-
end
|
29
|
-
return
|
30
|
-
end
|
31
|
-
|
32
|
-
return unless json_content_type?
|
33
|
-
|
34
|
-
result = ''.dup
|
35
|
-
all_body_parts_are_string = true
|
36
|
-
|
37
|
-
body.each do |body_part|
|
38
|
-
if body_part.is_a?(String)
|
39
|
-
result.concat(body_part)
|
40
|
-
else
|
41
|
-
all_body_parts_are_string = false
|
42
|
-
break
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
return unless all_body_parts_are_string
|
47
|
-
|
48
|
-
begin
|
49
|
-
JSON.parse(result)
|
50
|
-
rescue JSON::ParserError => e
|
51
|
-
Datadog.logger.debug { "Failed to parse response body. Error #{e.class}. Message #{e.message}" }
|
52
|
-
nil
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
22
|
def response
|
57
23
|
@response ||= ::Rack::Response.new(body, status, headers)
|
58
24
|
end
|
59
|
-
|
60
|
-
private
|
61
|
-
|
62
|
-
VALID_JSON_TYPES = [
|
63
|
-
'application/json',
|
64
|
-
'text/json'
|
65
|
-
].freeze
|
66
|
-
|
67
|
-
def json_content_type?
|
68
|
-
content_type = headers['content-type']
|
69
|
-
VALID_JSON_TYPES.include?(content_type)
|
70
|
-
end
|
71
25
|
end
|
72
26
|
end
|
73
27
|
end
|
@@ -10,7 +10,6 @@ module Datadog
|
|
10
10
|
ADDRESSES = [
|
11
11
|
'response.status',
|
12
12
|
'response.headers',
|
13
|
-
'response.body',
|
14
13
|
].freeze
|
15
14
|
private_constant :ADDRESSES
|
16
15
|
|
@@ -18,7 +17,6 @@ module Datadog
|
|
18
17
|
catch(:block) do
|
19
18
|
op.publish('response.status', gateway_response.status)
|
20
19
|
op.publish('response.headers', gateway_response.headers)
|
21
|
-
op.publish('response.body', gateway_response.parsed_body)
|
22
20
|
|
23
21
|
nil
|
24
22
|
end
|
@@ -31,7 +29,6 @@ module Datadog
|
|
31
29
|
response_status = values[0]
|
32
30
|
response_headers = values[1]
|
33
31
|
response_headers_no_cookies = response_headers.dup.tap { |h| h.delete('set-cookie') }
|
34
|
-
response_body = values[2]
|
35
32
|
|
36
33
|
waf_args = {
|
37
34
|
'server.response.status' => response_status.to_s,
|
@@ -39,8 +36,6 @@ module Datadog
|
|
39
36
|
'server.response.headers.no_cookies' => response_headers_no_cookies,
|
40
37
|
}
|
41
38
|
|
42
|
-
waf_args['server.response.body'] = response_body if response_body
|
43
|
-
|
44
39
|
waf_timeout = Datadog.configuration.appsec.waf_timeout
|
45
40
|
result = waf_context.run(waf_args, waf_timeout)
|
46
41
|
|
@@ -66,16 +66,6 @@ module Datadog
|
|
66
66
|
request_return = AppSec::Response.negotiate(env, blocked_event.last[:actions]).to_rack if blocked_event
|
67
67
|
end
|
68
68
|
|
69
|
-
if request_return[2].respond_to?(:to_ary)
|
70
|
-
# Following the Rack specification. The response body should only call :each once.
|
71
|
-
# Calling :to_ary returns an array with identical content as the produced when calling :each
|
72
|
-
# replacing request_return[2] with that new value allow us to safely operate on the response body.
|
73
|
-
# On Gateway::Response#parsed_body we might iterate over the reposne body using :each
|
74
|
-
# https://github.com/rack/rack/blob/main/SPEC.rdoc#enumerable-body-
|
75
|
-
consumed_body = request_return[2].to_ary
|
76
|
-
request_return[2] = consumed_body if consumed_body
|
77
|
-
end
|
78
|
-
|
79
69
|
gateway_response = Gateway::Response.new(
|
80
70
|
request_return[2],
|
81
71
|
request_return[0],
|