Skip to content

Commit

Permalink
pkg/ipc: refactor rate limiting
Browse files Browse the repository at this point in the history
1. Move the flag to Config (logically belongs there).
2. Create rate limter lazily (it's not needed most of the time).

This will help to stop passing *prog.Prog to Exec method.
  • Loading branch information
dvyukov committed Apr 15, 2024
1 parent 68d19d3 commit a2559a6
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 18 deletions.
40 changes: 23 additions & 17 deletions pkg/ipc/ipc.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"path/filepath"
"reflect"
"strings"
"sync"
"sync/atomic"
"time"
"unsafe"
Expand Down Expand Up @@ -68,6 +69,7 @@ type Config struct {

UseShmem bool // use shared memory instead of pipes for communication
UseForkServer bool // use extended protocol with handshake
RateLimit bool // rate limit start of new processes for host fuzzer mode

// Flags are configuation flags, defined above.
Flags EnvFlags
Expand Down Expand Up @@ -246,8 +248,6 @@ func (env *Env) Close() error {
}
}

var rateLimit = time.NewTicker(1 * time.Second)

// Exec starts executor binary to execute program p and returns information about the execution:
// output: process output
// info: per-call info
Expand All @@ -271,7 +271,7 @@ func (env *Env) Exec(opts *ExecOpts, p *prog.Prog) (output []byte, info *ProgInf
}

atomic.AddUint64(&env.StatExecs, 1)
err0 = env.RestartIfNeeded(p.Target)
err0 = env.RestartIfNeeded()
if err0 != nil {
return
}
Expand Down Expand Up @@ -306,23 +306,29 @@ func (env *Env) ForceRestart() {
}
}

// This smethod brings up an executor process if it was stopped.
func (env *Env) RestartIfNeeded(target *prog.Target) error {
if env.cmd == nil {
if target.OS != targets.TestOS && targets.Get(target.OS, target.Arch).HostFuzzer {
// The executor is actually ssh,
// starting them too frequently leads to timeouts.
<-rateLimit.C
}
tmpDirPath := "./"
atomic.AddUint64(&env.StatRestarts, 1)
var err error
env.cmd, err = makeCommand(env.pid, env.bin, env.config, env.inFile, env.outFile, env.out, tmpDirPath)
return err
// RestartIfNeeded brings up an executor process if it was stopped.
func (env *Env) RestartIfNeeded() error {
if env.cmd != nil {
return nil
}
return nil
if env.config.RateLimit {
rateLimiterOnce.Do(func() {
rateLimiter = time.NewTicker(1 * time.Second).C
})
<-rateLimiter
}
tmpDirPath := "./"
atomic.AddUint64(&env.StatRestarts, 1)
var err error
env.cmd, err = makeCommand(env.pid, env.bin, env.config, env.inFile, env.outFile, env.out, tmpDirPath)
return err
}

var (
rateLimiterOnce sync.Once
rateLimiter <-chan time.Time
)

// addFallbackSignal computes simple fallback signal in cases we don't have real coverage signal.
// We use syscall number or-ed with returned errno value as signal.
// At least this gives us all combinations of syscall+errno.
Expand Down
1 change: 1 addition & 0 deletions pkg/ipc/ipcconfig/ipcconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ func Default(target *prog.Target) (*ipc.Config, *ipc.ExecOpts, error) {
c.Flags |= sandboxFlags
c.UseShmem = sysTarget.ExecutorUsesShmem
c.UseForkServer = sysTarget.ExecutorUsesForkServer
c.RateLimit = sysTarget.HostFuzzer && target.OS != targets.TestOS
opts := &ipc.ExecOpts{
Flags: ipc.FlagDedupCover,
}
Expand Down
2 changes: 1 addition & 1 deletion syz-fuzzer/proc.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ func (proc *Proc) executeRaw(opts *ipc.ExecOpts, p *prog.Prog) *ipc.ProgInfo {
var hanged bool
// On a heavily loaded VM, syz-executor may take significant time to start.
// Let's do it outside of the gate ticket.
err := proc.env.RestartIfNeeded(p.Target)
err := proc.env.RestartIfNeeded()
if err == nil {
// Limit concurrency.
ticket := proc.tool.gate.Enter()
Expand Down

0 comments on commit a2559a6

Please sign in to comment.