datadog 2.7.1 → 2.9.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 (133) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +69 -1
  3. data/ext/datadog_profiling_native_extension/clock_id.h +2 -2
  4. data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +64 -54
  5. data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.c +1 -1
  6. data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.h +1 -1
  7. data/ext/datadog_profiling_native_extension/collectors_idle_sampling_helper.c +16 -16
  8. data/ext/datadog_profiling_native_extension/collectors_stack.c +7 -7
  9. data/ext/datadog_profiling_native_extension/collectors_thread_context.c +259 -132
  10. data/ext/datadog_profiling_native_extension/extconf.rb +0 -8
  11. data/ext/datadog_profiling_native_extension/heap_recorder.c +11 -89
  12. data/ext/datadog_profiling_native_extension/heap_recorder.h +1 -1
  13. data/ext/datadog_profiling_native_extension/http_transport.c +4 -4
  14. data/ext/datadog_profiling_native_extension/private_vm_api_access.c +4 -1
  15. data/ext/datadog_profiling_native_extension/private_vm_api_access.h +3 -1
  16. data/ext/datadog_profiling_native_extension/profiling.c +10 -8
  17. data/ext/datadog_profiling_native_extension/ruby_helpers.c +8 -8
  18. data/ext/datadog_profiling_native_extension/stack_recorder.c +54 -88
  19. data/ext/datadog_profiling_native_extension/stack_recorder.h +1 -1
  20. data/ext/datadog_profiling_native_extension/time_helpers.h +1 -1
  21. data/ext/datadog_profiling_native_extension/unsafe_api_calls_check.c +47 -0
  22. data/ext/datadog_profiling_native_extension/unsafe_api_calls_check.h +31 -0
  23. data/ext/libdatadog_api/crashtracker.c +3 -0
  24. data/ext/libdatadog_extconf_helpers.rb +1 -1
  25. data/lib/datadog/appsec/assets/waf_rules/recommended.json +355 -157
  26. data/lib/datadog/appsec/assets/waf_rules/strict.json +62 -32
  27. data/lib/datadog/appsec/component.rb +1 -8
  28. data/lib/datadog/appsec/context.rb +54 -0
  29. data/lib/datadog/appsec/contrib/active_record/instrumentation.rb +73 -0
  30. data/lib/datadog/appsec/contrib/active_record/integration.rb +41 -0
  31. data/lib/datadog/appsec/contrib/active_record/patcher.rb +53 -0
  32. data/lib/datadog/appsec/contrib/devise/patcher/authenticatable_patch.rb +6 -6
  33. data/lib/datadog/appsec/contrib/devise/patcher/registration_controller_patch.rb +4 -4
  34. data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +19 -28
  35. data/lib/datadog/appsec/contrib/graphql/reactive/multiplex.rb +5 -5
  36. data/lib/datadog/appsec/contrib/rack/gateway/response.rb +3 -3
  37. data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +64 -96
  38. data/lib/datadog/appsec/contrib/rack/reactive/request.rb +10 -10
  39. data/lib/datadog/appsec/contrib/rack/reactive/request_body.rb +5 -5
  40. data/lib/datadog/appsec/contrib/rack/reactive/response.rb +6 -6
  41. data/lib/datadog/appsec/contrib/rack/request_body_middleware.rb +10 -11
  42. data/lib/datadog/appsec/contrib/rack/request_middleware.rb +43 -49
  43. data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +21 -32
  44. data/lib/datadog/appsec/contrib/rails/patcher.rb +1 -1
  45. data/lib/datadog/appsec/contrib/rails/reactive/action.rb +6 -6
  46. data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +41 -63
  47. data/lib/datadog/appsec/contrib/sinatra/patcher.rb +2 -2
  48. data/lib/datadog/appsec/contrib/sinatra/reactive/routed.rb +5 -5
  49. data/lib/datadog/appsec/event.rb +6 -6
  50. data/lib/datadog/appsec/ext.rb +3 -1
  51. data/lib/datadog/appsec/monitor/gateway/watcher.rb +22 -32
  52. data/lib/datadog/appsec/monitor/reactive/set_user.rb +5 -5
  53. data/lib/datadog/appsec/processor/context.rb +2 -2
  54. data/lib/datadog/appsec/processor/rule_loader.rb +0 -3
  55. data/lib/datadog/appsec/remote.rb +1 -3
  56. data/lib/datadog/appsec/response.rb +7 -11
  57. data/lib/datadog/appsec.rb +6 -5
  58. data/lib/datadog/auto_instrument.rb +3 -0
  59. data/lib/datadog/core/configuration/agent_settings_resolver.rb +39 -11
  60. data/lib/datadog/core/configuration/components.rb +20 -2
  61. data/lib/datadog/core/configuration/settings.rb +10 -0
  62. data/lib/datadog/core/configuration.rb +10 -2
  63. data/lib/datadog/{tracing → core}/contrib/rails/utils.rb +1 -3
  64. data/lib/datadog/core/crashtracking/component.rb +1 -3
  65. data/lib/datadog/core/remote/client/capabilities.rb +6 -0
  66. data/lib/datadog/core/remote/client.rb +65 -59
  67. data/lib/datadog/core/telemetry/component.rb +9 -3
  68. data/lib/datadog/core/telemetry/event.rb +87 -3
  69. data/lib/datadog/core/telemetry/ext.rb +1 -0
  70. data/lib/datadog/core/telemetry/logging.rb +2 -2
  71. data/lib/datadog/core/telemetry/metric.rb +22 -0
  72. data/lib/datadog/core/telemetry/worker.rb +33 -0
  73. data/lib/datadog/di/base.rb +115 -0
  74. data/lib/datadog/di/code_tracker.rb +11 -7
  75. data/lib/datadog/di/component.rb +21 -11
  76. data/lib/datadog/di/configuration/settings.rb +11 -1
  77. data/lib/datadog/di/contrib/active_record.rb +1 -0
  78. data/lib/datadog/di/contrib/railtie.rb +15 -0
  79. data/lib/datadog/di/contrib.rb +26 -0
  80. data/lib/datadog/di/error.rb +5 -0
  81. data/lib/datadog/di/instrumenter.rb +111 -20
  82. data/lib/datadog/di/preload.rb +18 -0
  83. data/lib/datadog/di/probe.rb +11 -1
  84. data/lib/datadog/di/probe_builder.rb +1 -0
  85. data/lib/datadog/di/probe_manager.rb +8 -5
  86. data/lib/datadog/di/probe_notification_builder.rb +27 -7
  87. data/lib/datadog/di/probe_notifier_worker.rb +5 -6
  88. data/lib/datadog/di/remote.rb +124 -0
  89. data/lib/datadog/di/serializer.rb +14 -7
  90. data/lib/datadog/di/transport.rb +3 -5
  91. data/lib/datadog/di/utils.rb +7 -0
  92. data/lib/datadog/di.rb +23 -62
  93. data/lib/datadog/kit/appsec/events.rb +3 -3
  94. data/lib/datadog/kit/identity.rb +4 -4
  95. data/lib/datadog/profiling/component.rb +59 -69
  96. data/lib/datadog/profiling/http_transport.rb +1 -26
  97. data/lib/datadog/tracing/configuration/settings.rb +4 -8
  98. data/lib/datadog/tracing/contrib/action_cable/integration.rb +5 -2
  99. data/lib/datadog/tracing/contrib/action_mailer/integration.rb +6 -2
  100. data/lib/datadog/tracing/contrib/action_pack/integration.rb +5 -2
  101. data/lib/datadog/tracing/contrib/action_view/integration.rb +5 -2
  102. data/lib/datadog/tracing/contrib/active_job/integration.rb +5 -2
  103. data/lib/datadog/tracing/contrib/active_record/integration.rb +6 -2
  104. data/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +3 -1
  105. data/lib/datadog/tracing/contrib/active_support/cache/instrumentation.rb +3 -1
  106. data/lib/datadog/tracing/contrib/active_support/cache/redis.rb +16 -4
  107. data/lib/datadog/tracing/contrib/active_support/configuration/settings.rb +10 -0
  108. data/lib/datadog/tracing/contrib/active_support/integration.rb +5 -2
  109. data/lib/datadog/tracing/contrib/auto_instrument.rb +2 -2
  110. data/lib/datadog/tracing/contrib/aws/integration.rb +3 -0
  111. data/lib/datadog/tracing/contrib/concurrent_ruby/integration.rb +3 -0
  112. data/lib/datadog/tracing/contrib/elasticsearch/configuration/settings.rb +4 -0
  113. data/lib/datadog/tracing/contrib/elasticsearch/patcher.rb +6 -1
  114. data/lib/datadog/tracing/contrib/httprb/integration.rb +3 -0
  115. data/lib/datadog/tracing/contrib/kafka/integration.rb +3 -0
  116. data/lib/datadog/tracing/contrib/mongodb/integration.rb +3 -0
  117. data/lib/datadog/tracing/contrib/opensearch/integration.rb +3 -0
  118. data/lib/datadog/tracing/contrib/presto/integration.rb +3 -0
  119. data/lib/datadog/tracing/contrib/rack/integration.rb +2 -2
  120. data/lib/datadog/tracing/contrib/rails/framework.rb +2 -2
  121. data/lib/datadog/tracing/contrib/rails/patcher.rb +1 -1
  122. data/lib/datadog/tracing/contrib/rest_client/integration.rb +3 -0
  123. data/lib/datadog/tracing/span.rb +12 -4
  124. data/lib/datadog/tracing/span_event.rb +123 -3
  125. data/lib/datadog/tracing/span_operation.rb +6 -0
  126. data/lib/datadog/tracing/transport/serializable_trace.rb +24 -6
  127. data/lib/datadog/version.rb +2 -2
  128. data/lib/datadog.rb +3 -0
  129. metadata +30 -17
  130. data/lib/datadog/appsec/processor/actions.rb +0 -49
  131. data/lib/datadog/appsec/reactive/operation.rb +0 -68
  132. data/lib/datadog/appsec/scope.rb +0 -58
  133. data/lib/datadog/core/crashtracking/agent_base_url.rb +0 -21
