ruby_memcheck 0.1.2 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: aa5f0f59617f5220d6870d3d44cae58605b9488c31d03c1c1d027895fafaf83d
4
- data.tar.gz: 999a0744c5a3c32ddf1e51d3f31164d13c144afe138fc4793b1930fcf3ec7a9e
3
+ metadata.gz: 7d7e2556e802cceebbd1607895ed319b54037e2a945586f8fe65e9f6bda0928c
4
+ data.tar.gz: 3cba76f62de7ad396458d651a272d660456e362a85c1c6a67ac6ae688b3e4c30
5
5
  SHA512:
6
- metadata.gz: f95821f8680a6685deb30e3a3acb8763878a52c76149f922f8a237f36406a0ded80e34dcbf66da29f78112e4fc4a4e3e534a7f6aa019a1df104c9e0d3cc18dbf
7
- data.tar.gz: 1d8cd567af6606c87b4222832917417a478e8ab265db59fffbc8ad4cd418bfd6bf06f63170ce537865972232134b503c23a661abdbdbc6b3f64d0ee2c7ca3a44
6
+ metadata.gz: 6e849c1bcfc9947293939452298c344acd71136dd7b617bb3edfc07c7b8122a9bc366e1e57a83d86293ed284569121185d465fd9e47959a9e9e0b6579b212022
7
+ data.tar.gz: 3131ae9a995bcd2e9f9fcab7f7bfb8b99c3449eadb12d9bfad0366681971d3c3fa7234e194fbf7e5c9a41583d18814cc59aad7802836ba1d075e0d6893be0e1d
data/.rubocop.yml CHANGED
@@ -3,3 +3,7 @@ inherit_gem:
3
3
 
4
4
  AllCops:
5
5
  SuggestExtensions: false
6
+
7
+ Style/GlobalVars:
8
+ Exclude:
9
+ - test/ruby_memcheck/ext/extconf.rb
data/README.md CHANGED
@@ -83,14 +83,15 @@ The easiest way to use this gem is to use it on your test suite using rake.
83
83
  RubyMemcheck::TestTask.new(valgrind: :compile, &test_config)
84
84
  end
85
85
  ```
86
- 1. In your `test_helper.rb`/`spec_helper.rb` (or whatever file sets up your test suite), add this line:
86
+ 1. At the top of your `test_helper.rb`/`spec_helper.rb` (or whatever file sets up your test suite), add this line:
87
87
 
88
88
  ```ruby
