From 546f8467f2af4e7ded7571caf91da85e1b12bc97 Mon Sep 17 00:00:00 2001 From: Kyrylo Silin Date: Wed, 29 Nov 2017 13:00:08 +0200 Subject: [PATCH] truncator: fix circular references Fixes #285 (Error in stackframe json) --- CHANGELOG.md | 4 ++++ lib/airbrake-ruby/truncator.rb | 10 +++++++++- spec/truncator_spec.rb | 23 +++++++++++++++++++++++ 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b939a708..3288beab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,10 @@ Airbrake Ruby Changelog ### master +* Fixed circular references in the new truncator + ([#286](https://github.com/airbrake/airbrake-ruby/pull/286)). All v2.6.0 are + *highly recommended* to upgrade. + ### [v2.6.0][v2.6.0] (November 9, 2017) * Reworked truncation to not mutate given payload (params) and made it freeze it diff --git a/lib/airbrake-ruby/truncator.rb b/lib/airbrake-ruby/truncator.rb index 803459a1..545b5982 100644 --- a/lib/airbrake-ruby/truncator.rb +++ b/lib/airbrake-ruby/truncator.rb @@ -12,10 +12,15 @@ class Truncator # strings with +ENCODING_OPTIONS+ TEMP_ENCODING = 'utf-16'.freeze + # @return [String] what to append when something is a circular reference CIRCULAR = '[Circular]'.freeze + # @return [String] what to append when something is truncated TRUNCATED = '[Truncated]'.freeze + # @return [Array] The types that can contain references to itself + CIRCULAR_TYPES = [Array, Hash, Set].freeze + # @param [Integer] max_size maximum size of hashes, arrays and strings def initialize(max_size) @max_size = max_size @@ -28,7 +33,10 @@ def initialize(max_size) # @param [Set] seen The cache that helps to detect recursion # @return [Object] truncated object def truncate(object, seen = Set.new) - return CIRCULAR if seen.include?(object) + if seen.include?(object) + return CIRCULAR if CIRCULAR_TYPES.any? { |t| object.is_a?(t) } + return object + end truncate_object(object, seen << object) end diff --git a/spec/truncator_spec.rb b/spec/truncator_spec.rb index 0fb1a59c..b29cb3b7 100644 --- a/spec/truncator_spec.rb +++ b/spec/truncator_spec.rb @@ -211,5 +211,28 @@ def obj.to_json expect(subject).to be_frozen end end + + context "given an array with hashes and hash-like objects with identical keys" do + let(:hashie) { Class.new(Hash) } + + let(:object) do + { + errors: [ + { file: 'a' }, + hashie.new.merge(file: 'bcde') + ] + } + end + + it "truncates values" do + expect(subject).to eq( + errors: [ + { file: 'a' }, + hashie.new.merge(file: 'bcd[Truncated]') + ] + ) + expect(subject).to be_frozen + end + end end end