diff --git a/ext/stack_frames/buffer.c b/ext/stack_frames/buffer.c index 9eeb358..9a4ae80 100644 --- a/ext/stack_frames/buffer.c +++ b/ext/stack_frames/buffer.c @@ -124,15 +124,22 @@ static VALUE buffer_find(VALUE self) { return Qnil; } +static void raise_frame_reference_error() +{ + rb_raise(rb_eRuntimeError, "Stack frame is no longer valid, its buffer was re-used for another capture"); +} + VALUE stack_buffer_profile_frame(VALUE buffer_obj, int index) { buffer_t *buffer; TypedData_Get_Struct(buffer_obj, buffer_t, &buffer_data_type, buffer); + if (index >= buffer->length) raise_frame_reference_error(); return buffer->profile_frames[index]; } int stack_buffer_frame_lineno(VALUE buffer_obj, int index) { buffer_t *buffer; TypedData_Get_Struct(buffer_obj, buffer_t, &buffer_data_type, buffer); + if (index >= buffer->length) raise_frame_reference_error(); return buffer->lines[index]; } diff --git a/ext/stack_frames/extconf.rb b/ext/stack_frames/extconf.rb index 7b2b891..07cfd85 100644 --- a/ext/stack_frames/extconf.rb +++ b/ext/stack_frames/extconf.rb @@ -1,4 +1,4 @@ require 'mkmf' -$CFLAGS << ' -Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers' +$CFLAGS << ' -Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers -Wno-missing-noreturn' $CFLAGS << ' -Werror' if ENV['STACK_FRAMES_DEV'] create_makefile("stack_frames/stack_frames") diff --git a/test/stack_frames/buffer_test.rb b/test/stack_frames/buffer_test.rb index 1b65b37..ecdaf70 100644 --- a/test/stack_frames/buffer_test.rb +++ b/test/stack_frames/buffer_test.rb @@ -115,6 +115,20 @@ def test_gc_stress GC.stress = false end + def test_frame_invalidated_from_recapture + buffer = StackFrames::Buffer.new(100) + frame1 do + buffer.capture + end + last_index = buffer.length - 1 + frame = buffer[last_index] + buffer.capture + exc = assert_raises(RuntimeError) { frame.method_name } + assert_match(/\AStack frame is no longer valid,/, exc.message) + exc2 = assert_raises(RuntimeError) { frame.lineno } + assert_equal(exc.message, exc2.message) + end + private def skipping_c_frames?