heapinfo 0.0.5 → 0.1.0

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.
data/lib/heapinfo/libc.rb CHANGED
@@ -2,15 +2,15 @@ module HeapInfo
2
2
  # Record libc's base, name, and offsets.
3
3
  class Libc < Segment
4
4
  include HeapInfo::Glibc
5
- # Instantiate a <tt>HeapInfo::Libc</tt> object.
5
+ # Instantiate a {HeapInfo::Libc} object.
6
6
  #
7
- # @param [Mixed] args See <tt>#HeapInfo::Segment.initialize</tt> for more information.
7
+ # @param [Mixed] args See {HeapInfo::Segment#initialize} for more information.
8
8
  def initialize(*args)
9
9
  super
10
10
  @offset = {}
11
11
  end
12
12
 
13
- # Get the offset of <tt>main_arena</tt> in libc.
13
+ # Get the offset of +main_arena+ in libc.
14
14
  # @return [Integer]
15
15
  def main_arena_offset
16
16
  return @offset[:main_arena] if @offset[:main_arena]
@@ -18,17 +18,17 @@ module HeapInfo
18
18
  @offset[:main_arena]
19
19
  end
20
20
 
21
- # Get the <tt>main_arena</tt> of libc.
21
+ # Get the +main_arena+ of libc.
22
22
  # @return [HeapInfo::Arena]
23
23
  def main_arena
24
24
  return @main_arena.reload! if @main_arena
25
25
  off = main_arena_offset
26
26
  return if off.nil?
27
- @main_arena = Arena.new(off + self.base, size_t, dumper)
27
+ @main_arena = Arena.new(off + base, size_t, dumper)
28
28
  end
29
29
 
30
- # @param [Array] maps See <tt>#HeapInfo::Segment.find</tt> for more information.
31
- # @param [String] name See <tt>#HeapInfo::Segment.find</tt> for more information.
30
+ # @param [Array] maps See {HeapInfo::Segment#find} for more information.
31
+ # @param [String] name See {HeapInfo::Segment#find} for more information.
32
32
  # @param [Integer] bits Either 64 or 32.
33
33
  # @param [String] ld_name The loader's realpath, will be used for running subprocesses.
34
34
  # @param [Proc] dumper The memory dumper for fetch more information.
@@ -41,7 +41,8 @@ module HeapInfo
41
41
  obj
42
42
  end
43
43
 
44
- private
44
+ private
45
+
45
46
  attr_accessor :ld_name
46
47
  # only for searching offset of main_arena now
47
48
  def exhaust_search(symbol)
@@ -51,23 +52,23 @@ module HeapInfo
51
52
  end
52
53
 
53
54
  def read_main_arena_offset
54
- key = HeapInfo::Cache::key_libc_offset(self.name)
55
- @offset = HeapInfo::Cache::read(key) || {}
56
- return @offset[:main_arena] if @offset.key? :main_arena
55
+ key = HeapInfo::Cache.key_libc_offset(name)
56
+ @offset = HeapInfo::Cache.read(key) || {}
57
+ return @offset[:main_arena] if @offset.key?(:main_arena)
57
58
  @offset[:main_arena] = resolve_main_arena_offset
58
- HeapInfo::Cache::write key, @offset
59
+ HeapInfo::Cache.write(key, @offset)
59
60
  end
60
61
 
61
62
  def resolve_main_arena_offset
62
- tmp_elf = HeapInfo::TMP_DIR + "/get_arena"
63
- libc_file = HeapInfo::TMP_DIR + "/libc.so.6"
64
- ld_file = HeapInfo::TMP_DIR + "/ld.so"
63
+ tmp_elf = HeapInfo::TMP_DIR + '/get_arena'
64
+ libc_file = HeapInfo::TMP_DIR + '/libc.so.6'
65
+ ld_file = HeapInfo::TMP_DIR + '/ld.so'
65
66
  flags = "-w #{size_t == 4 ? '-m32' : ''}"
