Skip to content

Commit

Permalink
feat: support --gen-suppressions
Browse files Browse the repository at this point in the history
When valgrind is run with `--gen-suppressions`, it will write the
error's suppression to XML as something like:

    <suppression>
      <sname>insert_a_suppression_name_here</sname>
      <skind>Memcheck:Leak</skind>
      <skaux>match-leak-kinds: definite</skaux>
      <sframe> <fun>malloc</fun> </sframe>
      <sframe> <fun>objspace_xmalloc0</fun> </sframe>
      <sframe> <fun>ruby_xmalloc0</fun> </sframe>
      <sframe> <fun>ruby_xmalloc_body</fun> </sframe>
      <sframe> <fun>ruby_xmalloc</fun> </sframe>
    </suppression>

If this data is present, then ValgrindError will stream it in the
right format for copy-pasting into a suppressions file.

See https://wiki.wxwidgets.org/Valgrind_Suppression_File_Howto for more.
  • Loading branch information
flavorjones authored and peterzhu2118 committed Oct 21, 2021
1 parent 73ef3ba commit e04b259
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 1 deletion.
1 change: 1 addition & 0 deletions lib/ruby_memcheck.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
require "ruby_memcheck/stack"
require "ruby_memcheck/test_task"
require "ruby_memcheck/valgrind_error"
require "ruby_memcheck/suppression"
require "ruby_memcheck/version"

module RubyMemcheck
Expand Down
25 changes: 25 additions & 0 deletions lib/ruby_memcheck/suppression.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# frozen_string_literal: true

module RubyMemcheck
class Suppression
attr_reader :root

def initialize(configuration, suppression_node)
@root = suppression_node
end

def to_s
return "" if root.nil?

str = StringIO.new
str << "{\n"
str << " #{root.at_xpath("sname").content}\n"
str << " #{root.at_xpath("skind").content}\n"
root.xpath("./sframe/fun | ./sframe/obj").each do |frame|
str << " #{frame.name}:#{frame.content}\n"
end
str << "}\n"
str.string
end
end
end
4 changes: 3 additions & 1 deletion lib/ruby_memcheck/valgrind_error.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

module RubyMemcheck
class ValgrindError
attr_reader :kind, :msg, :stack
attr_reader :kind, :msg, :stack, :suppression

def initialize(configuration, error)
@kind = error.at_xpath("kind").content
Expand All @@ -14,6 +14,7 @@ def initialize(configuration, error)
end
@stack = Stack.new(configuration, error.at_xpath("stack"))
@configuration = configuration
@suppression = Suppression.new(configuration, error.at_xpath("suppression"))
end

def skip?
Expand All @@ -34,6 +35,7 @@ def to_s
" #{frame}\n"
end
end
str << suppression.to_s
str.string
end

Expand Down
53 changes: 53 additions & 0 deletions test/ruby_memcheck/ruby_memcheck_suppression_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# frozen_string_literal: true

require "test_helper"
require "nokogiri"

module RubyMemcheck
class RubyMemcheckSuppressionTest < Minitest::Test
def setup
@configuration = Configuration.new(
binary_name: "ruby_memcheck_c_test",
output_io: @output_io,
)
end

def test_given_nil
assert_equal("", RubyMemcheck::Suppression.new(@configuration, nil).to_s)
end

def test_given_a_suppression_node
suppression = ::Nokogiri::XML(<<~EOF).at_xpath("//suppression")
<foo>
<suppression>
<sname>insert_a_suppression_name_here</sname>
<skind>Memcheck:Leak</skind>
<skaux>match-leak-kinds: definite</skaux>
<sframe> <fun>malloc</fun> </sframe>
<sframe> <fun>objspace_xmalloc0</fun> </sframe>
<sframe> <fun>ruby_xmalloc0</fun> </sframe>
<sframe> <obj>/usr/lib/libX11.so.6.3.0</fun> </sframe>
<sframe> <fun>ruby_xmalloc_body</fun> </sframe>
<sframe> <fun>ruby_xmalloc</fun> </sframe>
</suppression>
</foo>
EOF
expected = <<~EOF
{
insert_a_suppression_name_here
Memcheck:Leak
fun:malloc
fun:objspace_xmalloc0
fun:ruby_xmalloc0
obj:/usr/lib/libX11.so.6.3.0
fun:ruby_xmalloc_body
fun:ruby_xmalloc
}
EOF
assert_equal(
expected,
RubyMemcheck::Suppression.new(@configuration, suppression).to_s,
)
end
end
end
22 changes: 22 additions & 0 deletions test/ruby_memcheck/ruby_memcheck_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,28 @@ def test_suppressions
assert_empty(@output_io.string)
end

def test_generation_of_suppressions
valgrind_options = RubyMemcheck::Configuration::DEFAULT_VALGRIND_OPTIONS.dup
valgrind_options << "--gen-suppressions=all"
build_configuration(valgrind_options: valgrind_options)

assert_raises(RubyMemcheck::TestTask::VALGRIND_REPORT_MSG) do
run_with_memcheck(<<~RUBY)
RubyMemcheck::CTest.new.memory_leak
RUBY
end

assert_equal(1, @test_task.errors.length)

output = @output_io.string
refute_empty(output)
assert_match(/^100 bytes in 1 blocks are definitely lost in loss record/, output)
assert_match(/^ \*memory_leak \(ruby_memcheck_c_test\.c:\d+\)$/, output)
assert_match(/^ insert_a_suppression_name_here/, output)
assert_match(/^ Memcheck:Leak/, output)
assert_match(/^ fun:allocate_memory_leak/, output)
end

def test_reports_multiple_errors
assert_raises(RubyMemcheck::TestTask::VALGRIND_REPORT_MSG) do
run_with_memcheck(<<~RUBY)
Expand Down

0 comments on commit e04b259

Please sign in to comment.