perf(sandbox): compile command-substitution regexps once

hasCommandSubstitution recompiled its three regexps with regexp.MustCompile
on every call, and ValidateArgs calls it once per argument — so validating
an N-arg command compiled 3N patterns. Hoist them to a package-level slice
compiled once at init.

Behavior is unchanged (same patterns); covered by the existing
TestScriptValidator_ValidateArgs / ValidateAll tests.

Benchmark, ValidateArgs with 8 args (-benchmem):
  before: 16374 ns/op, 40142 B/op, 505 allocs/op
  after:   2092 ns/op,    32 B/op,   1 allocs/op

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
adawang
2026-06-16 17:42:54 +08:00
committed by lyingbug
parent 1c735ebb9e
commit 8f4b3333f2
2 changed files with 19 additions and 7 deletions
+10 -7
View File
@@ -217,15 +217,18 @@ func (v *ScriptValidator) hasShellOperators(s string) bool {
return false
}
// Command-substitution patterns, compiled once. hasCommandSubstitution runs
// per argument in ValidateArgs, so recompiling these on every call wasted work
// proportional to the argument count.
var commandSubstitutionPatterns = []*regexp.Regexp{
regexp.MustCompile(`\$\([^)]+\)`), // $(command)
regexp.MustCompile("`[^`]+`"), // `command`
regexp.MustCompile(`\$\{[^}]*\$\(`), // ${...$(command)
}
// hasCommandSubstitution checks for command substitution patterns
func (v *ScriptValidator) hasCommandSubstitution(s string) bool {
patterns := []*regexp.Regexp{
regexp.MustCompile(`\$\([^)]+\)`), // $(command)
regexp.MustCompile("`[^`]+`"), // `command`
regexp.MustCompile(`\$\{[^}]*\$\(`), // ${...$(command)
}
for _, p := range patterns {
for _, p := range commandSubstitutionPatterns {
if p.MatchString(s) {
return true
}
+9
View File
@@ -359,3 +359,12 @@ func containsHelper(s, substr string) bool {
}
return false
}
func BenchmarkValidateArgs(b *testing.B) {
v := NewScriptValidator()
args := []string{"--input", "file.txt", "--name", "report 2024", "--out", "/tmp/x", "--verbose", "--limit=50"}
b.ReportAllocs()
for i := 0; i < b.N; i++ {
_ = v.ValidateArgs(args)
}
}