ruby_memcheck 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.github/workflows/lint.yml +12 -0
- data/.github/workflows/test.yml +22 -0
- data/.gitignore +12 -0
- data/.rubocop.yml +5 -0
- data/Gemfile +5 -0
- data/LICENSE.txt +21 -0
- data/README.md +97 -0
- data/Rakefile +20 -0
- data/lib/ruby_memcheck/configuration.rb +90 -0
- data/lib/ruby_memcheck/frame.rb +28 -0
- data/lib/ruby_memcheck/stack.rb +11 -0
- data/lib/ruby_memcheck/test_task.rb +55 -0
- data/lib/ruby_memcheck/valgrind_error.rb +50 -0
- data/lib/ruby_memcheck/version.rb +5 -0
- data/lib/ruby_memcheck.rb +28 -0
- data/ruby_memcheck.gemspec +34 -0
- metadata +144 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 84b08d7b0d1f0f1a254be4d2634c44055c21c415ccfa12d69c9bef56763291bf
|
4
|
+
data.tar.gz: b73189e2d75124b4117565ba97a2fadf1a1b8ef9963bf6d8528fb04bd19c0b33
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 682b181ca12116b0383a317304e9f931b4ccc4459259ef87b5d7823641ae73ec1077954e0a80b704ee20d525d39f01ea12ded58e24e39c48e69a065e79811873
|
7
|
+
data.tar.gz: 82ea0151eebe57bcc43cc7316ba93ad6bb8af5413c311ffd48d78ebf105091774a1c28364a8acef7b4dafcfb4cc21fa4a542f43457bda44a69b8f63b9294f177
|
@@ -0,0 +1,12 @@
|
|
1
|
+
name: Lint
|
2
|
+
on: [push, pull_request]
|
3
|
+
jobs:
|
4
|
+
rubocop:
|
5
|
+
runs-on: ubuntu-latest
|
6
|
+
steps:
|
7
|
+
- uses: actions/checkout@v2
|
8
|
+
- uses: ruby/setup-ruby@v1
|
9
|
+
with:
|
10
|
+
ruby-version: '3.0'
|
11
|
+
- run: bundle install --jobs=3 --retry=3 --path=vendor/bundle
|
12
|
+
- run: bundle exec rubocop
|
@@ -0,0 +1,22 @@
|
|
1
|
+
name: Test
|
2
|
+
on: [push, pull_request]
|
3
|
+
jobs:
|
4
|
+
test:
|
5
|
+
runs-on: ubuntu-latest
|
6
|
+
strategy:
|
7
|
+
matrix:
|
8
|
+
entry:
|
9
|
+
- { ruby: '2.6', allowed-failure: false }
|
10
|
+
- { ruby: '2.7', allowed-failure: false }
|
11
|
+
- { ruby: '3.0', allowed-failure: false }
|
12
|
+
- { ruby: ruby-head, allowed-failure: false }
|
13
|
+
name: ruby ${{ matrix.entry.ruby }}
|
14
|
+
steps:
|
15
|
+
- uses: actions/checkout@v2
|
16
|
+
- uses: ruby/setup-ruby@v1
|
17
|
+
with:
|
18
|
+
ruby-version: ${{ matrix.entry.ruby }}
|
19
|
+
- run: sudo apt-get install -y valgrind
|
20
|
+
- run: bundle install --jobs=3 --retry=3
|
21
|
+
- run: bundle exec rake
|
22
|
+
continue-on-error: ${{ matrix.entry.allowed-failure }}
|
data/.gitignore
ADDED
data/.rubocop.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2021 Peter Zhu
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
# ruby_memcheck
|
2
|
+
|
3
|
+
This gem provides a sane way to use Valgrind's memcheck on your native extension gem.
|
4
|
+
|
5
|
+
## Table of contents
|
6
|
+
|
7
|
+
1. [What is this gem?](#what-is-this-gem)
|
8
|
+
1. [Who should use this gem?](#who-should-use-this-gem)
|
9
|
+
1. [How does it work?](#how-does-it-work)
|
10
|
+
1. [Limitations](#limitations)
|
11
|
+
1. [Installation](#installation)
|
12
|
+
1. [Usage](#usage)
|
13
|
+
|
14
|
+
## What is this gem?
|
15
|
+
|
16
|
+
Valgrind's memcheck is a great tool to find and debug memory issues (e.g. memory leak, use-after-free, etc.). However, it doesn't work well on Ruby because Ruby does not free all of the memory it allocates during shutdown. This results in Valgrind reporting thousands (or more) false-positives, making it very difficult for Valgrind to actually be useful. This gem solves the problem by using heuristics to filter out false-positives.
|
17
|
+
|
18
|
+
### Who should use this gem?
|
19
|
+
|
20
|
+
Only gems with native extensions can use this gem. If your gem is written in plain Ruby, this gem is not useful for you.
|
21
|
+
|
22
|
+
### How does it work?
|
23
|
+
|
24
|
+
This gem runs Valgrind with the `--xml` option to generate a 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.
|
25
|
+
|
26
|
+
### Limitations
|
27
|
+
|
28
|
+
Because of the aggressive heuristics used to filter out false-positives, there are various limitations of what this gem can detect.
|
29
|
+
|
30
|
+
1. This gem is only expected to work on Linux.
|
31
|
+
1. It will not find memory leaks in Ruby. It filters out everything in Ruby.
|
32
|
+
1. It will not find memory leaks of allocations that occurred in Ruby (even if the memory leak is caused by your native extension).
|
33
|
+
|
34
|
+
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.
|
35
|
+
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).
|
36
|
+
1. It will not find leaks that occur in the `Init` function of your native extension.
|
37
|
+
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!).
|
38
|
+
|
39
|
+
## Installation
|
40
|
+
|
41
|
+
Add this line to your application's Gemfile:
|
42
|
+
|
43
|
+
```ruby
|
44
|
+
gem "ruby_memcheck"
|
45
|
+
```
|
46
|
+
|
47
|
+
## Usage
|
48
|
+
|
49
|
+
The easiest way to use this gem is to use it on your test suite using rake.
|
50
|
+
|
51
|
+
0. Install Valgrind.
|
52
|
+
1. In your Rakefile, require this gem.
|
53
|
+
|
54
|
+
```ruby
|
55
|
+
require "ruby_memcheck"
|
56
|
+
```
|
57
|
+
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!
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
RubyMemcheck.config(binary_name: "your_binary_name")
|
61
|
+
```
|
62
|
+
1. Locate your test task(s) in your Rakefile. You can identify it with a call to `Rake::TestTask.new`.
|
63
|
+
1. Create a namespace under the test task and create a `RubyMemcheck::TestTask` with the same configuration.
|
64
|
+
|
65
|
+
For example, if your Rakefile looked like this before:
|
66
|
+
|
67
|
+
```ruby
|
68
|
+
Rake::TestTask.new(test: :compile) do |t|
|
69
|
+
t.libs << "test"
|
70
|
+
t.test_files = FileList["test/unit/**/*_test.rb"]
|
71
|
+
end
|
72
|
+
```
|
73
|
+
|
74
|
+
You can change it to look like this:
|
75
|
+
|
76
|
+
```ruby
|
77
|
+
test_config = lambda do |t|
|
78
|
+
t.libs << "test"
|
79
|
+
t.test_files = FileList["test/**/*_test.rb"]
|
80
|
+
end
|
81
|
+
Rake::TestTask.new(test: :compile, &test_config)
|
82
|
+
namespace :test do
|
83
|
+
RubyMemcheck::TestTask.new(valgrind: :compile, &test_config)
|
84
|
+
end
|
85
|
+
```
|
86
|
+
1. In your `test_helper.rb`/`spec_helper.rb` (or whatever file sets up your test suite), add this line:
|
87
|
+
|
88
|
+
```ruby
|
89
|
+
END { GC.start }
|
90
|
+
```
|
91
|
+
|
92
|
+
This will ensure that the Garbage Collector is ran before Ruby shuts down. This will reduce the number of false-positives.
|
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
|
+
|
95
|
+
## License
|
96
|
+
|
97
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "bundler/gem_tasks"
|
4
|
+
require "rake/testtask"
|
5
|
+
require "rake/extensiontask"
|
6
|
+
|
7
|
+
Rake::TestTask.new(test: "test:compile") do |t|
|
8
|
+
t.libs << "test"
|
9
|
+
t.libs << "lib"
|
10
|
+
t.test_files = FileList["test/**/*_test.rb"]
|
11
|
+
end
|
12
|
+
|
13
|
+
namespace :test do
|
14
|
+
Rake::ExtensionTask.new("ruby_memcheck_c_test") do |ext|
|
15
|
+
ext.ext_dir = "test/ruby_memcheck/ext"
|
16
|
+
ext.lib_dir = "test/ruby_memcheck/ext"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
task default: :test
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RubyMemcheck
|
4
|
+
class Configuration
|
5
|
+
DEFAULT_VALGRIND = "valgrind"
|
6
|
+
DEFAULT_VALGRIND_OPTIONS = [
|
7
|
+
"--num-callers=50",
|
8
|
+
"--error-limit=no",
|
9
|
+
"--undef-value-errors=no",
|
10
|
+
"--leak-check=full",
|
11
|
+
"--show-leak-kinds=definite",
|
12
|
+
].freeze
|
13
|
+
DEFAULT_SKIPPED_RUBY_FUNCTIONS = [
|
14
|
+
/\Arb_check_funcall/,
|
15
|
+
/\Arb_enc_raise\z/,
|
16
|
+
/\Arb_funcall/,
|
17
|
+
/\Arb_ivar_set\z/,
|
18
|
+
/\Arb_raise\z/,
|
19
|
+
/\Arb_rescue/,
|
20
|
+
/\Arb_respond_to\z/,
|
21
|
+
/\Arb_yield/,
|
22
|
+
].freeze
|
23
|
+
|
24
|
+
attr_reader :binary_name, :ruby, :valgrind_options, :valgrind,
|
25
|
+
:skipped_ruby_functions, :valgrind_xml_file, :output_io
|
26
|
+
|
27
|
+
def initialize(
|
28
|
+
binary_name:,
|
29
|
+
ruby: FileUtils::RUBY,
|
30
|
+
valgrind: DEFAULT_VALGRIND,
|
31
|
+
valgrind_options: DEFAULT_VALGRIND_OPTIONS,
|
32
|
+
skipped_ruby_functions: DEFAULT_SKIPPED_RUBY_FUNCTIONS,
|
33
|
+
valgrind_xml_file: Tempfile.new,
|
34
|
+
output_io: $stderr
|
35
|
+
)
|
36
|
+
@binary_name = binary_name
|
37
|
+
@ruby = ruby
|
38
|
+
@valgrind = valgrind
|
39
|
+
@valgrind_options = valgrind_options
|
40
|
+
@skipped_ruby_functions = skipped_ruby_functions
|
41
|
+
@output_io = output_io
|
42
|
+
|
43
|
+
if valgrind_xml_file
|
44
|
+
@valgrind_xml_file = valgrind_xml_file
|
45
|
+
@valgrind_options += [
|
46
|
+
"--xml=yes",
|
47
|
+
"--xml-file=#{valgrind_xml_file.path}",
|
48
|
+
]
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def command(*args)
|
53
|
+
"#{valgrind} #{valgrind_options.join(" ")} #{ruby} #{args.join(" ")}"
|
54
|
+
end
|
55
|
+
|
56
|
+
def skip_stack?(stack)
|
57
|
+
in_binary = false
|
58
|
+
|
59
|
+
stack.frames.each do |frame|
|
60
|
+
fn = frame.fn
|
61
|
+
|
62
|
+
if frame_in_ruby?(frame) # in ruby
|
63
|
+
unless in_binary
|
64
|
+
# Skip this stack because it was called from Ruby
|
65
|
+
return true if skipped_ruby_functions.any? { |r| r.match?(fn) }
|
66
|
+
end
|
67
|
+
elsif frame_in_binary?(frame) # in binary
|
68
|
+
in_binary = true
|
69
|
+
|
70
|
+
# Skip the Init function
|
71
|
+
return true if fn == "Init_#{binary_name}"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
!in_binary
|
76
|
+
end
|
77
|
+
|
78
|
+
def frame_in_ruby?(frame)
|
79
|
+
frame.obj == ruby
|
80
|
+
end
|
81
|
+
|
82
|
+
def frame_in_binary?(frame)
|
83
|
+
if frame.obj
|
84
|
+
File.basename(frame.obj, ".*") == binary_name
|
85
|
+
else
|
86
|
+
false
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RubyMemcheck
|
4
|
+
class Frame
|
5
|
+
attr_reader :fn, :obj, :file, :line, :in_binary
|
6
|
+
alias_method :in_binary?, :in_binary
|
7
|
+
|
8
|
+
def initialize(configuration, frame_xml)
|
9
|
+
@fn = frame_xml.at_xpath("fn")&.content
|
10
|
+
@obj = frame_xml.at_xpath("obj")&.content
|
11
|
+
# file and line may not be available
|
12
|
+
@file = frame_xml.at_xpath("file")&.content
|
13
|
+
@line = frame_xml.at_xpath("line")&.content
|
14
|
+
|
15
|
+
@in_binary = configuration.frame_in_binary?(self)
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_s
|
19
|
+
if file
|
20
|
+
"#{fn} (#{file}:#{line})"
|
21
|
+
elsif fn
|
22
|
+
"#{fn} (at #{obj})"
|
23
|
+
else
|
24
|
+
"<unknown stack frame>"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RubyMemcheck
|
4
|
+
class TestTask < Rake::TestTask
|
5
|
+
VALGRIND_REPORT_MSG = "Valgrind reported errors (e.g. memory leak or use-after-free)"
|
6
|
+
|
7
|
+
attr_reader :configuration, :errors
|
8
|
+
|
9
|
+
def initialize(*args)
|
10
|
+
@configuration =
|
11
|
+
if !args.empty? && args[0].is_a?(Configuration)
|
12
|
+
args.shift
|
13
|
+
else
|
14
|
+
RubyMemcheck.default_configuration
|
15
|
+
end
|
16
|
+
|
17
|
+
super
|
18
|
+
end
|
19
|
+
|
20
|
+
def ruby(*args, **options, &block)
|
21
|
+
command = configuration.command(args)
|
22
|
+
sh(command, **options) do |ok, res|
|
23
|
+
if ok && configuration.valgrind_xml_file
|
24
|
+
parse_valgrind_output
|
25
|
+
unless errors.empty?
|
26
|
+
output_valgrind_errors
|
27
|
+
raise VALGRIND_REPORT_MSG
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
yield ok, res if block_given?
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def parse_valgrind_output
|
38
|
+
@errors = []
|
39
|
+
|
40
|
+
xml = Nokogiri::XML(configuration.valgrind_xml_file.read)
|
41
|
+
xml.xpath("/valgrindoutput/error").each do |error|
|
42
|
+
error = ValgrindError.new(configuration, error)
|
43
|
+
next if error.skip?
|
44
|
+
@errors << error
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def output_valgrind_errors
|
49
|
+
@errors.each do |error|
|
50
|
+
configuration.output_io.puts error
|
51
|
+
configuration.output_io.puts
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RubyMemcheck
|
4
|
+
class ValgrindError
|
5
|
+
attr_reader :kind, :msg, :stack
|
6
|
+
|
7
|
+
def initialize(configuration, error)
|
8
|
+
@kind = error.at_xpath("kind").content
|
9
|
+
@msg =
|
10
|
+
if kind_leak?
|
11
|
+
error.at_xpath("xwhat/text").content
|
12
|
+
else
|
13
|
+
error.at_xpath("what").content
|
14
|
+
end
|
15
|
+
@stack = Stack.new(configuration, error.at_xpath("stack"))
|
16
|
+
@configuration = configuration
|
17
|
+
end
|
18
|
+
|
19
|
+
def skip?
|
20
|
+
if should_filter?
|
21
|
+
@configuration.skip_stack?(stack)
|
22
|
+
else
|
23
|
+
false
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_s
|
28
|
+
str = StringIO.new
|
29
|
+
str << "#{msg}\n"
|
30
|
+
stack.frames.each do |frame|
|
31
|
+
str << if frame.in_binary?
|
32
|
+
" *#{frame}\n"
|
33
|
+
else
|
34
|
+
" #{frame}\n"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
str.string
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def should_filter?
|
43
|
+
kind_leak?
|
44
|
+
end
|
45
|
+
|
46
|
+
def kind_leak?
|
47
|
+
kind.start_with?("Leak_")
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "tempfile"
|
4
|
+
require "nokogiri"
|
5
|
+
require "rake/testtask"
|
6
|
+
|
7
|
+
require "ruby_memcheck/configuration"
|
8
|
+
require "ruby_memcheck/frame"
|
9
|
+
require "ruby_memcheck/stack"
|
10
|
+
require "ruby_memcheck/test_task"
|
11
|
+
require "ruby_memcheck/valgrind_error"
|
12
|
+
require "ruby_memcheck/version"
|
13
|
+
|
14
|
+
module RubyMemcheck
|
15
|
+
class << self
|
16
|
+
def config(**opts)
|
17
|
+
@default_configuration = Configuration.new(**opts)
|
18
|
+
end
|
19
|
+
|
20
|
+
def default_configuration
|
21
|
+
unless @default_configuration
|
22
|
+
raise "RubyMemcheck is not configured with a default configuration. "\
|
23
|
+
"Please run RubyMemcheck.config before using it."
|
24
|
+
end
|
25
|
+
@default_configuration
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "lib/ruby_memcheck/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "ruby_memcheck"
|
7
|
+
spec.version = RubyMemcheck::VERSION
|
8
|
+
spec.authors = ["Peter Zhu"]
|
9
|
+
spec.email = ["peter@peterzhu.ca"]
|
10
|
+
|
11
|
+
spec.summary = "Use Valgrind memcheck without going crazy"
|
12
|
+
spec.homepage = "https://github.com/peterzhu2118/ruby_memcheck"
|
13
|
+
spec.license = "MIT"
|
14
|
+
spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
|
15
|
+
|
16
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
17
|
+
|
18
|
+
# Specify which files should be added to the gem when it is released.
|
19
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
20
|
+
spec.files = Dir.chdir(File.expand_path("..", __FILE__)) do
|
21
|
+
%x(git ls-files -z).split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
22
|
+
end
|
23
|
+
spec.bindir = "exe"
|
24
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
25
|
+
spec.require_paths = ["lib"]
|
26
|
+
|
27
|
+
spec.add_dependency("nokogiri")
|
28
|
+
|
29
|
+
spec.add_development_dependency("minitest", "~> 5.0")
|
30
|
+
spec.add_development_dependency("rake", "~> 13.0")
|
31
|
+
spec.add_development_dependency("rake-compiler", "~> 1.1")
|
32
|
+
spec.add_development_dependency("rubocop", "~> 1.22")
|
33
|
+
spec.add_development_dependency("rubocop-shopify", "~> 2.3")
|
34
|
+
end
|
metadata
ADDED
@@ -0,0 +1,144 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ruby_memcheck
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Peter Zhu
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2021-10-15 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: nokogiri
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: minitest
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '5.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '5.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '13.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '13.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake-compiler
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.1'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.1'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rubocop
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '1.22'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '1.22'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rubocop-shopify
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '2.3'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '2.3'
|
97
|
+
description:
|
98
|
+
email:
|
99
|
+
- peter@peterzhu.ca
|
100
|
+
executables: []
|
101
|
+
extensions: []
|
102
|
+
extra_rdoc_files: []
|
103
|
+
files:
|
104
|
+
- ".github/workflows/lint.yml"
|
105
|
+
- ".github/workflows/test.yml"
|
106
|
+
- ".gitignore"
|
107
|
+
- ".rubocop.yml"
|
108
|
+
- Gemfile
|
109
|
+
- LICENSE.txt
|
110
|
+
- README.md
|
111
|
+
- Rakefile
|
112
|
+
- lib/ruby_memcheck.rb
|
113
|
+
- lib/ruby_memcheck/configuration.rb
|
114
|
+
- lib/ruby_memcheck/frame.rb
|
115
|
+
- lib/ruby_memcheck/stack.rb
|
116
|
+
- lib/ruby_memcheck/test_task.rb
|
117
|
+
- lib/ruby_memcheck/valgrind_error.rb
|
118
|
+
- lib/ruby_memcheck/version.rb
|
119
|
+
- ruby_memcheck.gemspec
|
120
|
+
homepage: https://github.com/peterzhu2118/ruby_memcheck
|
121
|
+
licenses:
|
122
|
+
- MIT
|
123
|
+
metadata:
|
124
|
+
homepage_uri: https://github.com/peterzhu2118/ruby_memcheck
|
125
|
+
post_install_message:
|
126
|
+
rdoc_options: []
|
127
|
+
require_paths:
|
128
|
+
- lib
|
129
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
130
|
+
requirements:
|
131
|
+
- - ">="
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: 2.3.0
|
134
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
requirements: []
|
140
|
+
rubygems_version: 3.2.15
|
141
|
+
signing_key:
|
142
|
+
specification_version: 4
|
143
|
+
summary: Use Valgrind memcheck without going crazy
|
144
|
+
test_files: []
|