66
- %x(cp #{self.name} #{libc_file} && \
67
+ `cp #{name} #{libc_file} && \
67
68
  cp #{ld_name} #{ld_file} && \
68
69
  gcc #{flags} #{File.expand_path('../tools/get_arena.c', __FILE__)} -o #{tmp_elf} 2>&1 > /dev/null && \
69
70
  #{ld_file} --library-path #{HeapInfo::TMP_DIR} #{tmp_elf} && \
70
- rm #{tmp_elf} #{libc_file} #{ld_file}).to_i(16)
71
+ rm #{tmp_elf} #{libc_file} #{ld_file}`.to_i(16)
71
72
  end
72
73
  end
73
74
  end
data/lib/heapinfo/nil.rb CHANGED
@@ -1,24 +1,30 @@
1
1
  module HeapInfo
2
- # Self defined <tt>nil</tt> like class.
2
+ # Self define a +nil+ like class.
3
3
  #
4
- # Be the return values of <tt>#dump</tt> or <tt>#dump_chunks</tt>, to prevent use the return value for calculating accidentally while exploiting remote.
4
+ # Can be the return value of {HeapInfo::Process#dump} and {HeapInfo::Process#dump_chunks},
5
+ # to prevent use the return value for calculating accidentally while exploiting remote.
5
6
  class Nil
6
7
  %i(nil? inspect to_s).each do |method_sym|
7
- define_method(method_sym){|*args, &block| nil.send(method_sym, *args, &block)}
8
+ define_method(method_sym) { |*args, &block| nil.send(method_sym, *args, &block) }
8
9
  end
9
10
 
10
11
  # Hook all missing methods
11
- # @return [HeapInfo::Nil] return <tt>self</tt> so that it can be a <tt>nil</tt> chain.
12
+ # @return [HeapInfo::Nil] return +self+ so that it can be a +nil+ chain.
12
13
  # @example
13
14
  # # h.dump would return Nil when process not found
14
- # p h.dump(:heap)[8,8].unpack("Q*)
15
+ # p h.dump(:heap)[8, 8].unpack('Q*')
15
16
  # # => nil
16
17
  def method_missing(method_sym, *args, &block)
17
- return nil.send(method_sym, *args, &block) if nil.respond_to? method_sym
18
- self
18
+ return nil.send(method_sym, *args, &block) if nil.respond_to?(method_sym)
19
+ self || super
19
20
  end
20
21
 
21
- # To prevent error raised when using <tt>puts Nil.new</tt>
22
+ # Yap
23
+ def respond_to_missing?(*)
24
+ super
25
+ end
26
+
27
+ # To prevent error raised when using +puts Nil.new+.
22
28
  # @return [Array] Empty array
23
29
  def to_ary
24
30
  []
@@ -1,13 +1,13 @@
1
- #encoding: ascii-8bit
1
+ # encoding: ascii-8bit
2
2
  module HeapInfo
3
3
  # Main class of heapinfo.
4
4
  class Process
5
5
  # The default options of libaries,
6
6
  # use for matching glibc and ld segments in <tt>/proc/[pid]/maps</tt>
7
7
  DEFAULT_LIB = {
8
- libc: /bc.*\.so/,
9
- ld: /\/ld-.+\.so/,
10
- }
8
+ libc: /bc[^a-z]*\.so/,
9
+ ld: %r{/ld-.+\.so}
10
+ }.freeze
11
11
  # @return [Fixnum, NilClass] return the pid of process, <tt>nil</tt> if no such process found
12
12
  attr_reader :pid
13
13
 
@@ -34,7 +34,7 @@ module HeapInfo
34
34
 
35
35
  # Use this method to wrapper all HeapInfo methods.
36
36
  #
37
- # Since <tt>::HeapInfo</tt> is a tool(debugger) for local usage,
37
+ # Since <tt>::HeapInfo</tt> is a tool(debugger) for local usage,
38
38
  # while exploiting remote service, all methods will not work properly.
39
39
  # So I suggest to wrapper all methods inside <tt>#debug</tt>,
40
40
  # which will ignore the block while the victim process is not found.
@@ -54,10 +54,13 @@ module HeapInfo
54
54
 
55
55
  # Dump the content of specific memory address.
56
56
  #
57
- # Note: This method require you have permission of attaching another process. If not, a warning message will present.
57
+ # Note: This method require you have permission of attaching another process.
58
+ # If not, a warning message will present.
58
59
  #
59
60
  # @param [Mixed] args Will be parsed into <tt>[base, offset, length]</tt>, see Examples for more information.
60
- # @return [String, HeapInfo::Nil] The content needed. When the request address is not readable or the process not exists, <tt>HeapInfo::Nil.new</tt> is returned.
61
+ # @return [String, HeapInfo::Nil]
62
+ # The content needed. When the request address is not readable or the process not exists,
63
+ # <tt>HeapInfo::Nil.new</tt> is returned.
61
64
  #
62
65
  # @example
63
66
  # h = heapinfo('victim')
@@ -102,22 +105,27 @@ module HeapInfo
102
105
  # # 0x1f0d000: 0x0000000000000000 0x0000000000002011
103
106
  # # 0x1f0d010: 0x00007f892a9f87b8 0x00007f892a9f87b8