89
- END { GC.start }
89
+ at_exit { GC.start }
90
90
  ```
91
91
 
92
- This will ensure that the Garbage Collector is ran before Ruby shuts down. This will reduce the number of false-positives.
92
+ Place this line as close to the top of the file as possible, before any requires in the file (especially before the call to `require "minitest/autorun"`). This will ensure that the Garbage Collector is ran before Ruby shuts down. This will reduce the number of false-positives.
93
93
  1. You're ready to run your test suite with Valgrind using `rake test:valgrind`! Note that this will take a while to run because Valgrind will make Ruby significantly slower.
94
+ 1. (Optional) If you find false-positives in the output, you can create suppression files in a `suppressions` directory in the root directory of your gem. In this directory, you can create [Valgrind suppression files](https://wiki.wxwidgets.org/Valgrind_Suppression_File_Howto). The most basic suppression file is `your_binary_name_ruby.supp`. If you want some suppressions for only specific versions of Ruby, you can add the Ruby version to the filename. For example, `your_binary_name_ruby-3.supp` will suppress for any Rubies with a major version of 3 (e.g. 3.0.0, 3.1.1, etc.), while suppression file `your_binary_name_ruby-3.1.supp` will only be used for Ruby with a major and minor version of 3.1 (e.g. 3.1.0, 3.1.1, etc.).
94
95
 
95
96
  ## License
96
97
 
@@ -10,11 +10,13 @@ module RubyMemcheck
10
10
  "--leak-check=full",
11
11
  "--show-leak-kinds=definite",
12
12
  ].freeze
13
+ DEFAULT_VALGRIND_SUPPRESSIONS_DIR = "suppressions"
13
14
  DEFAULT_SKIPPED_RUBY_FUNCTIONS = [
14
15
  /\Arb_check_funcall/,
15
16
  /\Arb_enc_raise\z/,
16
17
  /\Arb_exc_raise\z/,
17
18
  /\Arb_funcall/,
19
+ /\Arb_intern/,
18
20
  /\Arb_ivar_set\z/,
19
21
  /\Arb_raise\z/,
20
22
  /\Arb_rescue/,
@@ -30,6 +32,7 @@ module RubyMemcheck
30
32
  ruby: FileUtils::RUBY,
31
33
  valgrind: DEFAULT_VALGRIND,
32
34
  valgrind_options: DEFAULT_VALGRIND_OPTIONS,
35
+ valgrind_suppressions_dir: DEFAULT_VALGRIND_SUPPRESSIONS_DIR,
33
36
  skipped_ruby_functions: DEFAULT_SKIPPED_RUBY_FUNCTIONS,
34
37
  valgrind_xml_file: Tempfile.new,
35
38
  output_io: $stderr
@@ -37,7 +40,9 @@ module RubyMemcheck
37
40
  @binary_name = binary_name
38
41
  @ruby = ruby
39
42
  @valgrind = valgrind
40
- @valgrind_options = valgrind_options
43
+ @valgrind_options =
44
+ valgrind_options +
45
+ get_valgrind_suppression_files(valgrind_suppressions_dir).map { |f| "--suppressions=#{f}" }
41
46
  @skipped_ruby_functions = skipped_ruby_functions
42
47
  @output_io = output_io
43
48
 
@@ -89,5 +94,18 @@ module RubyMemcheck
89
94
  false
90
95
  end
91
96
  end
97
+
98
+ private
99
+
100
+ def get_valgrind_suppression_files(dir)
101
+ full_ruby_version = "#{RUBY_ENGINE}-#{RUBY_VERSION}.#{RUBY_PATCHLEVEL}"
102
+ versions = [full_ruby_version]
103
+ (0..3).reverse_each { |i| versions << full_ruby_version.split(".")[0, i].join(".") }
104
+ versions << RUBY_ENGINE
105
+
106
+ versions.map do |version|
107
+ Dir[File.join(dir, "#{binary_name}_#{version}.supp")]
108
+ end.flatten
109
+ end
92
110
  end
93
111
  end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyMemcheck
4
+ class Suppression
5
+ attr_reader :root
6
+
7
+ def initialize(configuration, suppression_node)
8
+ @root = suppression_node
9
+ end
10
+
11
+ def to_s
12
+ return "" if root.nil?
13
+
14
+ str = StringIO.new
15
+ str << "{\n"
16
+ str << " #{root.at_xpath("sname").content}\n"
17
+ str << " #{root.at_xpath("skind").content}\n"
18
+ root.xpath("./sframe/fun | ./sframe/obj").each do |frame|
19
+ str << " #{frame.name}:#{frame.content}\n"
20
+ end
21
+ str << "}\n"
22
+ str.string
23
+ end
24
+ end
25
+ end
@@ -20,7 +20,7 @@ module RubyMemcheck
20
20
  def ruby(*args, **options, &block)
21
21
  command = configuration.command(args)
22
22
  sh(command, **options) do |ok, res|
23
- if ok && configuration.valgrind_xml_file
23
+ if configuration.valgrind_xml_file
24
24
  parse_valgrind_output
25
25
  unless errors.empty?
26
26
  output_valgrind_errors
@@ -35,10 +35,13 @@ module RubyMemcheck
35
35
  private
36
36
 
37
37
  def parse_valgrind_output
38
+ require "nokogiri"
39
+
38
40
  @errors = []
39
41
 
40
- xml = Nokogiri::XML(configuration.valgrind_xml_file.read)
41
- xml.xpath("/valgrindoutput/error").each do |error_xml|
42
+ Nokogiri::XML::Reader(File.open(configuration.valgrind_xml_file.to_path)).each do |node|
43
+ next unless node.name == "error" && node.node_type == Nokogiri::XML::Reader::TYPE_ELEMENT
44
+ error_xml = Nokogiri::XML::Document.parse(node.outer_xml).root
42
45
  error = ValgrindError.new(configuration, error_xml)
43
46
  next if error.skip?
44
47
  @errors << error
@@ -2,7 +2,7 @@
2
2
 
3
3
  module RubyMemcheck
4
4
  class ValgrindError
5
- attr_reader :kind, :msg, :stack
5
+ attr_reader :kind, :msg, :stack, :suppression
6
6
 
7
7
  def initialize(configuration, error)
8
8
  @kind = error.at_xpath("kind").content
@@ -14,6 +14,7 @@ module RubyMemcheck
14
14
  end
15
15
  @stack = Stack.new(configuration, error.at_xpath("stack"))
16
16
  @configuration = configuration
17
+ @suppression = Suppression.new(configuration, error.at_xpath("suppression"))
17
18
  end
18
19
 
19
20
  def skip?
@@ -34,6 +35,7 @@ module RubyMemcheck
34
35
  " #{frame}\n"
35
36
  end
36
37
  end
38
+ str << suppression.to_s
37
39
  str.string
38
40
  end
39
41
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RubyMemcheck
4
- VERSION = "0.1.2"
4
+ VERSION = "0.2.1"
5
5
  end
data/lib/ruby_memcheck.rb CHANGED
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "tempfile"
4
- require "nokogiri"
5
4
  require "rake/testtask"
6
5
 
7
6
  require "ruby_memcheck/configuration"
@@ -9,6 +8,7 @@ require "ruby_memcheck/frame"
9
8
  require "ruby_memcheck/stack"
10
9
  require "ruby_memcheck/test_task"
11
10
  require "ruby_memcheck/valgrind_error"
11
+ require "ruby_memcheck/suppression"
12
12
  require "ruby_memcheck/version"
13
13
 
14
14
  module RubyMemcheck
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby_memcheck
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter Zhu
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-10-18 00:00:00.000000000 Z
11
+ date: 2021-10-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: nokogiri
@@ -94,7 +94,7 @@ dependencies:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
96
  version: '2.3'
97
- description:
97
+ description:
98
98
  email:
99
99
  - peter@peterzhu.ca
100
100
  executables: []
@@ -113,6 +113,7 @@ files:
113
113
  - lib/ruby_memcheck/configuration.rb
114
114
  - lib/ruby_memcheck/frame.rb
115
115
  - lib/ruby_memcheck/stack.rb
116
+ - lib/ruby_memcheck/suppression.rb
116
117
  - lib/ruby_memcheck/test_task.rb
117
118
  - lib/ruby_memcheck/valgrind_error.rb
118
119
  - lib/ruby_memcheck/version.rb
@@ -122,7 +123,7 @@ licenses:
122
123
  - MIT
123
124
  metadata:
124
125
  homepage_uri: https://github.com/peterzhu2118/ruby_memcheck
125
- post_install_message:
126
+ post_install_message:
126
127
  rdoc_options: []
127
128
  require_paths:
128
129
  - lib
@@ -137,8 +138,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
137
138
  - !ruby/object:Gem::Version
138
139
  version: '0'
139
140
  requirements: []
140
- rubygems_version: 3.2.15
141
- signing_key:
141
+ rubygems_version: 3.3.0.dev
142
+ signing_key:
142
143
  specification_version: 4
143
144
  summary: Use Valgrind memcheck without going crazy
144
145
  test_files: []