@@ -173,18 +173,18 @@ static const uint8_t all_value_types_positions[] =
173
173
 
174
174
  // Struct for storing stats related to a profile in a particular slot.
175
175
  // These stats will share the same lifetime as the data in that profile slot.
176
- typedef struct slot_stats {
176
+ typedef struct {
177
177
  // How many individual samples were recorded into this slot (un-weighted)
178
178
  uint64_t recorded_samples;
179
179
  } stats_slot;
180
180
 
181
- typedef struct profile_slot {
181
+ typedef struct {
182
182
  ddog_prof_Profile profile;
183
183
  stats_slot stats;
184
184
  } profile_slot;
185
185
 
186
186
  // Contains native state for each instance
187
- struct stack_recorder_state {
187
+ typedef struct {
188
188
  // Heap recorder instance
189
189
  heap_recorder *heap_recorder;
190
190
  bool heap_clean_after_gc_enabled;
@@ -210,17 +210,17 @@ struct stack_recorder_state {
210
210
  long serialization_time_ns_max;
211
211
  uint64_t serialization_time_ns_total;
212
212
  } stats_lifetime;
213
- };
213
+ } stack_recorder_state;
214
214
 
215
215
  // Used to group mutex and the corresponding profile slot for easy unlocking after work is done.
216
- typedef struct locked_profile_slot {
216
+ typedef struct {
217
217
  pthread_mutex_t *mutex;
218
218
  profile_slot *data;
219
219
  } locked_profile_slot;
220
220
 
221
- struct call_serialize_without_gvl_arguments {
221
+ typedef struct {
222
222
  // Set by caller
223
- struct stack_recorder_state *state;
223
+ stack_recorder_state *state;
224
224
  ddog_Timespec finish_timestamp;
225
225
 
226
226
  // Set by callee
@@ -231,26 +231,26 @@ struct call_serialize_without_gvl_arguments {
231
231
 
232
232
  // Set by both
233
233
  bool serialize_ran;
234
- };
234
+ } call_serialize_without_gvl_arguments;
235
235
 
236
236
  static VALUE _native_new(VALUE klass);
237
- static void initialize_slot_concurrency_control(struct stack_recorder_state *state);
238
- static void initialize_profiles(struct stack_recorder_state *state, ddog_prof_Slice_ValueType sample_types);
237
+ static void initialize_slot_concurrency_control(stack_recorder_state *state);
238
+ static void initialize_profiles(stack_recorder_state *state, ddog_prof_Slice_ValueType sample_types);
239
239
  static void stack_recorder_typed_data_free(void *data);
240
240
  static VALUE _native_initialize(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _self);
241
241
  static VALUE _native_serialize(VALUE self, VALUE recorder_instance);
242
242
  static VALUE ruby_time_from(ddog_Timespec ddprof_time);
243
243
  static void *call_serialize_without_gvl(void *call_args);
244
- static locked_profile_slot sampler_lock_active_profile(struct stack_recorder_state *state);
244
+ static locked_profile_slot sampler_lock_active_profile(stack_recorder_state *state);
245
245
  static void sampler_unlock_active_profile(locked_profile_slot active_slot);
246
- static profile_slot* serializer_flip_active_and_inactive_slots(struct stack_recorder_state *state);
246
+ static profile_slot* serializer_flip_active_and_inactive_slots(stack_recorder_state *state);
247
247
  static VALUE _native_active_slot(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance);
248
248
  static VALUE _native_is_slot_one_mutex_locked(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance);
249
249
  static VALUE _native_is_slot_two_mutex_locked(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance);
250
250
  static VALUE test_slot_mutex_state(VALUE recorder_instance, int slot);
251
251
  static ddog_Timespec system_epoch_now_timespec(void);
252
252
  static VALUE _native_reset_after_fork(DDTRACE_UNUSED VALUE self, VALUE recorder_instance);
253
- static void serializer_set_start_timestamp_for_next_profile(struct stack_recorder_state *state, ddog_Timespec start_time);
253
+ static void serializer_set_start_timestamp_for_next_profile(stack_recorder_state *state, ddog_Timespec start_time);
254
254
  static VALUE _native_record_endpoint(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance, VALUE local_root_span_id, VALUE endpoint);
255
255
  static void reset_profile_slot(profile_slot *slot, ddog_Timespec *start_time /* Can be null */);
256
256
  static VALUE _native_track_object(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance, VALUE new_obj, VALUE weight, VALUE alloc_class);
@@ -258,8 +258,6 @@ static VALUE _native_check_heap_hashes(DDTRACE_UNUSED VALUE _self, VALUE locatio
258
258
  static VALUE _native_start_fake_slow_heap_serialization(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance);
259
259
  static VALUE _native_end_fake_slow_heap_serialization(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance);
260
260
  static VALUE _native_debug_heap_recorder(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance);
261
- static VALUE _native_gc_force_recycle(DDTRACE_UNUSED VALUE _self, VALUE obj);
262
- static VALUE _native_has_seen_id_flag(DDTRACE_UNUSED VALUE _self, VALUE obj);
263
261
  static VALUE _native_stats(DDTRACE_UNUSED VALUE self, VALUE instance);
264
262
  static VALUE build_profile_stats(profile_slot *slot, long serialization_time_ns, long heap_iteration_prep_time_ns, long heap_profile_build_time_ns);
265
263
  static VALUE _native_is_object_recorded(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance, VALUE object_id);
@@ -297,10 +295,6 @@ void stack_recorder_init(VALUE profiling_module) {
297
295
  _native_end_fake_slow_heap_serialization, 1);
298
296
  rb_define_singleton_method(testing_module, "_native_debug_heap_recorder",
299
297
  _native_debug_heap_recorder, 1);
300
- rb_define_singleton_method(testing_module, "_native_gc_force_recycle",
301
- _native_gc_force_recycle, 1);
302
- rb_define_singleton_method(testing_module, "_native_has_seen_id_flag",
303
- _native_has_seen_id_flag, 1);
304
298
  rb_define_singleton_method(testing_module, "_native_is_object_recorded?", _native_is_object_recorded, 2);
305
299
  rb_define_singleton_method(testing_module, "_native_heap_recorder_reset_last_update", _native_heap_recorder_reset_last_update, 1);
306
300
  rb_define_singleton_method(testing_module, "_native_recorder_after_gc_step", _native_recorder_after_gc_step, 1);
@@ -322,7 +316,7 @@ static const rb_data_type_t stack_recorder_typed_data = {
322
316
  };
323
317
 
324
318
  static VALUE _native_new(VALUE klass) {
325
- struct stack_recorder_state *state = ruby_xcalloc(1, sizeof(struct stack_recorder_state));
319
+ stack_recorder_state *state = ruby_xcalloc(1, sizeof(stack_recorder_state));
326
320
 
327
321
  // Note: Any exceptions raised from this note until the TypedData_Wrap_Struct call will lead to the state memory
328
322
  // being leaked.
@@ -360,7 +354,7 @@ static VALUE _native_new(VALUE klass) {
360
354
  return stack_recorder;
361
355
  }
362
356
 
363
- static void initialize_slot_concurrency_control(struct stack_recorder_state *state) {
357
+ static void initialize_slot_concurrency_control(stack_recorder_state *state) {
364
358
  state->mutex_slot_one = (pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER;
365
359
  state->mutex_slot_two = (pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER;
366
360
 
@@ -370,7 +364,7 @@ static void initialize_slot_concurrency_control(struct stack_recorder_state *sta
370
364
  state->active_slot = 1;
371
365
  }
372
366
 
373
- static void initialize_profiles(struct stack_recorder_state *state, ddog_prof_Slice_ValueType sample_types) {
367
+ static void initialize_profiles(stack_recorder_state *state, ddog_prof_Slice_ValueType sample_types) {
374
368
  ddog_prof_Profile_NewResult slot_one_profile_result =
375
369
  ddog_prof_Profile_new(sample_types, NULL /* period is optional */, NULL /* start_time is optional */);
376
370
 
@@ -397,7 +391,7 @@ static void initialize_profiles(struct stack_recorder_state *state, ddog_prof_Sl
397
391
  }
398
392
 
399
393
  static void stack_recorder_typed_data_free(void *state_ptr) {
400
- struct stack_recorder_state *state = (struct stack_recorder_state *) state_ptr;
394
+ stack_recorder_state *state = (stack_recorder_state *) state_ptr;
401
395
 
402
396
  pthread_mutex_destroy(&state->mutex_slot_one);
403
397
  ddog_prof_Profile_drop(&state->profile_slot_one.profile);
@@ -432,8 +426,8 @@ static VALUE _native_initialize(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _sel
432
426
  ENFORCE_BOOLEAN(timeline_enabled);
433
427
  ENFORCE_BOOLEAN(heap_clean_after_gc_enabled);
434
428
 
435
- struct stack_recorder_state *state;
436
- TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state);
429
+ stack_recorder_state *state;
430
+ TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state);
437
431
 
438
432
  state->heap_clean_after_gc_enabled = (heap_clean_after_gc_enabled == Qtrue);
439
433
 
@@ -523,8 +517,8 @@ static VALUE _native_initialize(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _sel
523
517
  }
524
518
 
525
519
  static VALUE _native_serialize(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance) {
526
- struct stack_recorder_state *state;
527
- TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state);
520
+ stack_recorder_state *state;
521
+ TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state);
528
522
 
529
523
  ddog_Timespec finish_timestamp = system_epoch_now_timespec();
530
524
  // Need to do this while still holding on to the Global VM Lock; see comments on method for why
@@ -538,7 +532,7 @@ static VALUE _native_serialize(DDTRACE_UNUSED VALUE _self, VALUE recorder_instan
538
532
 
539
533
  // We'll release the Global VM Lock while we're calling serialize, so that the Ruby VM can continue to work while this
540
534
  // is pending
541
- struct call_serialize_without_gvl_arguments args = {
535
+ call_serialize_without_gvl_arguments args = {
542
536
  .state = state,
543
537
  .finish_timestamp = finish_timestamp,
544
538
  .serialize_ran = false
@@ -603,8 +597,8 @@ static VALUE ruby_time_from(ddog_Timespec ddprof_time) {
603
597
  }
604
598
 
605
599
  void record_sample(VALUE recorder_instance, ddog_prof_Slice_Location locations, sample_values values, sample_labels labels) {
606
- struct stack_recorder_state *state;
607
- TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state);
600
+ stack_recorder_state *state;
601
+ TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state);
608
602
 
609
603
  locked_profile_slot active_slot = sampler_lock_active_profile(state);
610
604
 
@@ -658,8 +652,8 @@ void record_sample(VALUE recorder_instance, ddog_prof_Slice_Location locations,
658
652
  }
659
653
 
660
654
  void track_object(VALUE recorder_instance, VALUE new_object, unsigned int sample_weight, ddog_CharSlice *alloc_class) {
661
- struct stack_recorder_state *state;
662
- TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state);
655
+ stack_recorder_state *state;
656
+ TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state);
663
657
  // FIXME: Heap sampling currently has to be done in 2 parts because the construction of locations is happening
664
658
  // very late in the allocation-sampling path (which is shared with the cpu sampling path). This can
665
659
  // be fixed with some refactoring but for now this leads to a less impactful change.
@@ -667,8 +661,8 @@ void track_object(VALUE recorder_instance, VALUE new_object, unsigned int sample
667
661
  }
668
662
 
669
663
  void record_endpoint(VALUE recorder_instance, uint64_t local_root_span_id, ddog_CharSlice endpoint) {
670
- struct stack_recorder_state *state;
671
- TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state);
664
+ stack_recorder_state *state;
665
+ TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state);
672
666
 
673
667
  locked_profile_slot active_slot = sampler_lock_active_profile(state);
674
668
 
@@ -682,8 +676,8 @@ void record_endpoint(VALUE recorder_instance, uint64_t local_root_span_id, ddog_
682
676
  }
683
677
 
684
678
  void recorder_after_gc_step(VALUE recorder_instance) {
685
- struct stack_recorder_state *state;
686
- TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state);
679
+ stack_recorder_state *state;
680
+ TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state);
687
681
 
688
682
  if (state->heap_clean_after_gc_enabled) heap_recorder_update_young_objects(state->heap_recorder);
689
683
  }
@@ -693,7 +687,7 @@ void recorder_after_gc_step(VALUE recorder_instance) {
693
687
  // Heap recorder iteration context allows us access to stack recorder state and profile being serialized
694
688
  // during iteration of heap recorder live objects.
695
689
  typedef struct heap_recorder_iteration_context {
696
- struct stack_recorder_state *state;
690
+ stack_recorder_state *state;
697
691
  profile_slot *slot;
698
692
 
699
693
  bool error;
@@ -755,7 +749,7 @@ static bool add_heap_sample_to_active_profile_without_gvl(heap_recorder_iteratio
755
749
  return true;
756
750
  }
757
751
 
758
- static void build_heap_profile_without_gvl(struct stack_recorder_state *state, profile_slot *slot) {
752
+ static void build_heap_profile_without_gvl(stack_recorder_state *state, profile_slot *slot) {
759
753
  heap_recorder_iteration_context iteration_context = {
760
754
  .state = state,
761
755
  .slot = slot,
@@ -776,7 +770,7 @@ static void build_heap_profile_without_gvl(struct stack_recorder_state *state, p
776
770
  }
777
771
 
778
772
  static void *call_serialize_without_gvl(void *call_args) {
779
- struct call_serialize_without_gvl_arguments *args = (struct call_serialize_without_gvl_arguments *) call_args;
773
+ call_serialize_without_gvl_arguments *args = (call_serialize_without_gvl_arguments *) call_args;
780
774
 
781
775
  long serialize_no_gvl_start_time_ns = monotonic_wall_time_now_ns(DO_NOT_RAISE_ON_FAILURE);
782
776
 
@@ -802,7 +796,7 @@ VALUE enforce_recorder_instance(VALUE object) {
802
796
  return object;
803
797
  }
804
798
 
805
- static locked_profile_slot sampler_lock_active_profile(struct stack_recorder_state *state) {
799
+ static locked_profile_slot sampler_lock_active_profile(stack_recorder_state *state) {
806
800
  int error;
807
801
 
808
802
  for (int attempts = 0; attempts < 2; attempts++) {
@@ -829,7 +823,7 @@ static void sampler_unlock_active_profile(locked_profile_slot active_slot) {
829
823
  ENFORCE_SUCCESS_GVL(pthread_mutex_unlock(active_slot.mutex));
830
824
  }
831
825
 
832
- static profile_slot* serializer_flip_active_and_inactive_slots(struct stack_recorder_state *state) {
826
+ static profile_slot* serializer_flip_active_and_inactive_slots(stack_recorder_state *state) {
833
827
  int previously_active_slot = state->active_slot;
834
828
 
835
829
  if (previously_active_slot != 1 && previously_active_slot != 2) {
@@ -855,8 +849,8 @@ static profile_slot* serializer_flip_active_and_inactive_slots(struct stack_reco
855
849
  // This method exists only to enable testing Datadog::Profiling::StackRecorder behavior using RSpec.
856
850
  // It SHOULD NOT be used for other purposes.
857
851
  static VALUE _native_active_slot(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance) {
858
- struct stack_recorder_state *state;
859
- TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state);
852
+ stack_recorder_state *state;
853
+ TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state);
860
854
 
861
855
  return INT2NUM(state->active_slot);
862
856
  }
@@ -870,8 +864,8 @@ static VALUE _native_is_slot_one_mutex_locked(DDTRACE_UNUSED VALUE _self, VALUE
870
864
  static VALUE _native_is_slot_two_mutex_locked(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance) { return test_slot_mutex_state(recorder_instance, 2); }
871
865
 
872
866
  static VALUE test_slot_mutex_state(VALUE recorder_instance, int slot) {
873
- struct stack_recorder_state *state;
874
- TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state);
867
+ stack_recorder_state *state;
868
+ TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state);
875
869
 
876
870
  pthread_mutex_t *slot_mutex = (slot == 1) ? &state->mutex_slot_one : &state->mutex_slot_two;
877
871
 
@@ -901,8 +895,8 @@ static ddog_Timespec system_epoch_now_timespec(void) {
901
895
  // Assumption: This method gets called BEFORE restarting profiling -- e.g. there are no components attempting to
902
896
  // trigger samples at the same time.
903
897
  static VALUE _native_reset_after_fork(DDTRACE_UNUSED VALUE self, VALUE recorder_instance) {
904
- struct stack_recorder_state *state;
905
- TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state);
898
+ stack_recorder_state *state;
899
+ TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state);
906
900
 
907
901
  // In case the fork happened halfway through `serializer_flip_active_and_inactive_slots` execution and the
908
902
  // resulting state is inconsistent, we make sure to reset it back to the initial state.
@@ -918,7 +912,7 @@ static VALUE _native_reset_after_fork(DDTRACE_UNUSED VALUE self, VALUE recorder_
918
912
 
919
913
  // Assumption 1: This method is called with the GVL being held, because `ddog_prof_Profile_reset` mutates the profile and must
920
914
  // not be interrupted part-way through by a VM fork.
921
- static void serializer_set_start_timestamp_for_next_profile(struct stack_recorder_state *state, ddog_Timespec start_time) {
915
+ static void serializer_set_start_timestamp_for_next_profile(stack_recorder_state *state, ddog_Timespec start_time) {
922
916
  // Before making this profile active, we reset it so that it uses the correct start_time for its start
923
917
  profile_slot *next_profile_slot = (state->active_slot == 1) ? &state->profile_slot_two : &state->profile_slot_one;
924
918
  reset_profile_slot(next_profile_slot, &start_time);
@@ -978,8 +972,8 @@ static void reset_profile_slot(profile_slot *slot, ddog_Timespec *start_time /*
978
972
  // This method exists only to enable testing Datadog::Profiling::StackRecorder behavior using RSpec.
979
973
  // It SHOULD NOT be used for other purposes.
980
974
  static VALUE _native_start_fake_slow_heap_serialization(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance) {
981
- struct stack_recorder_state *state;
982
- TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state);
975
+ stack_recorder_state *state;
976
+ TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state);
983
977
 
984
978
  heap_recorder_prepare_iteration(state->heap_recorder);
985
979
 
@@ -989,8 +983,8 @@ static VALUE _native_start_fake_slow_heap_serialization(DDTRACE_UNUSED VALUE _se
989
983
  // This method exists only to enable testing Datadog::Profiling::StackRecorder behavior using RSpec.
990
984
  // It SHOULD NOT be used for other purposes.
991
985
  static VALUE _native_end_fake_slow_heap_serialization(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance) {
992
- struct stack_recorder_state *state;
993
- TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state);
986
+ stack_recorder_state *state;
987
+ TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state);
994
988
 
995
989
  heap_recorder_finish_iteration(state->heap_recorder);
996
990
 
@@ -1000,43 +994,15 @@ static VALUE _native_end_fake_slow_heap_serialization(DDTRACE_UNUSED VALUE _self
1000
994
  // This method exists only to enable testing Datadog::Profiling::StackRecorder behavior using RSpec.
1001
995
  // It SHOULD NOT be used for other purposes.
1002
996
  static VALUE _native_debug_heap_recorder(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance) {
1003
- struct stack_recorder_state *state;
1004
- TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state);
997
+ stack_recorder_state *state;
998
+ TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state);
1005
999
 
1006
1000
  return heap_recorder_testonly_debug(state->heap_recorder);
1007
1001
  }
1008
1002
 
1009
- #pragma GCC diagnostic push
1010
- // rb_gc_force_recycle was deprecated in latest versions of Ruby and is a noop.
1011
- #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
1012
- #pragma GCC diagnostic ignored "-Wunused-parameter"
1013
- // This method exists only to enable testing Datadog::Profiling::StackRecorder behavior using RSpec.
1014
- // It SHOULD NOT be used for other purposes.
1015
- static VALUE _native_gc_force_recycle(DDTRACE_UNUSED VALUE _self, VALUE obj) {
1016
- #ifdef HAVE_WORKING_RB_GC_FORCE_RECYCLE
1017
- rb_gc_force_recycle(obj);
1018
- #endif
1019
- return Qnil;
1020
- }
1021
- #pragma GCC diagnostic pop
1022
-
1023
- // This method exists only to enable testing Datadog::Profiling::StackRecorder behavior using RSpec.
1024
- // It SHOULD NOT be used for other purposes.
1025
- static VALUE _native_has_seen_id_flag(DDTRACE_UNUSED VALUE _self, VALUE obj) {
1026
- #ifndef NO_SEEN_OBJ_ID_FLAG
1027
- if (RB_FL_TEST(obj, RUBY_FL_SEEN_OBJ_ID)) {
1028
- return Qtrue;
1029
- } else {
1030
- return Qfalse;
1031
- }
1032
- #else
1033
- return Qfalse;
1034
- #endif
1035
- }
1036
-
1037
1003
  static VALUE _native_stats(DDTRACE_UNUSED VALUE self, VALUE recorder_instance) {
1038
- struct stack_recorder_state *state;
1039
- TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state);
1004
+ stack_recorder_state *state;
1005
+ TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state);
1040
1006
 
1041
1007
  uint64_t total_serializations = state->stats_lifetime.serialization_successes + state->stats_lifetime.serialization_failures;
1042
1008
 
@@ -1074,15 +1040,15 @@ static VALUE build_profile_stats(profile_slot *slot, long serialization_time_ns,
1074
1040
  static VALUE _native_is_object_recorded(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance, VALUE obj_id) {
1075
1041
  ENFORCE_TYPE(obj_id, T_FIXNUM);
1076
1042
 
1077
- struct stack_recorder_state *state;
1078
- TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state);
1043
+ stack_recorder_state *state;
1044
+ TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state);
1079
1045
 
1080
1046
  return heap_recorder_testonly_is_object_recorded(state->heap_recorder, obj_id);
1081
1047
  }
1082
1048
 
1083
1049
  static VALUE _native_heap_recorder_reset_last_update(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance) {
1084
- struct stack_recorder_state *state;
1085
- TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state);
1050
+ stack_recorder_state *state;
1051
+ TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state);
1086
1052
 
1087
1053
  heap_recorder_testonly_reset_last_update(state->heap_recorder);
1088
1054
 
@@ -13,7 +13,7 @@ typedef struct {
13
13
  int64_t timeline_wall_time_ns;
14
14
  } sample_values;
15
15
 
16
- typedef struct sample_labels {
16
+ typedef struct {
17
17
  ddog_prof_Slice_Label labels;
18
18
 
19
19
  // This is used to allow the `Collectors::Stack` to modify the existing label, if any. This MUST be NULL or point
@@ -39,7 +39,7 @@ static inline long system_epoch_time_now_ns(raise_on_failure_setting raise_on_fa
39
39
  // https://docs.redhat.com/en/documentation/red_hat_enterprise_linux_for_real_time/7/html/reference_guide/sect-posix_clocks#Using_clock_getres_to_compare_clock_resolution
40
40
  // We introduce here a separate type for it, so as to make it harder to misuse/more explicit when these timestamps are used
41
41
 
42
- typedef struct coarse_instant {
42
+ typedef struct {
43
43
  long timestamp_ns;
44
44
  } coarse_instant;
45
45
 
@@ -0,0 +1,47 @@
1
+ #include <ruby.h>
2
+ #include <ruby/debug.h>
3
+ #include <stdbool.h>
4
+
5
+ #include "datadog_ruby_common.h"
6
+ #include "unsafe_api_calls_check.h"
7
+ #include "extconf.h"
8
+
9
+ static bool inside_unsafe_context = false;
10
+
11
+ #ifndef NO_POSTPONED_TRIGGER
12
+ static rb_postponed_job_handle_t check_for_unsafe_api_calls_handle;
13
+ #endif
14
+
15
+ static void check_for_unsafe_api_calls(DDTRACE_UNUSED void *_unused);
16
+
17
+ void unsafe_api_calls_check_init(void) {
18
+ #ifndef NO_POSTPONED_TRIGGER
19
+ int unused_flags = 0;
20
+
21
+ check_for_unsafe_api_calls_handle = rb_postponed_job_preregister(unused_flags, check_for_unsafe_api_calls, NULL);
22
+
23
+ if (check_for_unsafe_api_calls_handle == POSTPONED_JOB_HANDLE_INVALID) {
24
+ rb_raise(rb_eRuntimeError, "Failed to register check_for_unsafe_api_calls_handle postponed job (got POSTPONED_JOB_HANDLE_INVALID)");
25
+ }
26
+ #endif
27
+ }
28
+
29
+ void debug_enter_unsafe_context(void) {
30
+ inside_unsafe_context = true;
31
+
32
+ #ifndef NO_POSTPONED_TRIGGER
33
+ rb_postponed_job_trigger(check_for_unsafe_api_calls_handle);
34
+ #else
35
+ rb_postponed_job_register(0, check_for_unsafe_api_calls, NULL);
36
+ #endif
37
+ }
38
+
39
+ void debug_leave_unsafe_context(void) {
40
+ inside_unsafe_context = false;
41
+ }
42
+
43
+ static void check_for_unsafe_api_calls(DDTRACE_UNUSED void *_unused) {
44
+ if (inside_unsafe_context) rb_bug(
45
+ "Datadog Ruby profiler detected callback nested inside sample. Please report this at https://github.com/datadog/dd-trace-rb/blob/master/CONTRIBUTING.md#found-a-bug"
46
+ );
47
+ }
@@ -0,0 +1,31 @@
1
+ #pragma once
2
+
3
+ // This checker is used to detect accidental thread scheduling switching points happening during profiling sampling.
4
+ //
5
+ // Specifically, when the profiler is sampling, we're never supposed to call into Ruby code (e.g. methods
6
+ // implemented using Ruby code) or allocate Ruby objects.
7
+ // That's because those events introduce thread switch points, and really we don't the VM switching between threads
8
+ // in the middle of the profiler sampling.
9
+ // This includes raising exceptions, unless we're trying to stop the profiler, and even then we must be careful.
10
+ //
11
+ // The above is especially true in situations such as GC profiling or allocation/heap profiling, as in those situations
12
+ // we can even crash the Ruby VM if we switch away at the wrong time.
13
+ //
14
+ // The below APIs can be used to detect these situations. They work by relying on the following observation:
15
+ // in most (all?) thread switch points, Ruby will check for interrupts and run the postponed jobs.
16
+ //
17
+ // Thus, if we set a flag while we're sampling (inside_unsafe_context), trigger the postponed job, and then only unset
18
+ // the flag after sampling, he correct thing to happen is that the postponed job should never see the flag.
19
+ //
20
+ // If, however, we have a bug and there's a thread switch point, our postponed job will see the flag and immediately
21
+ // stop the Ruby VM before further damage happens (and hopefully giving us a stack trace clearly pointing to the culprit).
22
+
23
+ void unsafe_api_calls_check_init(void);
24
+
25
+ // IMPORTANT: This method **MUST** only be called from test code, as it causes an immediate hard-crash on the Ruby VM
26
+ // when it detects a potential issue, and that's not something we want for production apps.
27
+ //
28
+ // In the future we may introduce some kind of setting (off by default) to also allow this to be safely be used
29
+ // in production code if needed.
30
+ void debug_enter_unsafe_context(void);
31
+ void debug_leave_unsafe_context(void);
@@ -54,6 +54,9 @@ static VALUE _native_start_or_update_on_fork(int argc, VALUE *argv, DDTRACE_UNUS
54
54
  // Tags and endpoint are heap-allocated, so after here we can't raise exceptions otherwise we'll leak this memory
55
55
  // Start of exception-free zone to prevent leaks {{
56
56
  ddog_Endpoint *endpoint = ddog_endpoint_from_url(char_slice_from_ruby_string(agent_base_url));
57
+ if (endpoint == NULL) {
58
+ rb_raise(rb_eRuntimeError, "Failed to create endpoint from agent_base_url: %"PRIsVALUE, agent_base_url);
59
+ }
57
60
  ddog_Vec_Tag tags = convert_tags(tags_as_array);
58
61
 
59
62
  ddog_crasht_Config config = {
@@ -8,7 +8,7 @@ module Datadog
8
8
  module LibdatadogExtconfHelpers
9
9
  # Used to make sure the correct gem version gets loaded, as extconf.rb does not get run with "bundle exec" and thus
10
10
  # may see multiple libdatadog versions. See https://github.com/DataDog/dd-trace-rb/pull/2531 for the horror story.
11
- LIBDATADOG_VERSION = '~> 14.1.0.1.0'
11
+ LIBDATADOG_VERSION = '~> 14.3.1.1.0'
12
12
 
13
13
  # Used as an workaround for a limitation with how dynamic linking works in environments where the datadog gem and
14
14
  # libdatadog are moved after the extension gets compiled.