104
107
  # # 0x1f0d020: 0x0000000000000000 0x0000000000000000
105
- # # 0x1f0d030: 0x0000000000000000 0x0000000000000000
108
+ # # 0x1f0d030: 0x0000000000000000 0x0000000000000000
106
109
  # @example
107
110
  # h.x 3, 0x400000
108
111
  # # 0x400000: 0x00010102464c457f 0x0000000000000000
109
112
  # # 0x400010: 0x00000001003e0002
110
113
  def x(count, *commands, io: $stdout)
111
- return unless load? and io.respond_to? :puts
114
+ return unless load? && io.respond_to?(:puts)
112
115
  dumper.x(count, *commands, io: io)
113
116
  end
114
117
 
115
118
  # Gdb-like command.
116
119
  #
117
120
  # Search a specific value/string/regexp in memory.
118
- # @param [Integer, String, Regexp] pattern The desired search pattern, can be value(<tt>Integer</tt>), string, or regular expression.
119
- # @param [Integer, String, Symbol] from Start address for searching, can be segment(<tt>Symbol</tt>) or segments with offset. See examples for more information.
120
- # @param [Integer] length The search length limit, default is unlimited, which will search until pattern found or reach unreadable memory.
121
+ # @param [Integer, String, Regexp] pattern
122
+ # The desired search pattern, can be value(<tt>Integer</tt>), string, or regular expression.
123
+ # @param [Integer, String, Symbol] from
124
+ # Start address for searching, can be segment(<tt>Symbol</tt>) or segments with offset.
125
+ # See examples for more information.
126
+ # @param [Integer] length
127
+ # The search length limit, default is unlimited,
128
+ # which will search until pattern found or reach unreadable memory.
121
129
  # @return [Integer, NilClass] The first matched address, <tt>nil</tt> is returned when no such pattern found.
122
130
  # @example
123
131
  # h.find(0xdeadbeef, 'heap+0x10', 0x1000)
@@ -134,8 +142,8 @@ module HeapInfo
134
142
  dumper.find(pattern, from, length)
135
143
  end
136
144
 
137
- # <tt>search</tt> is more intutive to me
138
- alias :search :find
145
+ # +search+ is more intutive to me
146
+ alias search find
139
147
 
140
148
  # Pretty dump of bins layouts.
141
149
  #
@@ -146,8 +154,8 @@ module HeapInfo
146
154
  # @example
147
155
  # h.layouts :fastbin, :unsorted_bin, :smallbin
148
156
  def layouts(*args, io: $stdout)
149
- return unless load? and io.respond_to? :puts
150
- io.puts self.libc.main_arena.layouts(*args)
157
+ return unless load? && io.respond_to?(:puts)
158
+ io.puts libc.main_arena.layouts(*args)
151
159
  end
152
160
 
153
161
  # Show simple information of target process.
@@ -157,16 +165,17 @@ module HeapInfo
157
165
  # @example
158
166
  # puts h
159
167
  def to_s
160
- return "Process not found" unless load?
168
+ return 'Process not found' unless load?
161
169
  "Program: #{Helper.color program.name} PID: #{Helper.color pid}\n" +
162
- program.to_s +
163
- heap.to_s +
164
- stack.to_s +
165
- libc.to_s +
166
- ld.to_s
170
+ program.to_s +
171
+ heap.to_s +
172
+ stack.to_s +
173
+ libc.to_s +
174
+ ld.to_s
167
175
  end
168
176
 
169
- private
177
+ private
178
+
170
179
  attr_accessor :dumper
171
180
  def load?
172
181
  @pid != nil
@@ -192,7 +201,7 @@ module HeapInfo
192
201
 
193
202
  def clear_process
194
203
  ProcessInfo::EXPORT.each do |m|
195
- self.class.send(:define_method, m) {Nil.new}
204
+ self.class.send(:define_method, m) { Nil.new }
196
205
  end
197
206
  false
198
207
  end
@@ -200,7 +209,7 @@ module HeapInfo
200
209
  def load_info! # :nodoc:
201
210
  @info = ProcessInfo.new(self)
202
211
  ProcessInfo::EXPORT.each do |m|
203
- self.class.send(:define_method, m) {@info.send(m)}
212
+ self.class.send(:define_method, m) { @info.send(m) }
204
213
  end
205
214
  @dumper = Dumper.new(@info, mem_filename)
206
215
  end
@@ -1,13 +1,13 @@
1
- #encoding: ascii-8bit
1
+ # encoding: ascii-8bit
2
2
  module HeapInfo
