ruby_memcheck 1.0.2 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d5d70104059dfe613b15fbb637b263ef6829e69e715d6cbeee472ab4715d0ae9
4
- data.tar.gz: 1827ee868afd8bb2bc4929d82d0c8ebefea2c4ef43547f9c509a38fed693489d
3
+ metadata.gz: 4cd707ffa4ebdb25945d2d2654659a38c2272a0e73678d9c9f58e655e19b3cc6
4
+ data.tar.gz: df247c2a1e77374ad3c9521b1a3f2554c443fa80e33d50cd948727821a3267d5
5
5
  SHA512:
6
- metadata.gz: d5b15eaaae74eb54957aaec9e460b59b07abdc0c922f2bb94f4e9f63504243caa2969a43c6dbfb075e51399c05fc1295ecb5996c381fd9f6ff9e10dae8d0dc4e
7
- data.tar.gz: 9fa9bc3f6374ffdfc5e0c80b6bd22e13aa26300b3b171895cc729eded1b1a446400912ebfcdc08c9ef3ca5ad3bca851a9222b309e51e8d82aee2d0560e47dcc9
6
+ metadata.gz: 7b4c337a38ad04be648365f4de828187524f11f67699aaa187182d906e4dbf922d84767003e4bab79572c0b3c41fe908c2bb23b1029b1d49360a9c399df5010f
7
+ data.tar.gz: 3c73f128a88b0eabce497b0ebb464166ccc541dbf5ec0e03b1951d8e1569abd6123a48a454b6a2e9b808c95770ea922b6e027db8c2be2a458d5f0b53f3cb74bc
@@ -6,9 +6,9 @@ jobs:
6
6
  strategy:
7
7
  matrix:
8
8
  entry:
9
- - { ruby: '2.6', allowed-failure: false }
10
9
  - { ruby: '2.7', allowed-failure: false }
11
10
  - { ruby: '3.0', allowed-failure: false }
11
+ - { ruby: '3.1', allowed-failure: false }
12
12
  - { ruby: ruby-head, allowed-failure: false }
13
13
  name: ruby ${{ matrix.entry.ruby }}
14
14
  steps:
data/.rubocop.yml CHANGED
@@ -8,3 +8,6 @@ AllCops:
8
8
  Style/GlobalVars:
9
9
  Exclude:
10
10
  - test/ruby_memcheck/ext/extconf.rb
11
+
12
+ Layout/CommentIndentation:
13
+ AllowForAlignment: true
data/README.md CHANGED
@@ -26,16 +26,19 @@ Only gems with native extensions can use this gem. If your gem is written in pla
26
26
 
27
27
  This gem runs Valgrind with the `--xml` option to generate an XML of all the errors. It will then parse the XML and use various heuristics based on the type of the error and the stack trace to filter out errors that are false positives.
28
28
 
