ruby_memcheck 1.3.2 → 2.0.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 +4 -4
- data/.github/workflows/cla.yml +23 -0
- data/.github/workflows/test.yml +3 -4
- data/LICENSE.txt +1 -1
- data/README.md +5 -12
- data/Rakefile +8 -1
- data/lib/ruby_memcheck/configuration.rb +20 -25
- data/lib/ruby_memcheck/frame.rb +12 -4
- data/lib/ruby_memcheck/rspec/rake_task.rb +3 -6
- data/lib/ruby_memcheck/stack.rb +4 -6
- data/lib/ruby_memcheck/test_helper.rb +7 -1
- data/lib/ruby_memcheck/test_task.rb +7 -4
- data/lib/ruby_memcheck/test_task_reporter.rb +43 -17
- data/lib/ruby_memcheck/valgrind_error.rb +2 -2
- data/lib/ruby_memcheck/version.rb +1 -1
- data/lib/ruby_memcheck.rb +1 -5
- data/ruby_memcheck.gemspec +1 -1
- data/suppressions/ruby.supp +17 -7
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 597a64c7109c460a09cfaa57715d6f26a50104e8137c5184d9bf5f658954d07f
|
4
|
+
data.tar.gz: e9524cbead271b0a5eb8abf85213c59d97d6629d1b6e2e2e3c03d0e94beb7970
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2b38c33923e1370245b6184b5b4f16b993819bf02dc3fc76a4fc152c2ae10f50d4597b507983b5fafbbcc09933fd63e06c2c057f55f30c613ece717c68e74e45
|
7
|
+
data.tar.gz: 30a0d75f4268ee39cc34cf865bfb7a0414f4bb89ce10995fd8e55517cc8090761c4d21356e908b2d93adf97a5e8200019e577cb4ba61d2361e7caca5097b6049
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# .github/workflows/cla.yml
|
2
|
+
name: Contributor License Agreement (CLA)
|
3
|
+
|
4
|
+
on:
|
5
|
+
pull_request_target:
|
6
|
+
types: [opened, synchronize]
|
7
|
+
issue_comment:
|
8
|
+
types: [created]
|
9
|
+
|
10
|
+
jobs:
|
11
|
+
cla:
|
12
|
+
runs-on: ubuntu-latest
|
13
|
+
if: |
|
14
|
+
(github.event.issue.pull_request
|
15
|
+
&& !github.event.issue.pull_request.merged_at
|
16
|
+
&& contains(github.event.comment.body, 'signed')
|
17
|
+
)
|
18
|
+
|| (github.event.pull_request && !github.event.pull_request.merged)
|
19
|
+
steps:
|
20
|
+
- uses: Shopify/shopify-cla-action@v1
|
21
|
+
with:
|
22
|
+
github-token: ${{ secrets.GITHUB_TOKEN }}
|
23
|
+
cla-token: ${{ secrets.CLA_TOKEN }}
|
data/.github/workflows/test.yml
CHANGED
@@ -7,7 +7,6 @@ jobs:
|
|
7
7
|
fail-fast: false
|
8
8
|
matrix:
|
9
9
|
entry:
|
10
|
-
- { ruby: '2.7', allowed-failure: false }
|
11
10
|
- { ruby: '3.0', allowed-failure: false }
|
12
11
|
- { ruby: '3.1', allowed-failure: false }
|
13
12
|
- { ruby: '3.2', allowed-failure: false }
|
@@ -24,9 +23,9 @@ jobs:
|
|
24
23
|
- run: sudo apt-get install -y libc6-dbg
|
25
24
|
- name: Install Valgrind from source
|
26
25
|
run: |
|
27
|
-
wget https://sourceware.org/pub/valgrind/valgrind-3.
|
28
|
-
tar xvf valgrind-3.
|
29
|
-
cd valgrind-3.
|
26
|
+
wget https://sourceware.org/pub/valgrind/valgrind-3.21.0.tar.bz2
|
27
|
+
tar xvf valgrind-3.21.0.tar.bz2
|
28
|
+
cd valgrind-3.21.0
|
30
29
|
./configure
|
31
30
|
make
|
32
31
|
sudo make install
|
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -61,9 +61,9 @@ gem install ruby_memcheck
|
|
61
61
|
> You can install Valgrind from source using the following commands:
|
62
62
|
> ```
|
63
63
|
> sudo apt-get install -y libc6-dbg
|
64
|
-
> wget https://sourceware.org/pub/valgrind/valgrind-3.
|
65
|
-
> tar xvf valgrind-3.
|
66
|
-
> cd valgrind-3.
|
64
|
+
> wget https://sourceware.org/pub/valgrind/valgrind-3.21.0.tar.bz2
|
65
|
+
> tar xvf valgrind-3.21.0.tar.bz2
|
66
|
+
> cd valgrind-3.21.0
|
67
67
|
> ./configure
|
68
68
|
> make
|
69
69
|
> sudo make install
|
@@ -84,12 +84,6 @@ The easiest way to use this gem is to use it on your test suite (minitest or RSp
|
|
84
84
|
require "ruby_memcheck/rspec/rake_task"
|
85
85
|
```
|
86
86
|
|
87
|
-
1. Configure the gem by calling `RubyMemcheck.config`. You must pass it your binary name. This is the same value you passed into `create_makefile` in your `extconf.rb` file. Make sure this value is correct or it will filter out almost everything as a false-positive!
|
88
|
-
|
89
|
-
```ruby
|
90
|
-
RubyMemcheck.config(binary_name: "your_binary_name")
|
91
|
-
```
|
92
|
-
|
93
87
|
1. Setup the test task for your test framework.
|
94
88
|
- **minitest**
|
95
89
|
|
@@ -145,18 +139,17 @@ The easiest way to use this gem is to use it on your test suite (minitest or RSp
|
|
145
139
|
|
146
140
|
## Configuration
|
147
141
|
|
148
|
-
|
142
|
+
If you want to override any of the default configurations you can call `RubyMemcheck.config` after `require "ruby_memcheck"`. This will create a default `RubyMemcheck::Configuration`. By default, the Rake tasks for minitest and RSpec will use this configuration. You can also manually pass in a `Configuration` object as the first argument to the constructor of `RubyMemcheck::TestTask` or `RubyMemcheck::RSpec::RakeTask` to use a different `Configuration` object rather than the default one.
|
149
143
|
|
150
144
|
`RubyMemcheck::Configuration` accepts a variety of keyword arguments. Here are all the arguments:
|
151
145
|
|
152
|
-
- `binary_name`: Required. The binary name of your native extension gem. This is the same value you passed into `create_makefile` in your `extconf.rb` file.
|
153
146
|
- `ruby`: Optional. The command to run to invoke Ruby. Defaults to the Ruby that is currently being used.
|
154
147
|
- `valgrind`: Optional. The command to run to invoke Valgrind. Defaults to the string `"valgrind"`.
|
155
148
|
- `valgrind_options`: Optional. Array of options to pass into Valgrind. This is only present as an escape hatch, so avoid using it. This may be deprecated or removed in future versions.
|
156
149
|
- `valgrind_suppressions_dir`: Optional. The string path of the directory that stores suppression files for Valgrind. See the [`Suppression files`](#suppression-files) section for more details. Defaults to `suppressions`.
|
157
150
|
- `valgrind_generate_suppressions`: Optional. Whether suppressions should also be outputted along with the errors. the [`Suppression files`](#suppression-files) section for more details. Defaults to `false`.
|
158
151
|
- `skipped_ruby_functions`: Optional. Ruby functions that are ignored because they are considered a call back into Ruby. This is only present as an escape hatch, so avoid using it. If you find another Ruby function that is a false positive because it calls back into Ruby, please send a patch into this repo. Otherwise, use a Valgrind suppression file.
|
159
|
-
- `
|
152
|
+
- `temp_dir`: Optional. The directory to store temporary files. It defaults to a temporary directory. This is present for development debugging, so you shouldn't have to use it.
|
160
153
|
- `output_io`: Optional. The `IO` object to output Valgrind errors to. Defaults to standard error.
|
161
154
|
- `filter_all_errors`: Optional. Whether to filter all kinds of Valgrind errors (not just memory leaks). This feature should only be used if you're encountering a large number of illegal memory accesses coming from Ruby. If you need to use this feature, you may have found a bug inside of Ruby. Consider reporting it to the [Ruby bug tracker](https://bugs.ruby-lang.org/projects/ruby-master/issues/new). Defaults to `false`.
|
162
155
|
|
data/Rakefile
CHANGED
@@ -11,9 +11,16 @@ Rake::TestTask.new(test: "test:compile") do |t|
|
|
11
11
|
end
|
12
12
|
|
13
13
|
namespace :test do
|
14
|
-
Rake::ExtensionTask.new("
|
14
|
+
Rake::ExtensionTask.new("ruby_memcheck_c_test_one") do |ext|
|
15
15
|
ext.ext_dir = "test/ruby_memcheck/ext"
|
16
16
|
ext.lib_dir = "test/ruby_memcheck/ext"
|
17
|
+
ext.config_script = "extconf_one.rb"
|
18
|
+
end
|
19
|
+
|
20
|
+
Rake::ExtensionTask.new("ruby_memcheck_c_test_two") do |ext|
|
21
|
+
ext.ext_dir = "test/ruby_memcheck/ext"
|
22
|
+
ext.lib_dir = "test/ruby_memcheck/ext"
|
23
|
+
ext.config_script = "extconf_two.rb"
|
17
24
|
end
|
18
25
|
end
|
19
26
|
|
@@ -31,14 +31,14 @@ module RubyMemcheck
|
|
31
31
|
/\Arb_yield/,
|
32
32
|
].freeze
|
33
33
|
|
34
|
-
attr_reader :binary_name
|
35
34
|
attr_reader :ruby
|
36
35
|
attr_reader :valgrind
|
37
36
|
attr_reader :valgrind_options
|
38
37
|
attr_reader :valgrind_suppression_files
|
39
38
|
attr_reader :valgrind_generate_suppressions
|
40
39
|
attr_reader :skipped_ruby_functions
|
41
|
-
attr_reader :
|
40
|
+
attr_reader :temp_dir
|
41
|
+
attr_reader :loaded_features_file
|
42
42
|
attr_reader :output_io
|
43
43
|
attr_reader :filter_all_errors
|
44
44
|
|
@@ -46,18 +46,19 @@ module RubyMemcheck
|
|
46
46
|
alias_method :filter_all_errors?, :filter_all_errors
|
47
47
|
|
48
48
|
def initialize(
|
49
|
-
binary_name
|
49
|
+
binary_name: nil,
|
50
50
|
ruby: FileUtils::RUBY,
|
51
51
|
valgrind: DEFAULT_VALGRIND,
|
52
52
|
valgrind_options: DEFAULT_VALGRIND_OPTIONS,
|
53
53
|
valgrind_suppressions_dir: DEFAULT_VALGRIND_SUPPRESSIONS_DIR,
|
54
54
|
valgrind_generate_suppressions: false,
|
55
55
|
skipped_ruby_functions: DEFAULT_SKIPPED_RUBY_FUNCTIONS,
|
56
|
-
|
56
|
+
temp_dir: Dir.mktmpdir,
|
57
57
|
output_io: $stderr,
|
58
58
|
filter_all_errors: false
|
59
59
|
)
|
60
|
-
|
60
|
+
warn("ruby_memcheck: binary_name is no longer required for configuration") if binary_name
|
61
|
+
|
61
62
|
@ruby = ruby
|
62
63
|
@valgrind = valgrind
|
63
64
|
@valgrind_options = valgrind_options
|
@@ -69,18 +70,18 @@ module RubyMemcheck
|
|
69
70
|
@output_io = output_io
|
70
71
|
@filter_all_errors = filter_all_errors
|
71
72
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
73
|
+
temp_dir = File.expand_path(temp_dir)
|
74
|
+
FileUtils.mkdir_p(temp_dir)
|
75
|
+
@temp_dir = temp_dir
|
76
|
+
@valgrind_options += [
|
77
|
+
"--xml=yes",
|
78
|
+
# %p will be replaced with the PID
|
79
|
+
# This prevents forking and shelling out from generating a corrupted XML
|
80
|
+
# See --log-file from https://valgrind.org/docs/manual/manual-core.html
|
81
|
+
"--xml-file=#{File.join(temp_dir, "%p.xml")}",
|
82
|
+
]
|
83
|
+
|
84
|
+
@loaded_features_file = Tempfile.create("", @temp_dir)
|
84
85
|
end
|
85
86
|
|
86
87
|
def command(*args)
|
@@ -97,6 +98,7 @@ module RubyMemcheck
|
|
97
98
|
valgrind_suppression_files.map { |f| "--suppressions=#{f}" },
|
98
99
|
valgrind_generate_suppressions ? "--gen-suppressions=all" : "",
|
99
100
|
ruby,
|
101
|
+
"-r" + File.expand_path(File.join(__dir__, "test_helper.rb")),
|
100
102
|
args,
|
101
103
|
].flatten.join(" ")
|
102
104
|
end
|
@@ -112,14 +114,7 @@ module RubyMemcheck
|
|
112
114
|
versions << RUBY_ENGINE
|
113
115
|
|
114
116
|
versions.map do |version|
|
115
|
-
|
116
|
-
|
117
|
-
unless old_format_files.empty?
|
118
|
-
warn("ruby_memcheck: please migrate your suppression filenames from " \
|
119
|
-
"`gem_name_ruby-3.1.0.supp` to `ruby-3.1.0.supp` (drop the gem name from the filename)")
|
120
|
-
end
|
121
|
-
|
122
|
-
old_format_files + Dir[File.join(dir, "#{version}.supp")]
|
117
|
+
Dir[File.join(dir, "#{version}.supp")]
|
123
118
|
end.flatten
|
124
119
|
end
|
125
120
|
end
|
data/lib/ruby_memcheck/frame.rb
CHANGED
@@ -2,10 +2,12 @@
|
|
2
2
|
|
3
3
|
module RubyMemcheck
|
4
4
|
class Frame
|
5
|
-
attr_reader :configuration, :fn, :obj, :file, :line
|
5
|
+
attr_reader :configuration, :loaded_binaries, :fn, :obj, :file, :line
|
6
6
|
|
7
|
-
def initialize(configuration, frame_xml)
|
7
|
+
def initialize(configuration, loaded_binaries, frame_xml)
|
8
8
|
@configuration = configuration
|
9
|
+
@loaded_binaries = loaded_binaries
|
10
|
+
|
9
11
|
@fn = frame_xml.at_xpath("fn")&.content
|
10
12
|
@obj = frame_xml.at_xpath("obj")&.content
|
11
13
|
# file and line may not be available
|
@@ -24,8 +26,14 @@ module RubyMemcheck
|
|
24
26
|
def in_binary?
|
25
27
|
return false unless obj
|
26
28
|
|
27
|
-
|
28
|
-
|
29
|
+
loaded_binaries.include?(obj)
|
30
|
+
end
|
31
|
+
|
32
|
+
def binary_init_func?
|
33
|
+
return false unless in_binary?
|
34
|
+
|
35
|
+
binary_name = File.basename(obj, ".*")
|
36
|
+
fn == "Init_#{binary_name}"
|
29
37
|
end
|
30
38
|
|
31
39
|
def to_s
|
@@ -5,9 +5,8 @@ require "rspec/core/rake_task"
|
|
5
5
|
module RubyMemcheck
|
6
6
|
module RSpec
|
7
7
|
class RakeTask < ::RSpec::Core::RakeTask
|
8
|
-
include TestTaskReporter
|
9
|
-
|
10
8
|
attr_reader :configuration
|
9
|
+
attr_reader :reporter
|
11
10
|
|
12
11
|
def initialize(*args)
|
13
12
|
@configuration =
|
@@ -23,15 +22,14 @@ module RubyMemcheck
|
|
23
22
|
def run_task(verbose)
|
24
23
|
error = nil
|
25
24
|
|
26
|
-
|
25
|
+
@reporter = TestTaskReporter.new(configuration)
|
26
|
+
@reporter.run_ruby_with_valgrind do
|
27
27
|
# RSpec::Core::RakeTask#run_task calls Kernel.exit on failure
|
28
28
|
super
|
29
29
|
rescue SystemExit => e
|
30
30
|
error = e
|
31
31
|
end
|
32
32
|
|
33
|
-
report_valgrind_errors
|
34
|
-
|
35
33
|
raise error if error
|
36
34
|
end
|
37
35
|
|
@@ -40,7 +38,6 @@ module RubyMemcheck
|
|
40
38
|
def spec_command
|
41
39
|
# First part of command is Ruby
|
42
40
|
args = super.split(" ")[1..]
|
43
|
-
args.unshift("-r" + File.expand_path(File.join(__dir__, "../test_helper.rb")))
|
44
41
|
|
45
42
|
configuration.command(args)
|
46
43
|
end
|
data/lib/ruby_memcheck/stack.rb
CHANGED
@@ -4,30 +4,28 @@ module RubyMemcheck
|
|
4
4
|
class Stack
|
5
5
|
attr_reader :configuration, :frames
|
6
6
|
|
7
|
-
def initialize(configuration, stack_xml)
|
7
|
+
def initialize(configuration, loaded_binaries, stack_xml)
|
8
8
|
@configuration = configuration
|
9
|
-
@frames = stack_xml.xpath("frame").map { |frame| Frame.new(configuration, frame) }
|
9
|
+
@frames = stack_xml.xpath("frame").map { |frame| Frame.new(configuration, loaded_binaries, frame) }
|
10
10
|
end
|
11
11
|
|
12
12
|
def skip?
|
13
13
|
in_binary = false
|
14
14
|
|
15
15
|
frames.each do |frame|
|
16
|
-
fn = frame.fn
|
17
|
-
|
18
16
|
if frame.in_ruby?
|
19
17
|
# If a stack from from the binary was encountered first, then this
|
20
18
|
# memory leak did not occur from Ruby
|
21
19
|
unless in_binary
|
22
20
|
# Skip this stack because it was called from Ruby
|
23
|
-
return true if configuration.skipped_ruby_functions.any? { |r| r.match?(fn) }
|
21
|
+
return true if configuration.skipped_ruby_functions.any? { |r| r.match?(frame.fn) }
|
24
22
|
end
|
25
23
|
elsif frame.in_binary?
|
26
24
|
in_binary = true
|
27
25
|
|
28
26
|
# Skip the Init function because it is only ever called once, so
|
29
27
|
# leaks in it cannot cause memory bloat
|
30
|
-
return true if
|
28
|
+
return true if frame.binary_init_func?
|
31
29
|
end
|
32
30
|
end
|
33
31
|
|
@@ -2,9 +2,8 @@
|
|
2
2
|
|
3
3
|
module RubyMemcheck
|
4
4
|
class TestTask < Rake::TestTask
|
5
|
-
include TestTaskReporter
|
6
|
-
|
7
5
|
attr_reader :configuration
|
6
|
+
attr_reader :reporter
|
8
7
|
|
9
8
|
def initialize(*args)
|
10
9
|
@configuration =
|
@@ -18,10 +17,14 @@ module RubyMemcheck
|
|
18
17
|
end
|
19
18
|
|
20
19
|
def ruby(*args, **options, &block)
|
21
|
-
args.unshift("-r" + File.expand_path(File.join(__dir__, "test_helper.rb")))
|
22
20
|
command = configuration.command(args)
|
21
|
+
|
22
|
+
@reporter = TestTaskReporter.new(configuration)
|
23
|
+
|
24
|
+
@reporter.setup
|
25
|
+
|
23
26
|
sh(command, **options) do |ok, res|
|
24
|
-
report_valgrind_errors
|
27
|
+
@reporter.report_valgrind_errors
|
25
28
|
|
26
29
|
yield ok, res if block_given?
|
27
30
|
end
|
@@ -1,36 +1,62 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module RubyMemcheck
|
4
|
-
|
4
|
+
class TestTaskReporter
|
5
5
|
VALGRIND_REPORT_MSG = "Valgrind reported errors (e.g. memory leak or use-after-free)"
|
6
6
|
|
7
|
+
attr_reader :configuration
|
7
8
|
attr_reader :errors
|
8
9
|
|
9
|
-
|
10
|
+
def initialize(configuration)
|
11
|
+
@configuration = configuration
|
12
|
+
@loaded_binaries = nil
|
13
|
+
end
|
14
|
+
|
15
|
+
def run_ruby_with_valgrind(&block)
|
16
|
+
setup
|
17
|
+
yield
|
18
|
+
report_valgrind_errors
|
19
|
+
end
|
20
|
+
|
21
|
+
def setup
|
22
|
+
ENV["RUBY_MEMCHECK_LOADED_FEATURES_FILE"] = File.expand_path(configuration.loaded_features_file)
|
23
|
+
ENV["RUBY_MEMCHECK_RUNNING"] = "1"
|
24
|
+
end
|
10
25
|
|
11
26
|
def report_valgrind_errors
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
output_valgrind_errors
|
19
|
-
raise VALGRIND_REPORT_MSG
|
20
|
-
end
|
27
|
+
parse_valgrind_output
|
28
|
+
remove_valgrind_xml_files
|
29
|
+
|
30
|
+
unless errors.empty?
|
31
|
+
output_valgrind_errors
|
32
|
+
raise VALGRIND_REPORT_MSG
|
21
33
|
end
|
22
34
|
end
|
23
35
|
|
36
|
+
private
|
37
|
+
|
38
|
+
def loaded_binaries
|
39
|
+
return @loaded_binaries if @loaded_binaries
|
40
|
+
|
41
|
+
loaded_features = File.readlines(configuration.loaded_features_file, chomp: true)
|
42
|
+
@loaded_binaries = loaded_features.keep_if do |feat|
|
43
|
+
# Keep only binaries (ignore Ruby files).
|
44
|
+
File.extname(feat) == ".so"
|
45
|
+
end.freeze
|
46
|
+
|
47
|
+
@loaded_binaries
|
48
|
+
end
|
49
|
+
|
24
50
|
def valgrind_xml_files
|
25
|
-
Dir[File.join(configuration.
|
51
|
+
@valgrind_xml_files ||= Dir[File.join(configuration.temp_dir, "*.xml")].freeze
|
26
52
|
end
|
27
53
|
|
28
|
-
def parse_valgrind_output
|
54
|
+
def parse_valgrind_output
|
29
55
|
require "nokogiri"
|
30
56
|
|
31
57
|
@errors = []
|
32
58
|
|
33
|
-
|
59
|
+
valgrind_xml_files.each do |file|
|
34
60
|
reader = Nokogiri::XML::Reader(File.open(file)) do |config| # rubocop:disable Style/SymbolProc
|
35
61
|
config.huge
|
36
62
|
end
|
@@ -38,7 +64,7 @@ module RubyMemcheck
|
|
38
64
|
next unless node.name == "error" && node.node_type == Nokogiri::XML::Reader::TYPE_ELEMENT
|
39
65
|
|
40
66
|
error_xml = Nokogiri::XML::Document.parse(node.outer_xml).root
|
41
|
-
error = ValgrindError.new(configuration, error_xml)
|
67
|
+
error = ValgrindError.new(configuration, loaded_binaries, error_xml)
|
42
68
|
next if error.skip?
|
43
69
|
|
44
70
|
@errors << error
|
@@ -46,8 +72,8 @@ module RubyMemcheck
|
|
46
72
|
end
|
47
73
|
end
|
48
74
|
|
49
|
-
def remove_valgrind_xml_files
|
50
|
-
|
75
|
+
def remove_valgrind_xml_files
|
76
|
+
valgrind_xml_files.each do |file|
|
51
77
|
File.delete(file)
|
52
78
|
end
|
53
79
|
end
|
@@ -7,7 +7,7 @@ module RubyMemcheck
|
|
7
7
|
|
8
8
|
attr_reader :kind, :msg, :stack, :suppression
|
9
9
|
|
10
|
-
def initialize(configuration, error)
|
10
|
+
def initialize(configuration, loaded_binaries, error)
|
11
11
|
@kind = error.at_xpath("kind").content
|
12
12
|
@msg =
|
13
13
|
if kind_leak?
|
@@ -15,7 +15,7 @@ module RubyMemcheck
|
|
15
15
|
else
|
16
16
|
error.at_xpath("what").content
|
17
17
|
end
|
18
|
-
@stack = Stack.new(configuration, error.at_xpath("stack"))
|
18
|
+
@stack = Stack.new(configuration, loaded_binaries, error.at_xpath("stack"))
|
19
19
|
@configuration = configuration
|
20
20
|
|
21
21
|
suppression_node = error.at_xpath("suppression")
|
data/lib/ruby_memcheck.rb
CHANGED
@@ -19,11 +19,7 @@ module RubyMemcheck
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def default_configuration
|
22
|
-
|
23
|
-
raise "RubyMemcheck is not configured with a default configuration. "\
|
24
|
-
"Please run RubyMemcheck.config before using it."
|
25
|
-
end
|
26
|
-
@default_configuration
|
22
|
+
@default_configuration ||= config
|
27
23
|
end
|
28
24
|
end
|
29
25
|
end
|
data/ruby_memcheck.gemspec
CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
|
|
9
9
|
spec.email = ["peter@peterzhu.ca"]
|
10
10
|
|
11
11
|
spec.summary = "Use Valgrind memcheck without going crazy"
|
12
|
-
spec.homepage = "https://github.com/
|
12
|
+
spec.homepage = "https://github.com/Shopify/ruby_memcheck"
|
13
13
|
spec.license = "MIT"
|
14
14
|
spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
|
15
15
|
|
data/suppressions/ruby.supp
CHANGED
@@ -12,13 +12,6 @@
|
|
12
12
|
fun:require_internal
|
13
13
|
...
|
14
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
|
-
}
|
22
15
|
{
|
23
16
|
recursive_list_access creates a hash called `list` that is stored on the threadptr_recursive_hash. This is reported as a memory leak.
|
24
17
|
Memcheck:Leak
|
@@ -50,3 +43,20 @@
|
|
50
43
|
fun:*try_statx*
|
51
44
|
...
|
52
45
|
}
|
46
|
+
{
|
47
|
+
strscan_do_scan in strscan.c will sometimes replace the ptr of the regex, which can be reported as a memory leak if the regex is stored in an iseq. https://github.com/ruby/ruby/pull/8136
|
48
|
+
Memcheck:Leak
|
49
|
+
...
|
50
|
+
fun:rb_reg_prepare_re
|
51
|
+
fun:strscan_do_scan
|
52
|
+
...
|
53
|
+
}
|
54
|
+
{
|
55
|
+
The callcache table (RCLASS_CC_TBL) is lazily created, so it is allocated when the first method that gets cached. If this happens in a native extension, it may be reported as a memory leak.
|
56
|
+
Memcheck:Leak
|
57
|
+
...
|
58
|
+
fun:rb_id_table_create
|
59
|
+
...
|
60
|
+
fun:rb_callable_method_entry
|
61
|
+
...
|
62
|
+
}
|
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:
|
4
|
+
version: 2.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Peter Zhu
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-08-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nokogiri
|
@@ -129,6 +129,7 @@ executables: []
|
|
129
129
|
extensions: []
|
130
130
|
extra_rdoc_files: []
|
131
131
|
files:
|
132
|
+
- ".github/workflows/cla.yml"
|
132
133
|
- ".github/workflows/lint.yml"
|
133
134
|
- ".github/workflows/test.yml"
|
134
135
|
- ".gitignore"
|
@@ -150,11 +151,11 @@ files:
|
|
150
151
|
- lib/ruby_memcheck/version.rb
|
151
152
|
- ruby_memcheck.gemspec
|
152
153
|
- suppressions/ruby.supp
|
153
|
-
homepage: https://github.com/
|
154
|
+
homepage: https://github.com/Shopify/ruby_memcheck
|
154
155
|
licenses:
|
155
156
|
- MIT
|
156
157
|
metadata:
|
157
|
-
homepage_uri: https://github.com/
|
158
|
+
homepage_uri: https://github.com/Shopify/ruby_memcheck
|
158
159
|
post_install_message:
|
159
160
|
rdoc_options: []
|
160
161
|
require_paths:
|