3
- # for <tt>Process</tt> to record current info(s)
4
- # <tt>Process</tt> has a <tt>process_info</tt> object iff the process found (pid not <tt>nil</tt>).
3
+ # for {Process} to record current info(s)
4
+ # {Process} has a +process_info+ object iff the process found (pid not +nil+).
5
5
  # Mainly records segments' base.
6
6
  class ProcessInfo
7
- # Methods to be transparent to <tt>process</tt>.
8
- # e.g. <tt>process.libc alias to process.info.libc</tt>
9
- EXPORT = %i(libc ld heap elf program stack bits)
10
-
7
+ # Methods to be transparent to +process+.
8
+ # e.g. +process.libc+ alias to +process.info.libc+.
9
+ EXPORT = %i(libc ld heap elf program stack bits).freeze
10
+
11
11
  # @return [Integer] 32 or 64.
12
12
  attr_reader :bits
13
13
  # @return [HeapInfo::Segment]
@@ -18,11 +18,11 @@ module HeapInfo
18
18
  attr_reader :libc
19
19
  # @return [HeapInfo::Segment]
20
20
  attr_reader :ld
21
- alias :elf :program
21
+ alias elf program
22
22
 
23
- # Instantiate a <tt>ProcessInfo</tt> object
23
+ # Instantiate a {ProcessInfo} object
24
24
  #
25
- # @param [HeapInfo::Process] process Load information from maps/memory for <tt>process</tt>
25
+ # @param [HeapInfo::Process] process Load information from maps/memory for +process+.
26
26
  def initialize(process)
27
27
  @pid = process.pid
28
28
  options = process.instance_variable_get(:@options)
@@ -33,18 +33,19 @@ module HeapInfo
33
33
  # well.. stack is a strange case because it will grow in runtime..
34
34
  # should i detect stack base growing..?
35
35
  @ld = Segment.find(maps, match_maps(maps, options[:ld]))
36
- @libc = Libc.find(maps, match_maps(maps, options[:libc]), @bits, @ld.name, ->(*args){ process.dump(*args) })
36
+ @libc = Libc.find(maps, match_maps(maps, options[:libc]), @bits, @ld.name, ->(*args) { process.dump(*args) })
37
37
  end
38
38
 
39
39
  # Heap will not be mmapped if the process not use heap yet, so create a lazy loading method.
40
40
  # Will re-read maps when heap segment not found yet.
41
41
  #
42
- # @return [HeapInfo::Segment] The <tt>Segment</tt> of heap
42
+ # @return [HeapInfo::Segment] The {Segment} of heap
43
43
  def heap # special handle because heap might not be initialized in the beginning
44
44
  @heap ||= Segment.find(maps!, '[heap]')
45
45
  end
46
46
 
47
- private
47
+ private
48
+
48
49
  attr_reader :maps
49
50
 
50
51
  # force reload maps
@@ -57,7 +58,7 @@ module HeapInfo
57
58
  end
58
59
 
59
60
  def match_maps(maps, pattern)
60
- maps.map{|s| s[3]}.find{|seg| pattern.is_a?(Regexp) ? seg =~ pattern : seg.include?(pattern)}
61
+ maps.map { |s| s[3] }.find { |seg| pattern.is_a?(Regexp) ? seg =~ pattern : seg.include?(pattern) }
61
62
  end
62
63
  end
63
64
  end
@@ -1,7 +1,6 @@
1
1
  module HeapInfo
2
2
  # Record the base address and name in maps
3
3
  class Segment
4
-
5
4
  # Base address of segment
6
5
  attr_reader :base
7
6
  # Name of segment
@@ -17,20 +16,22 @@ module HeapInfo
17
16
  # Hook <tt>#to_s</tt> for pretty printing
18
17
  # @return [String] Information of name and base address wrapper with color codes.
19
18
  def to_s
20
- "%-28s\tbase @ #{Helper.color("%#x" % base)}\n" % Helper.color(name.split('/')[-1])
19
+ format("%-28s\tbase @ #{Helper.color(format('%#x', base))}\n", Helper.color(name.split('/')[-1]))
21
20
  end
22
21
 
23
- # Helper for create an <tt>Segment</tt>
22
+ # Helper for create a {HeapInfo::Segment}.
24
23
  #
25
- # Search the specific <tt>pattern</tt> in <tt>maps</tt> and return a <tt>HeapInfo::Segment</tt> object.
24
+ # Search the specific <tt>pattern</tt> in <tt>maps</tt> and return a {HeapInfo::Segment} object.
26
25
  #
