ruzzy 0.6.0 → 0.8.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.
- checksums.yaml +4 -4
- data/ext/cruzzy/cruzzy.c +6 -6
- data/ext/cruzzy/extconf.rb +23 -11
- data/ext/dummy/dummy.c +11 -10
- data/lib/ruzzy/fuzzed_data_provider.rb +221 -0
- data/lib/ruzzy.rb +27 -6
- metadata +5 -8
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7d564227ec95d197cadc085f2190a7089fbe5610d4e6f7c9d9ff5a84a4243208
|
|
4
|
+
data.tar.gz: aa7c37d65b75d202e650832ffad9589c3a6a750d162760d0af934256268115aa
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 54cc91f765a3622756e3925f62e29003ef3169a8a413af4b450b320bdea979125ede2a203be2b2fac52114abf52b3b735f8d97e395f9181eb01f080b09648988
|
|
7
|
+
data.tar.gz: cc8895f40905092d68bbdad2557fd691c189b04f336bb360c0f0a1b3f82a52d0227f82e966248b2b70cfd694b35e464ecd967a76d0e0426e45f5ffa2e941444f
|
data/ext/cruzzy/cruzzy.c
CHANGED
|
@@ -194,11 +194,11 @@ static void event_hook_branch(VALUE counter_hash, rb_trace_arg_t *tracearg) {
|
|
|
194
194
|
|
|
195
195
|
static void enable_branch_coverage_hooks()
|
|
196
196
|
{
|
|
197
|
-
// Call Coverage.
|
|
197
|
+
// Call Coverage.start(branches: true) to activate branch coverage hooks.
|
|
198
198
|
// Branch coverage hooks will not be activated without this call despite
|
|
199
199
|
// adding the event hooks. I suspect rb_set_coverages must be called
|
|
200
200
|
// first, which initializes some global state that we do not have direct
|
|
201
|
-
// access to. Calling
|
|
201
|
+
// access to. Calling start initializes coverage state here:
|
|
202
202
|
// https://github.com/ruby/ruby/blob/v3_3_0/ext/coverage/coverage.c#L112-L120
|
|
203
203
|
// If rb_set_coverages is not called, then rb_get_coverages returns a NULL
|
|
204
204
|
// pointer, which appears to effectively disable coverage collection here:
|
|
@@ -207,10 +207,10 @@ static void enable_branch_coverage_hooks()
|
|
|
207
207
|
VALUE coverage_mod = rb_const_get(rb_cObject, rb_intern("Coverage"));
|
|
208
208
|
VALUE hash_arg = rb_hash_new();
|
|
209
209
|
rb_hash_aset(hash_arg, ID2SYM(rb_intern("branches")), Qtrue);
|
|
210
|
-
rb_funcall(coverage_mod, rb_intern("
|
|
210
|
+
rb_funcall(coverage_mod, rb_intern("start"), 1, hash_arg);
|
|
211
211
|
}
|
|
212
212
|
|
|
213
|
-
static VALUE
|
|
213
|
+
static VALUE c_trace(VALUE self, VALUE harness_path)
|
|
214
214
|
{
|
|
215
215
|
VALUE counter_hash = rb_hash_new();
|
|
216
216
|
|
|
@@ -230,7 +230,7 @@ static VALUE c_trace_branch(VALUE self)
|
|
|
230
230
|
|
|
231
231
|
enable_branch_coverage_hooks();
|
|
232
232
|
|
|
233
|
-
return
|
|
233
|
+
return rb_require(StringValueCStr(harness_path));
|
|
234
234
|
}
|
|
235
235
|
|
|
236
236
|
void Init_cruzzy()
|
|
@@ -245,5 +245,5 @@ void Init_cruzzy()
|
|
|
245
245
|
rb_define_module_function(ruzzy, "c_libfuzzer_is_loaded", &c_libfuzzer_is_loaded, 0);
|
|
246
246
|
rb_define_module_function(ruzzy, "c_trace_cmp8", &c_trace_cmp8, 2);
|
|
247
247
|
rb_define_module_function(ruzzy, "c_trace_div8", &c_trace_div8, 1);
|
|
248
|
-
rb_define_module_function(ruzzy, "
|
|
248
|
+
rb_define_module_function(ruzzy, "c_trace", &c_trace, 1);
|
|
249
249
|
}
|
data/ext/cruzzy/extconf.rb
CHANGED
|
@@ -19,6 +19,7 @@ LOGGER.level = ENV.key?('RUZZY_DEBUG') ? Logger::DEBUG : Logger::INFO
|
|
|
19
19
|
CC = ENV.fetch('CC', 'clang')
|
|
20
20
|
CXX = ENV.fetch('CXX', 'clang++')
|
|
21
21
|
AR = ENV.fetch('AR', 'ar')
|
|
22
|
+
LD = ENV.fetch('LD', 'ld')
|
|
22
23
|
FUZZER_NO_MAIN_LIB_ENV = 'FUZZER_NO_MAIN_LIB'
|
|
23
24
|
|
|
24
25
|
LOGGER.debug("Ruby CC: #{RbConfig::CONFIG['CC']}")
|
|
@@ -64,7 +65,9 @@ def merge_sanitizer_libfuzzer_lib(sanitizer_lib, fuzzer_no_main_lib, merged_outp
|
|
|
64
65
|
'-Wl,--no-whole-archive',
|
|
65
66
|
'-lpthread',
|
|
66
67
|
'-ldl',
|
|
68
|
+
'-lstdc++',
|
|
67
69
|
'-shared',
|
|
70
|
+
"-fuse-ld=#{LD}",
|
|
68
71
|
'-o',
|
|
69
72
|
merged_output
|
|
70
73
|
)
|
|
@@ -75,18 +78,24 @@ def merge_sanitizer_libfuzzer_lib(sanitizer_lib, fuzzer_no_main_lib, merged_outp
|
|
|
75
78
|
end
|
|
76
79
|
end
|
|
77
80
|
|
|
78
|
-
|
|
79
|
-
'libclang_rt.fuzzer_no_main.a',
|
|
80
|
-
'libclang_rt.fuzzer_no_main-aarch64.a',
|
|
81
|
-
'libclang_rt.fuzzer_no_main-x86_64.a'
|
|
82
|
-
]
|
|
83
|
-
fuzzer_no_main_lib = fuzzer_no_main_libs.map { |lib| get_clang_file_name(lib) }.find(&:itself)
|
|
81
|
+
fuzzer_no_main_lib = ENV.fetch(FUZZER_NO_MAIN_LIB_ENV, nil)
|
|
84
82
|
|
|
85
|
-
|
|
86
|
-
LOGGER.
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
83
|
+
if fuzzer_no_main_lib
|
|
84
|
+
LOGGER.info("Using #{FUZZER_NO_MAIN_LIB_ENV}=#{fuzzer_no_main_lib}")
|
|
85
|
+
unless File.exist?(fuzzer_no_main_lib)
|
|
86
|
+
LOGGER.error("#{FUZZER_NO_MAIN_LIB_ENV} file does not exist: #{fuzzer_no_main_lib}")
|
|
87
|
+
exit(1)
|
|
88
|
+
end
|
|
89
|
+
else
|
|
90
|
+
fuzzer_no_main_libs = [
|
|
91
|
+
'libclang_rt.fuzzer_no_main.a',
|
|
92
|
+
'libclang_rt.fuzzer_no_main-aarch64.a',
|
|
93
|
+
'libclang_rt.fuzzer_no_main-x86_64.a'
|
|
94
|
+
]
|
|
95
|
+
fuzzer_no_main_lib = fuzzer_no_main_libs.map { |lib| get_clang_file_name(lib) }.find(&:itself)
|
|
96
|
+
|
|
97
|
+
unless fuzzer_no_main_lib
|
|
98
|
+
LOGGER.error("Could not find fuzzer_no_main using #{CC}.")
|
|
90
99
|
LOGGER.error("Please include #{CC} in your path or specify #{FUZZER_NO_MAIN_LIB_ENV} ENV variable.")
|
|
91
100
|
exit(1)
|
|
92
101
|
end
|
|
@@ -137,4 +146,7 @@ merge_sanitizer_libfuzzer_lib(
|
|
|
137
146
|
# For more information, see https://github.com/ruby/ruby/blob/master/lib/mkmf.rb.
|
|
138
147
|
$LOCAL_LIBS = fuzzer_no_main_lib
|
|
139
148
|
|
|
149
|
+
$LIBS << ' -lstdc++'
|
|
150
|
+
$DLDFLAGS << " -fuse-ld=#{LD}"
|
|
151
|
+
|
|
140
152
|
create_makefile('cruzzy/cruzzy')
|
data/ext/dummy/dummy.c
CHANGED
|
@@ -6,17 +6,18 @@
|
|
|
6
6
|
// https://llvm.org/docs/LibFuzzer.html#toy-example
|
|
7
7
|
static int _c_dummy_test_one_input(const uint8_t *data, size_t size)
|
|
8
8
|
{
|
|
9
|
-
char
|
|
9
|
+
volatile char boom = 'x';
|
|
10
10
|
|
|
11
|
-
if (size
|
|
12
|
-
if (
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
11
|
+
if (size == 2) {
|
|
12
|
+
if (data[0] == 'H') {
|
|
13
|
+
if (data[1] == 'I') {
|
|
14
|
+
// Intentional heap-use-after-free for testing purposes
|
|
15
|
+
char * volatile ptr = malloc(128);
|
|
16
|
+
ptr[0] = 'x';
|
|
17
|
+
free(ptr);
|
|
18
|
+
boom = ptr[0];
|
|
19
|
+
(void) boom;
|
|
20
|
+
}
|
|
20
21
|
}
|
|
21
22
|
}
|
|
22
23
|
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ruzzy
|
|
4
|
+
# Splits raw fuzzer bytes into typed Ruby values.
|
|
5
|
+
#
|
|
6
|
+
# FuzzedDataProvider wraps a binary string (typically from libFuzzer via
|
|
7
|
+
# Ruzzy.fuzz) and provides methods to consume typed values from it. This
|
|
8
|
+
# enables fuzz targets that test APIs accepting typed arguments rather than
|
|
9
|
+
# raw byte strings.
|
|
10
|
+
#
|
|
11
|
+
# Following libFuzzer's FuzzedDataProvider.h design, strings and raw bytes
|
|
12
|
+
# are consumed from the *front* of the buffer, while integers are consumed
|
|
13
|
+
# from the *end*. This bidirectional consumption lets the fuzzer modify
|
|
14
|
+
# structural decisions (integers controlling lengths, indices, variant
|
|
15
|
+
# selection) independently from content (string payloads, raw bytes),
|
|
16
|
+
# improving mutation quality.
|
|
17
|
+
#
|
|
18
|
+
# @example Basic usage in a fuzz target
|
|
19
|
+
# test_one_input = lambda do |data|
|
|
20
|
+
# fdp = Ruzzy::FuzzedDataProvider.new(data)
|
|
21
|
+
# name = fdp.consume_random_length_string(50)
|
|
22
|
+
# age = fdp.consume_int_in_range(0, 150)
|
|
23
|
+
# score = fdp.consume_float_in_range(0.0, 100.0)
|
|
24
|
+
# role = fdp.pick_value_in_list(['admin', 'user', 'guest'])
|
|
25
|
+
# User.new(name: name, age: age, score: score, role: role).validate!
|
|
26
|
+
# end
|
|
27
|
+
# Ruzzy.fuzz(test_one_input)
|
|
28
|
+
class FuzzedDataProvider
|
|
29
|
+
def initialize(data)
|
|
30
|
+
@data = data
|
|
31
|
+
# Front cursor for strings/bytes (advances forward)
|
|
32
|
+
@front = 0
|
|
33
|
+
# Back cursor for integers (advances backward)
|
|
34
|
+
@back = @data.bytesize
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Returns the number of unconsumed bytes remaining.
|
|
38
|
+
def remaining_bytes
|
|
39
|
+
@back - @front
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# --- Byte and String methods (consume from front) ---
|
|
43
|
+
|
|
44
|
+
# Consume up to +count+ raw bytes from the front of the buffer.
|
|
45
|
+
# Returns a binary-encoded String.
|
|
46
|
+
def consume_bytes(count)
|
|
47
|
+
count = clamp_count(count)
|
|
48
|
+
result = @data.byteslice(@front, count)
|
|
49
|
+
@front += count
|
|
50
|
+
result.force_encoding(Encoding::BINARY)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Consume a variable-length string from the front of the buffer.
|
|
54
|
+
# The string terminates when a backslash followed by a non-backslash
|
|
55
|
+
# byte is encountered, or when +max_length+ characters are consumed.
|
|
56
|
+
# This encoding lets the fuzzer easily control string length through
|
|
57
|
+
# single-byte mutations.
|
|
58
|
+
#
|
|
59
|
+
# Matches libFuzzer's ConsumeRandomLengthString.
|
|
60
|
+
def consume_random_length_string(max_length = remaining_bytes)
|
|
61
|
+
result = +''
|
|
62
|
+
max_length.times do
|
|
63
|
+
break if remaining_bytes.zero?
|
|
64
|
+
|
|
65
|
+
byte = consume_front_byte
|
|
66
|
+
char = byte.chr(Encoding::BINARY)
|
|
67
|
+
|
|
68
|
+
if char == '\\' && remaining_bytes.positive?
|
|
69
|
+
next_byte = consume_front_byte
|
|
70
|
+
next_char = next_byte.chr(Encoding::BINARY)
|
|
71
|
+
break if next_char != '\\'
|
|
72
|
+
|
|
73
|
+
result << '\\'
|
|
74
|
+
else
|
|
75
|
+
result << char
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
result
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Consume all remaining bytes. Returns a binary-encoded String.
|
|
82
|
+
def consume_remaining_bytes
|
|
83
|
+
consume_bytes(remaining_bytes)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Consume all remaining bytes as a String.
|
|
87
|
+
def consume_remaining_as_string
|
|
88
|
+
consume_remaining_bytes
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# --- Integer methods (consume from end) ---
|
|
92
|
+
|
|
93
|
+
# Consume an unsigned integer from the end of the buffer.
|
|
94
|
+
# Reads up to +count+ bytes in little-endian order from the back.
|
|
95
|
+
# Returns 0 when no data remains.
|
|
96
|
+
def consume_uint(count)
|
|
97
|
+
return 0 if count <= 0 || remaining_bytes.zero?
|
|
98
|
+
|
|
99
|
+
actual = [count, remaining_bytes].min
|
|
100
|
+
result = 0
|
|
101
|
+
actual.times do |i|
|
|
102
|
+
@back -= 1
|
|
103
|
+
result |= @data.getbyte(@back) << (i * 8)
|
|
104
|
+
end
|
|
105
|
+
result
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# Consume a signed integer from the end of the buffer.
|
|
109
|
+
# Reads +count+ bytes and interprets as two's complement.
|
|
110
|
+
# Returns 0 when no data remains.
|
|
111
|
+
def consume_int(count)
|
|
112
|
+
unsigned = consume_uint(count)
|
|
113
|
+
return 0 if count.zero?
|
|
114
|
+
|
|
115
|
+
bits = count * 8
|
|
116
|
+
max_unsigned = 1 << bits
|
|
117
|
+
half = max_unsigned >> 1
|
|
118
|
+
|
|
119
|
+
unsigned >= half ? unsigned - max_unsigned : unsigned
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# Consume an integer in [min, max] from the end of the buffer.
|
|
123
|
+
# Returns +min+ when no data remains.
|
|
124
|
+
# Raises ArgumentError if min > max.
|
|
125
|
+
#
|
|
126
|
+
# Matches libFuzzer's ConsumeIntegralInRange: consumes only as many
|
|
127
|
+
# bytes from the end as needed to cover the range.
|
|
128
|
+
def consume_int_in_range(min, max)
|
|
129
|
+
raise ArgumentError, "min (#{min}) must be <= max (#{max})" if min > max
|
|
130
|
+
|
|
131
|
+
range = max - min
|
|
132
|
+
return min if range.zero?
|
|
133
|
+
|
|
134
|
+
# Consume bytes from the end, one at a time, until we've covered the range.
|
|
135
|
+
# This matches libFuzzer: only consume bytes while (range >> offset) > 0.
|
|
136
|
+
result = 0
|
|
137
|
+
offset = 0
|
|
138
|
+
while offset < 64 && (range >> offset).positive? && remaining_bytes.positive?
|
|
139
|
+
@back -= 1
|
|
140
|
+
result = (result << 8) | @data.getbyte(@back)
|
|
141
|
+
offset += 8
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
if range == (1 << offset) - 1
|
|
145
|
+
# range+1 is a power of 2, modulo is identity
|
|
146
|
+
min + result
|
|
147
|
+
else
|
|
148
|
+
min + (result % (range + 1))
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
# Consume a boolean from the end of the buffer.
|
|
153
|
+
# Returns false when no data remains.
|
|
154
|
+
def consume_bool
|
|
155
|
+
(consume_uint(1) & 1) == 1
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
# --- Float methods (consume from end) ---
|
|
159
|
+
|
|
160
|
+
# Consume a Float in [0.0, 1.0] from the end of the buffer.
|
|
161
|
+
# Returns 0.0 when no data remains.
|
|
162
|
+
def consume_probability
|
|
163
|
+
raw = consume_uint(8)
|
|
164
|
+
raw.to_f / 18_446_744_073_709_551_615.0 # 2^64 - 1
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
# Consume a Float in [min, max] from the end of the buffer.
|
|
168
|
+
# Returns +min+ when no data remains.
|
|
169
|
+
# Raises ArgumentError if min > max.
|
|
170
|
+
def consume_float_in_range(min, max)
|
|
171
|
+
raise ArgumentError, 'min must be <= max' if min > max
|
|
172
|
+
return min if min == max
|
|
173
|
+
|
|
174
|
+
range = max - min
|
|
175
|
+
if range.infinite?
|
|
176
|
+
# Overflow: split the range and recurse
|
|
177
|
+
mid = min / 2.0 + max / 2.0
|
|
178
|
+
if consume_bool
|
|
179
|
+
consume_float_in_range(mid, max)
|
|
180
|
+
else
|
|
181
|
+
consume_float_in_range(min, mid)
|
|
182
|
+
end
|
|
183
|
+
else
|
|
184
|
+
min + range * consume_probability
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
# Consume a Float spanning the full double range.
|
|
189
|
+
# Matches libFuzzer's ConsumeFloatingPoint.
|
|
190
|
+
def consume_float
|
|
191
|
+
consume_float_in_range(-Float::MAX, Float::MAX)
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
# --- Selection methods ---
|
|
195
|
+
|
|
196
|
+
# Return a random element from +list+, consuming bytes from the end.
|
|
197
|
+
# Raises ArgumentError if the list is empty.
|
|
198
|
+
def pick_value_in_list(list)
|
|
199
|
+
raise ArgumentError, 'list must not be empty' if list.empty?
|
|
200
|
+
|
|
201
|
+
list[consume_int_in_range(0, list.length - 1)]
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
private
|
|
205
|
+
|
|
206
|
+
# Consume a single byte from the front.
|
|
207
|
+
def consume_front_byte
|
|
208
|
+
return 0 if remaining_bytes.zero?
|
|
209
|
+
|
|
210
|
+
byte = @data.getbyte(@front)
|
|
211
|
+
@front += 1
|
|
212
|
+
byte
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
def clamp_count(count)
|
|
216
|
+
count = 0 if count.negative?
|
|
217
|
+
count = remaining_bytes if count > remaining_bytes
|
|
218
|
+
count
|
|
219
|
+
end
|
|
220
|
+
end
|
|
221
|
+
end
|
data/lib/ruzzy.rb
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require 'pathname'
|
|
4
|
+
require 'ruzzy/fuzzed_data_provider'
|
|
4
5
|
|
|
5
|
-
# A Ruby C
|
|
6
|
+
# A coverage-guided fuzzer for pure Ruby code and Ruby C extensions
|
|
6
7
|
module Ruzzy
|
|
7
8
|
require 'cruzzy/cruzzy'
|
|
8
9
|
|
|
@@ -15,10 +16,6 @@ module Ruzzy
|
|
|
15
16
|
c_fuzz(test_one_input, args)
|
|
16
17
|
end
|
|
17
18
|
|
|
18
|
-
def dummy
|
|
19
|
-
fuzz(->(data) { Ruzzy.dummy_test_one_input(data) })
|
|
20
|
-
end
|
|
21
|
-
|
|
22
19
|
def dummy_test_one_input(data)
|
|
23
20
|
# This 'require' depends on LD_PRELOAD, so it's placed inside the function
|
|
24
21
|
# scope. This allows us to access EXT_PATH for LD_PRELOAD and not have a
|
|
@@ -28,9 +25,33 @@ module Ruzzy
|
|
|
28
25
|
c_dummy_test_one_input(data)
|
|
29
26
|
end
|
|
30
27
|
|
|
28
|
+
def dummy
|
|
29
|
+
# Load the instrumented shared object before calling fuzz so its coverage
|
|
30
|
+
# maps are registered before LLVMFuzzerRunDriver starts. Some fuzzer
|
|
31
|
+
# runtimes (e.g. LibAFL) require coverage maps to exist upfront.
|
|
32
|
+
require 'dummy/dummy'
|
|
33
|
+
|
|
34
|
+
fuzz(->(data) { dummy_test_one_input(data) })
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def trace(harness_script)
|
|
38
|
+
harness_path = Pathname.new(harness_script)
|
|
39
|
+
|
|
40
|
+
# Mimic require_relative. If harness script is provided as an absolute path,
|
|
41
|
+
# then use that. If not, then assume the script is in the same directory as
|
|
42
|
+
# as the tracer script, i.e. the caller.
|
|
43
|
+
if !harness_path.absolute?
|
|
44
|
+
caller_path = Pathname.new(caller_locations.first.path)
|
|
45
|
+
harness_path = (caller_path.parent / harness_path).realpath
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
c_trace(harness_path.to_s)
|
|
49
|
+
end
|
|
50
|
+
|
|
31
51
|
module_function :fuzz
|
|
32
|
-
module_function :dummy
|
|
33
52
|
module_function :dummy_test_one_input
|
|
53
|
+
module_function :dummy
|
|
54
|
+
module_function :trace
|
|
34
55
|
end
|
|
35
56
|
|
|
36
57
|
# Hook Integer operations for tracing in SantizerCoverage
|
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ruzzy
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.8.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Trail of Bits
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: rake
|
|
@@ -66,7 +65,6 @@ dependencies:
|
|
|
66
65
|
- - "~>"
|
|
67
66
|
- !ruby/object:Gem::Version
|
|
68
67
|
version: '1.60'
|
|
69
|
-
description:
|
|
70
68
|
email: support@trailofbits.com
|
|
71
69
|
executables: []
|
|
72
70
|
extensions:
|
|
@@ -79,11 +77,11 @@ files:
|
|
|
79
77
|
- ext/dummy/dummy.c
|
|
80
78
|
- ext/dummy/extconf.rb
|
|
81
79
|
- lib/ruzzy.rb
|
|
80
|
+
- lib/ruzzy/fuzzed_data_provider.rb
|
|
82
81
|
homepage: https://rubygems.org/gems/ruzzy
|
|
83
82
|
licenses:
|
|
84
83
|
- AGPL-3.0-only
|
|
85
84
|
metadata: {}
|
|
86
|
-
post_install_message:
|
|
87
85
|
rdoc_options: []
|
|
88
86
|
require_paths:
|
|
89
87
|
- lib
|
|
@@ -98,8 +96,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
98
96
|
- !ruby/object:Gem::Version
|
|
99
97
|
version: '0'
|
|
100
98
|
requirements: []
|
|
101
|
-
rubygems_version:
|
|
102
|
-
signing_key:
|
|
99
|
+
rubygems_version: 4.0.6
|
|
103
100
|
specification_version: 4
|
|
104
|
-
summary: A Ruby C
|
|
101
|
+
summary: A coverage-guided fuzzer for pure Ruby code and Ruby C extensions
|
|
105
102
|
test_files: []
|