Skip to content

Commit 804add8

Browse files
authored
Merge pull request #243 from dalehamel/fix/gc-frame-race-condition-minimal
Fix data race in GC frame recording between signal handler and postponed job.
2 parents 8d57d8e + b9e7f5b commit 804add8

1 file changed

Lines changed: 22 additions & 21 deletions

File tree

ext/stackprof/stackprof.c

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -537,7 +537,7 @@ st_numtable_increment(st_table *table, st_data_t key, size_t increment)
537537
}
538538

539539
void
540-
stackprof_record_sample_for_stack(int num, uint64_t sample_timestamp, int64_t timestamp_delta)
540+
stackprof_record_sample_for_stack(int num, VALUE *frames_buffer, int *lines_buffer, uint64_t sample_timestamp, int64_t timestamp_delta)
541541
{
542542
int i, n;
543543
VALUE prev_frame = Qnil;
@@ -571,8 +571,8 @@ stackprof_record_sample_for_stack(int num, uint64_t sample_timestamp, int64_t ti
571571
* in the raw buffer are stored in the opposite direction of stacks
572572
* in the frames buffer that came from Ruby. */
573573
for (i = num-1, n = 0; i >= 0; i--, n++) {
574-
VALUE frame = _stackprof.frames_buffer[i];
575-
int line = _stackprof.lines_buffer[i];
574+
VALUE frame = frames_buffer[i];
575+
int line = lines_buffer[i];
576576

577577
// Encode the line in to the upper 16 bits.
578578
uint64_t key = ((uint64_t)line << 48) | (uint64_t)frame;
@@ -594,8 +594,8 @@ stackprof_record_sample_for_stack(int num, uint64_t sample_timestamp, int64_t ti
594594
_stackprof.raw_sample_index = _stackprof.raw_samples_len;
595595
_stackprof.raw_samples[_stackprof.raw_samples_len++] = (VALUE)num;
596596
for (i = num-1; i >= 0; i--) {
597-
VALUE frame = _stackprof.frames_buffer[i];
598-
int line = _stackprof.lines_buffer[i];
597+
VALUE frame = frames_buffer[i];
598+
int line = lines_buffer[i];
599599

600600
// Encode the line in to the upper 16 bits.
601601
uint64_t key = ((uint64_t)line << 48) | (uint64_t)frame;
@@ -626,8 +626,8 @@ stackprof_record_sample_for_stack(int num, uint64_t sample_timestamp, int64_t ti
626626
}
627627

628628
for (i = 0; i < num; i++) {
629-
int line = _stackprof.lines_buffer[i];
630-
VALUE frame = _stackprof.frames_buffer[i];
629+
int line = lines_buffer[i];
630+
VALUE frame = frames_buffer[i];
631631
frame_data_t *frame_data = sample_for(frame);
632632

633633
if (frame_data->seen_at_sample_number != _stackprof.overall_samples) {
@@ -710,27 +710,28 @@ stackprof_record_gc_samples(void)
710710
for (i = 0; i < _stackprof.unrecorded_gc_samples; i++) {
711711
int64_t timestamp_delta = i == 0 ? delta_to_first_unrecorded_gc_sample : NUM2LONG(_stackprof.interval);
712712

713+
/* Use local arrays for GC frames to avoid a data race with the
714+
* signal handler, which can overwrite _stackprof.frames_buffer
715+
* via stackprof_buffer_sample/rb_profile_frames at any time. */
716+
VALUE gc_frames[2];
717+
int gc_lines[2] = {0, 0};
718+
713719
if (_stackprof.unrecorded_gc_marking_samples) {
714-
_stackprof.frames_buffer[0] = FAKE_FRAME_MARK;
715-
_stackprof.lines_buffer[0] = 0;
716-
_stackprof.frames_buffer[1] = FAKE_FRAME_GC;
717-
_stackprof.lines_buffer[1] = 0;
720+
gc_frames[0] = FAKE_FRAME_MARK;
721+
gc_frames[1] = FAKE_FRAME_GC;
718722
_stackprof.unrecorded_gc_marking_samples--;
719723

720-
stackprof_record_sample_for_stack(2, start_timestamp, timestamp_delta);
724+
stackprof_record_sample_for_stack(2, gc_frames, gc_lines, start_timestamp, timestamp_delta);
721725
} else if (_stackprof.unrecorded_gc_sweeping_samples) {
722-
_stackprof.frames_buffer[0] = FAKE_FRAME_SWEEP;
723-
_stackprof.lines_buffer[0] = 0;
724-
_stackprof.frames_buffer[1] = FAKE_FRAME_GC;
725-
_stackprof.lines_buffer[1] = 0;
726+
gc_frames[0] = FAKE_FRAME_SWEEP;
727+
gc_frames[1] = FAKE_FRAME_GC;
726728

727729
_stackprof.unrecorded_gc_sweeping_samples--;
728730

729-
stackprof_record_sample_for_stack(2, start_timestamp, timestamp_delta);
731+
stackprof_record_sample_for_stack(2, gc_frames, gc_lines, start_timestamp, timestamp_delta);
730732
} else {
731-
_stackprof.frames_buffer[0] = FAKE_FRAME_GC;
732-
_stackprof.lines_buffer[0] = 0;
733-
stackprof_record_sample_for_stack(1, start_timestamp, timestamp_delta);
733+
gc_frames[0] = FAKE_FRAME_GC;
734+
stackprof_record_sample_for_stack(1, gc_frames, gc_lines, start_timestamp, timestamp_delta);
734735
}
735736
}
736737
_stackprof.during_gc += _stackprof.unrecorded_gc_samples;
@@ -743,7 +744,7 @@ stackprof_record_gc_samples(void)
743744
static void
744745
stackprof_record_buffer(void)
745746
{
746-
stackprof_record_sample_for_stack(_stackprof.buffer_count, _stackprof.buffer_time.timestamp_usec, _stackprof.buffer_time.delta_usec);
747+
stackprof_record_sample_for_stack(_stackprof.buffer_count, _stackprof.frames_buffer, _stackprof.lines_buffer, _stackprof.buffer_time.timestamp_usec, _stackprof.buffer_time.delta_usec);
747748

748749
// reset the buffer
749750
_stackprof.buffer_count = 0;

0 commit comments

Comments
 (0)