29
+ For more details, read [this blog post](https://blog.peterzhu.ca/ruby-memcheck/).
30
+
29
31
  ### Limitations
30
32
 
31
33
  Because of the aggressive heuristics used to filter out false positives, there are various limitations of what this gem can detect.
32
34
 
33
35
  1. This gem is only expected to work on Linux.
36
+ 1. This gem runs your gem's test suite to find errors and memory leaks. It will only be able to report errors on code paths that are covered by your tests. So make sure your test suite has good coverage!
34
37
  1. It will not find memory leaks in Ruby. It filters out everything in Ruby.
35
38
  1. It will not find memory leaks of allocations that occurred in Ruby (even if the memory leak is caused by your native extension).
36
39
 
37
40
  An example of this is if a string is allocated in Ruby, passed into your native extension, you change the pointer of the string without freeing the contents, so the contents of the string becomes leaked.
38
- 1. To filter out false-positives, it will only find definite leaks (i.e. memory regions with no pointers to it). It will not find possible leaks (i.e. memory regions with pointers to it).
41
+ 1. To filter out false positives, it will only find definite leaks (i.e. memory regions with no pointers to it). It will not find possible leaks (i.e. memory regions with pointers to it).
39
42
  1. It will not find leaks that occur in the `Init` function of your native extension.
40
43
  1. It will not find uses of undefined values (e.g. conditional jumps depending on undefined values). This is just a technical limitation that has not been solved yet (contributions welcome!).
41
44
 
@@ -67,6 +70,7 @@ The easiest way to use this gem is to use it on your test suite (minitest or RSp
67
70
  ```ruby
68
71
  RubyMemcheck.config(binary_name: "your_binary_name")
69
72
  ```
73
+
70
74
  1. Setup the test task for your test framework.
71
75
  - **minitest**
72
76
 
@@ -105,18 +109,30 @@ The easiest way to use this gem is to use it on your test suite (minitest or RSp
105
109
  For example, if your Rakefile looked like this before:
106
110
 
107
111
  ```ruby
108
- RubyMemcheck::RSpec::RakeTask.new(spec: :compile)
112
+ RSpec::Core::RakeTask.new(spec: :compile)
109
113
  ```
110
114
 
111
115
  You can change it to look like this:
112
116
 
113
117
  ```ruby
114
- RubyMemcheck::RSpec::RakeTask.new(spec: :compile)
118
+ RSpec::Core::RakeTask.new(spec: :compile)
115
119
  namespace :spec do
116
120
  RubyMemcheck::RSpec::RakeTask.new(valgrind: :compile)
117
121
  end
118
122
  ```
119
123
 
124
+ 1. Add the following line to your `test_helper.rb` or `spec_helper.rb`:
125
+
126
+ ```ruby
127
+ at_exit { GC.start }
128
+ ```
129
+
130
+ This will run a major garbage collection cycle before the Ruby process shuts down. This will ensure that any remaining Ruby objects are collected which will prevent Valgrind from reporting false positives.
131
+
132
+ It is safest to add the line above at the very first line of `test_helper.rb` or `spec_helper.rb`.
133
+
134
+ - **For minitest:** It is important that the line above is added BEFORE the `require "minitest/autorun"` line.
135
+
120
136
  1. You're ready to run your test suite with Valgrind using `rake test:valgrind` or `rake spec:valgrind`! Note that this will take a while to run because Valgrind will make Ruby significantly slower.
121
137
  1. (Optional) If you find false positives in the output, you can create Valgrind suppression files. See the [`Suppression files`](#suppression-files) section for more details.
122
138
 
@@ -140,7 +156,7 @@ When you run `RubyMemcheck.config`, you are creating a default `RubyMemcheck::Co
140
156
 
141
157
  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).
142
158
 
143
- 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.).
159
+ The most basic suppression file is `ruby.supp`. If you want some suppressions for only specific versions of Ruby, you can add the Ruby version to the filename. For example, `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 `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.).
144
160
 
145
161
  ## Success stories
146
162
 
@@ -31,7 +31,7 @@ module RubyMemcheck
31
31
  /\Arb_yield/,
32
32
  ].freeze
33
33
 
34
- attr_reader :binary_name, :ruby, :valgrind, :valgrind_options, :valgrind_suppressions_dir,
34
+ attr_reader :binary_name, :ruby, :valgrind, :valgrind_options, :valgrind_suppression_files,
35
35
  :valgrind_generate_suppressions, :skipped_ruby_functions, :valgrind_xml_dir, :output_io
36
36
  alias_method :valgrind_generate_suppressions?, :valgrind_generate_suppressions
37
37
 
@@ -50,7 +50,9 @@ module RubyMemcheck
50
50
  @ruby = ruby
51
51
  @valgrind = valgrind
52
52
  @valgrind_options = valgrind_options
53
- @valgrind_suppressions_dir = File.expand_path(valgrind_suppressions_dir)
53
+ @valgrind_suppression_files =
54
+ get_valgrind_suppression_files(File.join(__dir__, "../../suppressions")) +
55
+ get_valgrind_suppression_files(valgrind_suppressions_dir)
54
56
  @valgrind_generate_suppressions = valgrind_generate_suppressions
55
57
  @skipped_ruby_functions = skipped_ruby_functions
56
58
  @output_io = output_io
@@ -80,7 +82,7 @@ module RubyMemcheck
80
82
  "ulimit -s unlimited && ",
81
83
  valgrind,
82
84
  valgrind_options,
83
- get_valgrind_suppression_files(valgrind_suppressions_dir).map { |f| "--suppressions=#{f}" },
85
+ valgrind_suppression_files.map { |f| "--suppressions=#{f}" },
84
86
  valgrind_generate_suppressions ? "--gen-suppressions=all" : "",
85
87
  ruby,
86
88
  args,
@@ -90,13 +92,22 @@ module RubyMemcheck
90
92
  private
91
93
 
92
94
  def get_valgrind_suppression_files(dir)
95
+ dir = File.expand_path(dir)
96
+
93
97
  full_ruby_version = "#{RUBY_ENGINE}-#{RUBY_VERSION}.#{RUBY_PATCHLEVEL}"
94
98
  versions = [full_ruby_version]
95
99
  (0..3).reverse_each { |i| versions << full_ruby_version.split(".")[0, i].join(".") }
96
100
  versions << RUBY_ENGINE
97
101
 
98
102
  versions.map do |version|
99
- Dir[File.join(dir, "#{binary_name}_#{version}.supp")]
103
+ old_format_files = Dir[File.join(dir, "#{binary_name}_#{version}.supp")]
104
+
105
+ unless old_format_files.empty?
106
+ warn("ruby_memcheck: please migrate your suppression filenames from " \
107
+ "`gem_name_ruby-3.1.0.supp` to `ruby-3.1.0.supp` (drop the gem name from the filename)")
108
+ end
109
+
110
+ old_format_files + Dir[File.join(dir, "#{version}.supp")]
100
111
  end.flatten
101
112
  end
102
113
  end
@@ -33,9 +33,11 @@ module RubyMemcheck
33
33
  xml_files.each do |file|
34
34
  Nokogiri::XML::Reader(File.open(file)).each do |node|
35
35
  next unless node.name == "error" && node.node_type == Nokogiri::XML::Reader::TYPE_ELEMENT
36
+
36
37
  error_xml = Nokogiri::XML::Document.parse(node.outer_xml).root
37
38
  error = ValgrindError.new(configuration, error_xml)
38
39
  next if error.skip?
40
+
39
41
  @errors << error
40
42
  end
41
43
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RubyMemcheck
4
- VERSION = "1.0.2"
4
+ VERSION = "1.1.0"
5
5
  end
@@ -0,0 +1,21 @@
1
+ {
2
+ On platforms where memcpy is safe for overlapped memory, the compiler will sometimes replace memmove with memcpy. Valgrind may report a false positive.
3
+ Memcheck:Overlap
4
+ fun:__memcpy_chk
5
+ fun:memmove
6
+ ...
7
+ }
8
+ {
9
+ Requiring a file will add it to the loaded features, which may be reported as a leak.
10
+ Memcheck:Leak
11
+ ...
12
+ fun:require_internal
13
+ ...
14
+ }
15
+ {
16
+ Remove this after Ruby 2.7.7, 3.0.5, 3.1.3 are relased. See: https://github.com/Shopify/ruby_memcheck/issues/6
17
+ Memcheck:Leak
18
+ ...
19
+ fun:stack_chunk_alloc
20
+ ...
21
+ }
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: 1.0.2
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter Zhu
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-11-04 00:00:00.000000000 Z
11
+ date: 2022-10-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: nokogiri
@@ -148,6 +148,7 @@ files:
148
148
  - lib/ruby_memcheck/valgrind_error.rb
149
149
  - lib/ruby_memcheck/version.rb
150
150
  - ruby_memcheck.gemspec
151
+ - suppressions/ruby.supp
151
152
  homepage: https://github.com/peterzhu2118/ruby_memcheck
152
153
  licenses:
153
154
  - MIT
@@ -168,7 +169,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
168
169
  - !ruby/object:Gem::Version
169
170
  version: '0'
170
171
  requirements: []
171
- rubygems_version: 3.2.22
172
+ rubygems_version: 3.3.7
172
173
  signing_key:
173
174
  specification_version: 4
174
175
  summary: Use Valgrind memcheck without going crazy