ruby_memcheck 1.0.0 → 1.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/test.yml +1 -1
- data/.rubocop.yml +3 -0
- data/README.md +17 -1
- data/lib/ruby_memcheck/configuration.rb +9 -0
- data/lib/ruby_memcheck/test_task_reporter.rb +17 -8
- data/lib/ruby_memcheck/version.rb +1 -1
- metadata +7 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c5872b7150e47c3eb369c82bff0f8adbd58e48ecf69cdd2c41f7aee2e11d2591
|
4
|
+
data.tar.gz: eb72ad63ada1c5af40938059f25f6392d30b44262d2482fc836aac795673683c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0b6582216142426fb20ebbad4493b0002f83aa3696ec314cf8173890eba2cc1398fcf89d7227a629e7be3f642f60551b315cc9957df47f17e0d603fa406b1a43
|
7
|
+
data.tar.gz: 74739f350aa890ef955fdc8d63c40810f8997ef4aaf8b5c5763086787da22efadf243e1a5e9d2ea20ac672714c1aed20bc72df9ab9a8abd22c7b3c9244114c59
|
data/.github/workflows/test.yml
CHANGED
@@ -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
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
|
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
|
|
@@ -117,6 +121,18 @@ The easiest way to use this gem is to use it on your test suite (minitest or RSp
|
|
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
|
|
@@ -29,6 +29,8 @@ module RubyMemcheck
|
|
29
29
|
/\Arb_respond_to\z/,
|
30
30
|
/\Arb_thread_create\z/, # Threads are relased to a cache, so they may be reported as a leak
|
31
31
|
/\Arb_yield/,
|
32
|
+
/\Astack_chunk_alloc/, # Remove this after Ruby 2.7.7, 3.0.5, 3.1.3 are relased
|
33
|
+
# See: https://github.com/Shopify/ruby_memcheck/issues/6
|
32
34
|
].freeze
|
33
35
|
|
34
36
|
attr_reader :binary_name, :ruby, :valgrind, :valgrind_options, :valgrind_suppressions_dir,
|
@@ -71,6 +73,13 @@ module RubyMemcheck
|
|
71
73
|
|
72
74
|
def command(*args)
|
73
75
|
[
|
76
|
+
# On some Rubies, not setting the stack size to be ulimited causes
|
77
|
+
# Valgrind to report the following error:
|
78
|
+
# Invalid write of size 1
|
79
|
+
# reserve_stack (thread_pthread.c:845)
|
80
|
+
# ruby_init_stack (thread_pthread.c:871)
|
81
|
+
# main (main.c:48)
|
82
|
+
"ulimit -s unlimited && ",
|
74
83
|
valgrind,
|
75
84
|
valgrind_options,
|
76
85
|
get_valgrind_suppression_files(valgrind_suppressions_dir).map { |f| "--suppressions=#{f}" },
|
@@ -10,8 +10,9 @@ module RubyMemcheck
|
|
10
10
|
|
11
11
|
def report_valgrind_errors
|
12
12
|
if configuration.valgrind_xml_dir
|
13
|
-
|
14
|
-
|
13
|
+
xml_files = valgrind_xml_files
|
14
|
+
parse_valgrind_output(xml_files)
|
15
|
+
remove_valgrind_xml_files(xml_files)
|
15
16
|
|
16
17
|
unless errors.empty?
|
17
18
|
output_valgrind_errors
|
@@ -20,31 +21,39 @@ module RubyMemcheck
|
|
20
21
|
end
|
21
22
|
end
|
22
23
|
|
23
|
-
def
|
24
|
+
def valgrind_xml_files
|
25
|
+
Dir[File.join(configuration.valgrind_xml_dir, "*")]
|
26
|
+
end
|
27
|
+
|
28
|
+
def parse_valgrind_output(xml_files)
|
24
29
|
require "nokogiri"
|
25
30
|
|
26
31
|
@errors = []
|
27
32
|
|
28
|
-
|
33
|
+
xml_files.each do |file|
|
29
34
|
Nokogiri::XML::Reader(File.open(file)).each do |node|
|
30
35
|
next unless node.name == "error" && node.node_type == Nokogiri::XML::Reader::TYPE_ELEMENT
|
36
|
+
|
31
37
|
error_xml = Nokogiri::XML::Document.parse(node.outer_xml).root
|
32
38
|
error = ValgrindError.new(configuration, error_xml)
|
33
39
|
next if error.skip?
|
40
|
+
|
34
41
|
@errors << error
|
35
42
|
end
|
36
43
|
end
|
37
44
|
end
|
38
45
|
|
46
|
+
def remove_valgrind_xml_files(xml_files)
|
47
|
+
xml_files.each do |file|
|
48
|
+
File.delete(file)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
39
52
|
def output_valgrind_errors
|
40
53
|
@errors.each do |error|
|
41
54
|
configuration.output_io.puts error
|
42
55
|
configuration.output_io.puts
|
43
56
|
end
|
44
57
|
end
|
45
|
-
|
46
|
-
def remove_valgrind_xml_files
|
47
|
-
FileUtils.rm_rf(configuration.valgrind_xml_dir)
|
48
|
-
end
|
49
58
|
end
|
50
59
|
end
|
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.
|
4
|
+
version: 1.0.3
|
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:
|
11
|
+
date: 2022-07-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nokogiri
|
@@ -122,7 +122,7 @@ dependencies:
|
|
122
122
|
- - "~>"
|
123
123
|
- !ruby/object:Gem::Version
|
124
124
|
version: '2.3'
|
125
|
-
description:
|
125
|
+
description:
|
126
126
|
email:
|
127
127
|
- peter@peterzhu.ca
|
128
128
|
executables: []
|
@@ -153,7 +153,7 @@ licenses:
|
|
153
153
|
- MIT
|
154
154
|
metadata:
|
155
155
|
homepage_uri: https://github.com/peterzhu2118/ruby_memcheck
|
156
|
-
post_install_message:
|
156
|
+
post_install_message:
|
157
157
|
rdoc_options: []
|
158
158
|
require_paths:
|
159
159
|
- lib
|
@@ -168,8 +168,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
168
168
|
- !ruby/object:Gem::Version
|
169
169
|
version: '0'
|
170
170
|
requirements: []
|
171
|
-
rubygems_version: 3.
|
172
|
-
signing_key:
|
171
|
+
rubygems_version: 3.3.7
|
172
|
+
signing_key:
|
173
173
|
specification_version: 4
|
174
174
|
summary: Use Valgrind memcheck without going crazy
|
175
175
|
test_files: []
|