regexp: avoid copying mutex in (*Regexp).Copy.

There's nothing guaranteeing that the *Regexp isn't in active use,
and so copying the sync.Mutex value is invalid.

Updates #14839.

Change-Id: Iddf52bf69df1b563377922399f64a571f76b95dd
Reviewed-on: https://go-review.googlesource.com/20841
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Reviewed-by: Andrew Gerrand <adg@golang.org>
This commit is contained in:
David Symonds 2016-03-18 09:55:18 +11:00
parent 815c9a7f28
commit 248c3a3c7b

View file

@ -81,6 +81,14 @@ var debug = false
// A Regexp is safe for concurrent use by multiple goroutines.
type Regexp struct {
// read-only after Compile
regexpRO
// cache of machines for running regexp
mu sync.Mutex
machine []*machine
}
type regexpRO struct {
expr string // as passed to Compile
prog *syntax.Prog // compiled program
onepass *onePassProg // onepass program or nil
@ -93,10 +101,6 @@ type Regexp struct {
numSubexp int
subexpNames []string
longest bool
// cache of machines for running regexp
mu sync.Mutex
machine []*machine
}
// String returns the source text used to compile the regular expression.
@ -109,10 +113,11 @@ func (re *Regexp) String() string {
// When using a Regexp in multiple goroutines, giving each goroutine
// its own copy helps to avoid lock contention.
func (re *Regexp) Copy() *Regexp {
r := *re
r.mu = sync.Mutex{}
r.machine = nil
return &r
// It is not safe to copy Regexp by value
// since it contains a sync.Mutex.
return &Regexp{
regexpRO: re.regexpRO,
}
}
// Compile parses a regular expression and returns, if successful,
@ -174,13 +179,15 @@ func compile(expr string, mode syntax.Flags, longest bool) (*Regexp, error) {
return nil, err
}
regexp := &Regexp{
expr: expr,
prog: prog,
onepass: compileOnePass(prog),
numSubexp: maxCap,
subexpNames: capNames,
cond: prog.StartCond(),
longest: longest,
regexpRO: regexpRO{
expr: expr,
prog: prog,
onepass: compileOnePass(prog),
numSubexp: maxCap,
subexpNames: capNames,
cond: prog.StartCond(),
longest: longest,
},
}
if regexp.onepass == notOnePass {
regexp.prefix, regexp.prefixComplete = prog.Prefix()