ddtrace 1.16.0 → 1.18.0

Sign up to get free protection for your applications and to get access to all the features.
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],