27
- # @param [Array] maps <tt>maps</tt> is in the form of the return value of <tt>HeapInfo::Helper.parse_maps</tt>
28
- # @param [Regexp, String] pattern The segment name want to match in maps. If <tt>String</tt> is given, the pattern is matched as a substring.
29
- # @return [HeapInfo::Segment, NilClass] The request <tt>Segment</tt> object. If the pattern is not matched, <tt>nil</tt> will be returned.
26
+ # @param [Array] maps <tt>maps</tt> is in the form of the return value of <tt>HeapInfo::Helper.parse_maps</tt>.
27
+ # @param [Regexp, String] pattern
28
+ # The segment name want to match in maps. If +String+ is given, the pattern is matched as a substring.
29
+ # @return [HeapInfo::Segment, NilClass]
30
+ # The request {HeapInfo::Segment} object. If the pattern is not matched, <tt>nil</tt> will be returned.
30
31
  def self.find(maps, pattern)
31
32
  return Nil.new if pattern.nil?
32
- needs = maps.select{|m| pattern.is_a?(Regexp) ? m[3] =~ pattern : m[3].include?(pattern)}
33
- self.new needs.map{|m| m[0]}.min, needs[0][3] unless needs.empty?
33
+ needs = maps.select { |m| pattern.is_a?(Regexp) ? m[3] =~ pattern : m[3].include?(pattern) }
34
+ new(needs.map(&:first).min, needs[0][3]) unless needs.empty?
34
35
  end
35
36
  end
36
37
  end
@@ -21,7 +21,6 @@ int main() {
21
21
  void *z = malloc(SZ); // prevent p merge with top chunk
22
22
  *p = z; // prevent compiler optimize
23
23
  free(p); // now *p must be the pointer of the (chunk_ptr) unsorted bin
24
- //TODO: check if this offset change in different version glibc
25
24
  z = (void*)((*p) - (4 + 4 + SZ * 10 )); // mutex+flags+fastbin[]
26
25
  void* a = search_head((size_t)__builtin_return_address(0));
27
26
  printf("%p\n", z-a);
@@ -1,3 +1,3 @@
1
1
  module HeapInfo
2
- VERSION = '0.0.5'.freeze
2
+ VERSION = '0.1.0'.freeze
3
3
  end
metadata CHANGED
@@ -1,15 +1,85 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: heapinfo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - david942j
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-01-03 00:00:00.000000000 Z
12
- dependencies: []
11
+ date: 2017-02-14 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '3.5'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '3.5'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rubocop
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.46'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.46'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '12.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '12.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: simplecov
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 0.13.0
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 0.13.0
69
+ - !ruby/object:Gem::Dependency
70
+ name: codeclimate-test-reporter
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0.6'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0.6'
13
83
  description: create an interactive memory info interface while pwn / exploiting
14
84
  email:
15
85
  - david942j@gmail.com
@@ -37,19 +107,6 @@ files:
37
107
  - lib/heapinfo/segment.rb
38
108
  - lib/heapinfo/tools/get_arena.c
39
109
  - lib/heapinfo/version.rb
40
- - spec/cache_spec.rb
41
- - spec/chunk_spec.rb
42
- - spec/chunks_spec.rb
43
- - spec/dumper_spec.rb
44
- - spec/files/32bit_maps
45
- - spec/files/64bit_maps
46
- - spec/files/victim.cpp
47
- - spec/helper_spec.rb
48
- - spec/libc_spec.rb
49
- - spec/nil_spec.rb
50
- - spec/process_spec.rb
51
- - spec/spec_helper.rb
52
- - spec/string_spec.rb
53
110
  homepage: https://github.com/david942j/heapinfo
54
111
  licenses:
55
112
  - MIT
@@ -70,21 +127,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
70
127
  version: '0'
71
128
  requirements: []
72
129
  rubyforge_project:
73
- rubygems_version: 2.5.2
130
+ rubygems_version: 2.6.10
74
131
  signing_key:
75
132
  specification_version: 4
76
133
  summary: HeapInfo - interactive heap exploitation helper
77
- test_files:
78
- - spec/files/32bit_maps
79
- - spec/files/victim.cpp
80
- - spec/files/64bit_maps
81
- - spec/cache_spec.rb
82
- - spec/dumper_spec.rb
83
- - spec/process_spec.rb
84
- - spec/chunk_spec.rb
85
- - spec/chunks_spec.rb
86
- - spec/string_spec.rb
87
- - spec/spec_helper.rb
88
- - spec/helper_spec.rb
89
- - spec/nil_spec.rb
90
- - spec/libc_spec.rb
134
+ test_files: []