-
Notifications
You must be signed in to change notification settings - Fork 397
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Add Fuzzer and Fuzzer CLI #3769
base: master
Are you sure you want to change the base?
Conversation
🛠 PR Checks Summary🔴 Pending initial approval by a review team member, or review from tech-staff Manual Checks (for Reviewers):
Read More🤖 This bot helps streamline PR reviews by verifying automated checks and providing guidance for contributors and reviewers. ✅ Automated Checks (for Contributors):🟢 Maintainers must be able to edit this pull request (more info) ☑️ Contributor Actions:
☑️ Reviewer Actions:
📚 Resources:Debug
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've left some comments. Also, please translate all comments to English.
} | ||
|
||
default: | ||
panic("logical Error. Type not implemented") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems good to change the panic message. It looks better to simply output that the particular type hasn't been implemented yet.
panic("logical Error. Type not implemented") | |
panic(ufmt.Sprintf("Type (%d) not implemented", input.(type)) |
result, usedStrategyMap := MutateNotSbEnt2interface(ms.NotSbEntsDict[argIdx], strength) | ||
boolResult, ok := result.(bool) | ||
if !ok { | ||
panic("logical Error. If it occred, Needs to fix") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Modify this kind of panic messages as well to provide clear information to the user.
|
||
// parseKeyVals identifies key-delimiter-value structures in the token stream. | ||
// It detects and extracts key-value pairs, including optional whitespace | ||
// surrounding delimiters like ":", "=", and ":=". |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This type of situation where multi-tokens need to be parsed is efficiently handled by combining recursive descent with limited lookahead.
Note: You don't need to make apply this comment right now, but please keep this in mind as it would make future maintenance easier.
Hey @rlaau, thank you for your contribution. At the current time, we are in a feature freeze ahead of the mainnet beta launch. This is a large feature which will require extensive time to review and merge, so it will be deferred to after the mainnet launch. In the meantime, Joon's comment are a good start; but yes, keep in mind that review by the core team will be deferred |
|
||
var shift int8 | ||
if exponent <= 1 { | ||
shift = int8(1 + int(mantissa%2)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changing mantissa%2
to mantissa&1
allows for more efficient processing because it only checks the LSB (Least Significant Bit) instead of performing an actual division operation.
You can also apply this method in randomFloat64
too.
func randomFloat32(a float32) float32 { | ||
bits := math.Float32bits(a) | ||
|
||
exponent := (bits >> 23) & 0xFF |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can reduce unnecessary type conversions by setting exponent
to int32
type. In this case shift
should also be changed to int32
type.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be good to add a comment explaining that the pcg from stdlib couldn't be used due to an import cycle, which is why it was separately added to the testing package.
Co-authored-by: Lee ByeongJun <lbj199874@gmail.com>
Background
Go has a native fuzzer written in Go, but Gno does not yet have such a fuzzer.
I thought it would be useful to have a simple fuzzer that can be imported and used via the
testing
library within Gno files.Therefore, I have added fuzzing-related functionalities to
stdlibs/testing
andstdlibs/testing/fuzzing
.Users can now import this fuzzer from the
testing
library and use it just like Go’s native fuzzer, but as a Gno-native fuzzer.Goal
Changes
Fix: Updated
gnovm/cmd/gno/test.go
gnovm/pkg/test/test.go
gnovm/stdlibs/testing/testing.gno
Add:
gnovm/stdlibs/testing/fuzz.gno
– Manages the interface for the Gno fuzzer.Add:
gnovm/stdlibs/testing/fuzzing/fuzz_hasher.gno
– Assigns and manages IDs for test coverage usingFuzzHasher
.Add:
gnovm/stdlibs/testing/fuzzing/fuzz_logger.gno
– Manages error inputs and logs viaFuzzLogger
.Add:
gnovm/stdlibs/testing/fuzzing/fuzz_manager.gno
– Efficiently manages seed inputs and coverage (hash numbers) priorities viaFuzzManager
.Add:
gnovm/stdlibs/testing/fuzzing/get_coverage.gno
– Executes input values to collect coverage data.Add:
gnovm/stdlibs/testing/fuzzing/mutator.gno
– Manages the seed values to be mutated and generates the next input from those seeds.Add:
gnovm/stdlibs/testing/fuzzing/parser.gno
,gnovm/stdlibs/testing/fuzzing/parser_for_not_sb.gno
– Analyzes input arguments to help the mutator perform more effective transformations.Add:
gnovm/stdlibs/testing/fuzzing/random.gno
– Generates PCG random numbers for fuzzing.Algorithm
The user provides initial seeds via
f.Add
. All initial seeds are executed, and based on the results:f.manager
.f.mutator
stores the seeds along with analyzed execution results.When
f.Fuzz
receives the target program to test, the following loop begins:f.manager
selects the highest-priority coverage (the least executed one) and extracts a seed from its queue, passing it tof.mutator
.f.mutator
analyzes the seed and selects an appropriate mutation strategy to modify it.f.hasher
execute the mutated seed and classify the execution results (assigning a hash number to coverage).f.manager
coordinates the seed based on execution results.f.mutator
updates mutation strategies according to coverage and seed data.f.logger
reports the error.Usage
Currently, coverage measurement for arbitrary functions is not implemented. The following example demonstrates coverage measurement for a specific function where coverage tracking is possible.
The CLI command allows usage similar to Go’s fuzzer:
gno test [file name] -fuzz=[function prefix] -v -i=[iteration count]
Other functionalities follow the usage described in Go’s fuzz documentation.
However, there are a few differences:
Notes
-- Refining mutation strategies
-- Improving management logic
-- Optimizing priority selection
-- Enhancing sampling techniques
Future Enhancements
TODOs:
-- Additional input minimization
-- Refining mutation and strategy update methods
-- Pattern-based analysis
-- Implement full coverage tracking
Apply sampling techniques for seed selection (e.g., Thompson sampling)
Set an execution limit to stop exploration beyond a threshold and reset strategies
Improve transformation and priority determination using Sonar-like distance metrics
Extract execution logic separately and process it in parallel using multiprocessing, assigning each process its own GnoVM instance for testing