Skip to content

Commit

Permalink
add REPASSGEN_MAX_LENGTH to prevent out-of-memory during fuzz testing
Browse files Browse the repository at this point in the history
  • Loading branch information
ilius committed Jul 18, 2023
1 parent a219c9b commit 78c76e4
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 10 deletions.
7 changes: 6 additions & 1 deletion lib/fuzz_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package passgen_test

import (
"os"
"testing"
"time"

Expand All @@ -18,8 +19,12 @@ func FuzzGenerate(f *testing.F) {
for _, tc := range testcases {
f.Add(tc) // Use f.Add to provide a seed corpus
}
// define a max output length to prevent out-of-memory and crash
os.Setenv("REPASSGEN_MAX_LENGTH", "500")
f.Fuzz(func(t *testing.T, pattern string) {
// TODO: define a max output length to prevent out of memory and crash
if len(pattern) > 100 {
return
}
out, _, err := passgen.Generate(passgen.GenerateInput{
Pattern: []rune(pattern),
})
Expand Down
3 changes: 3 additions & 0 deletions lib/repeat.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ func (g *repeatGenerator) Generate(s *State) error {
count := g.count
for i := int64(0); i < count; i++ {
err := child.Generate(s)
if s.tooLong() {
break
}
if err != nil {
return err
}
Expand Down
34 changes: 25 additions & 9 deletions lib/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package passgen
import (
"fmt"
"log"
"os"
"strconv"
)

// SharedState is the shared part of State
Expand All @@ -13,6 +15,8 @@ type SharedState struct {
errorMarkLen int
patternEntropy float64
lastGroupId uint64

maxOutputLength int
}

// State is lex inputs, output and temp state
Expand Down Expand Up @@ -46,15 +50,11 @@ func (s *State) moveBack(chars uint64) {
s.absPos -= chars
}

// func (s *State) moveBackAbs(chars uint64) {
// if s.absPos < chars {
// log.Printf("moveBack(%v) with absPos=%v", chars, s.absPos)
// return
// }
// s.absPos -= chars
// }

func (s *State) addOutputOne(c rune) {
if s.tooLong() {
s.lastGen = nil
return
}
s.lastGen = &staticStringGenerator{str: []rune{c}}
s.lastGen.Generate(s)
}
Expand All @@ -69,7 +69,14 @@ func (s *State) addOutputNonRepeatable(data []rune) {
s.output = append(s.output, data...)
}

func (s *State) tooLong() bool {
return s.maxOutputLength > 0 && len(s.output) > s.maxOutputLength
}

func (s *State) end() bool {
if s.tooLong() {
return true
}
return s.inputPos >= uint64(len(s.input))
}

Expand Down Expand Up @@ -124,10 +131,19 @@ func (s *State) errorUnknown(msg string, args ...interface{}) error {

// NewSharedState is factory function for SharedState
func NewSharedState() *SharedState {
return &SharedState{
ss := &SharedState{
groupsOutput: map[uint64][]rune{},
errorMarkLen: 1,
}
maxLengthStr := os.Getenv("REPASSGEN_MAX_LENGTH")
if maxLengthStr != "" {
maxLength, err := strconv.ParseInt(maxLengthStr, 10, 64)
if err != nil {
panic("invalid REPASSGEN_MAX_LENGTH: must be an integer")
}
ss.maxOutputLength = int(maxLength)
}
return ss
}

// NewState is factory function for State
Expand Down

0 comments on commit 78c76e4

Please sign in to comment.