ddtrace 1.16.0 → 1.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +86 -1
  3. data/ext/ddtrace_profiling_native_extension/clock_id_from_pthread.c +3 -0
  4. data/ext/ddtrace_profiling_native_extension/collectors_thread_context.c +8 -1
  5. data/ext/ddtrace_profiling_native_extension/extconf.rb +28 -10
  6. data/ext/ddtrace_profiling_native_extension/http_transport.c +5 -2
  7. data/ext/ddtrace_profiling_native_extension/private_vm_api_access.c +78 -18
  8. data/ext/ddtrace_profiling_native_extension/private_vm_api_access.h +6 -0
  9. data/ext/ddtrace_profiling_native_extension/profiling.c +1 -0
  10. data/ext/ddtrace_profiling_native_extension/stack_recorder.c +1 -3
  11. data/lib/datadog/appsec/component.rb +4 -1
  12. data/lib/datadog/appsec/configuration/settings.rb +4 -6
  13. data/lib/datadog/appsec/contrib/devise/patcher/registration_controller_patch.rb +2 -0
  14. data/lib/datadog/appsec/contrib/rack/gateway/response.rb +0 -46
  15. data/lib/datadog/appsec/contrib/rack/reactive/response.rb +0 -5
  16. data/lib/datadog/appsec/contrib/rack/request_middleware.rb +0 -10
  17. data/lib/datadog/appsec/processor/rule_loader.rb +60 -0
  18. data/lib/datadog/appsec/remote.rb +12 -9
  19. data/lib/datadog/core/configuration/settings.rb +1 -1
  20. data/lib/datadog/core/configuration.rb +4 -0
  21. data/lib/datadog/core/remote/worker.rb +1 -0
  22. data/lib/datadog/core/workers/async.rb +1 -0
  23. data/lib/datadog/kit/enable_core_dumps.rb +5 -6
  24. data/lib/datadog/opentelemetry/sdk/span_processor.rb +39 -8
  25. data/lib/datadog/opentelemetry/sdk/trace/span.rb +102 -3
  26. data/lib/datadog/opentracer/text_map_propagator.rb +2 -1
  27. data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +1 -0
  28. data/lib/datadog/profiling/collectors/idle_sampling_helper.rb +1 -0
  29. data/lib/datadog/profiling/component.rb +13 -5
  30. data/lib/datadog/tracing/configuration/ext.rb +3 -0
  31. data/lib/datadog/tracing/configuration/settings.rb +18 -3
  32. data/lib/datadog/tracing/contrib/concurrent_ruby/context_composite_executor_service.rb +1 -1
  33. data/lib/datadog/tracing/contrib/pg/configuration/settings.rb +5 -0
  34. data/lib/datadog/tracing/contrib/pg/instrumentation.rb +24 -0
  35. data/lib/datadog/tracing/distributed/datadog.rb +0 -1
  36. data/lib/datadog/tracing/distributed/propagation.rb +25 -4
  37. data/lib/datadog/tracing/trace_digest.rb +31 -0
  38. data/lib/datadog/tracing/workers.rb +1 -0
  39. data/lib/ddtrace/version.rb +1 -1
  40. metadata +7 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 59aaa9c3c11af9219405c9eee4e318df4cafdaae57eb42c7b5105d46764d3293
4
- data.tar.gz: ef0d6766221287a4e9d42bf42f43fd5ddd81990ea381e536b5083be8a3f0b94d
3
+ metadata.gz: 69e775ab06a83ce14114a7287056e3d3fb575191b7ff6ccdc5c7b33f7fd58172
4
+ data.tar.gz: 13b607a4e29e516be4988dca7827eca09b79e968cf98e0641a155039d2ec3273
5
5
  SHA512:
6
- metadata.gz: 0201e1fd1e96ea0a076cf88af3824cb02f15862312eb26688db474caec2698bdfee9381b947e4ab278bbaa752aeb8a92df2f2188aa7e4ba988e5cdc31331f138
7
- data.tar.gz: 2a034e4187f41b85a29d7003fbe1098552cdddf0be663e490ab2ca71c4da40a8ad122f3357b11286af10df988f0891cc8d2d71ca59d9949db790dda6011033d0
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.16.0...master
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
- class_name = DDOG_CHARSLICE_C("(VM Internal, T_IMEMO)");
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
- have_header('vm_core.h') &&
257
- have_header('iseq.h') &&
258
- (RUBY_VERSION < '3.3' || have_header('ractor_core.h'))
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 (preview2): https://github.com/ruby/ruby/pull/5836
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
- return thread_struct_from_object(thread)->nt->thread_id;
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
- return (current_gvl_owner) {
117
- .valid = true,
118
- .owner =
119
- #ifndef NO_RB_NATIVE_THREAD
120
- current_owner->nt->thread_id
121
- #else
122
- current_owner->thread_id
123
- #endif
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
- return thread_struct_from_object(thread)->nt->tid;
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
- const rb_execution_context_t *ec = th->ec;
447
- #else // Ruby < 2.5
448
- const rb_thread_t *ec = th;
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
- lines[i] = calc_lineno(cfp->iseq, cfp->pc);
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);
@@ -68,6 +68,7 @@ void DDTRACE_EXPORT Init_ddtrace_profiling_native_extension(void) {
68
68
 
69
69
  static VALUE native_working_p(DDTRACE_UNUSED VALUE _self) {
70
70
  self_test_clock_id();
71
+ self_test_mn_enabled();
71
72
 
72
73
  return Qtrue;
73
74
  }
@@ -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
@@ -42,6 +42,8 @@ module Datadog
42
42
  **event_information.to_h
43
43
  )
44
44
  end
45
+
46
+ yield resource if block_given?
45
47
  end
46
48
  end
47
49
  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],