From 7b9a7ef24716cd3bbd1a9eeefa9ea5a9058b0b49 Mon Sep 17 00:00:00 2001 From: Neel Shah Date: Mon, 1 Jun 2026 17:35:42 +0200 Subject: [PATCH] fix(stacktrace): stop leaking internal frame state into event payload MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Interface#to_h serializes every instance variable, so helper ivars stored on StacktraceInterface::Frame leaked into the event payload. The FilenameCache change (#2904) made this worse by serializing "#" — a memory address that differs on every run — into every frame. Pass filename_cache/strip_backtrace_load_path through the constructor instead of storing them as ivars, so they never reach to_h. This also drops the pre-existing project_root/strip_backtrace_load_path leaks. All real frame fields are unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) --- sentry-ruby/lib/sentry/interfaces/stacktrace.rb | 9 +-------- sentry-ruby/spec/sentry/interfaces/stacktrace_spec.rb | 7 +++++++ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/sentry-ruby/lib/sentry/interfaces/stacktrace.rb b/sentry-ruby/lib/sentry/interfaces/stacktrace.rb index dae34a3ab..71acb7def 100644 --- a/sentry-ruby/lib/sentry/interfaces/stacktrace.rb +++ b/sentry-ruby/lib/sentry/interfaces/stacktrace.rb @@ -28,25 +28,18 @@ class Frame < Interface :lineno, :module, :pre_context, :post_context, :vars def initialize(project_root, line, strip_backtrace_load_path = true, filename_cache: nil) - @strip_backtrace_load_path = strip_backtrace_load_path - @filename_cache = filename_cache - @abs_path = line.file @function = line.method if line.method @lineno = line.number @in_app = line.in_app @module = line.module_name if line.module_name - @filename = compute_filename + @filename = filename_cache&.compute_filename(@abs_path, @in_app, strip_backtrace_load_path) end def to_s "#{@filename}:#{@lineno}" end - def compute_filename - @filename_cache&.compute_filename(abs_path, in_app, @strip_backtrace_load_path) - end - def set_context(linecache, context_lines) return unless abs_path diff --git a/sentry-ruby/spec/sentry/interfaces/stacktrace_spec.rb b/sentry-ruby/spec/sentry/interfaces/stacktrace_spec.rb index b12935264..df20963f2 100644 --- a/sentry-ruby/spec/sentry/interfaces/stacktrace_spec.rb +++ b/sentry-ruby/spec/sentry/interfaces/stacktrace_spec.rb @@ -30,6 +30,13 @@ expect(second_frame.lineno).to eq(5) end + it "does not leak internal state into the serialized frame payload" do + frame = Sentry::StacktraceInterface::Frame.new(configuration.project_root, lines.last, true, filename_cache: filename_cache) + + expect(frame.to_h.keys).to contain_exactly(:abs_path, :function, :lineno, :in_app, :filename) + expect(frame.to_h).not_to include(:project_root, :strip_backtrace_load_path, :filename_cache) + end + it "does not strip load path when strip_backtrace_load_path is false" do first_frame = Sentry::StacktraceInterface::Frame.new(configuration.project_root, lines.first, false, filename_cache: filename_cache) expect(first_frame.filename).to eq(first_frame.abs_path)