Skip to content

Commit 248c3a3

Browse files
committed
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 <[email protected]> Reviewed-by: Andrew Gerrand <[email protected]>
1 parent 815c9a7 commit 248c3a3

File tree

1 file changed

+22
-15
lines changed

1 file changed

+22
-15
lines changed

src/regexp/regexp.go

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,14 @@ var debug = false
8181
// A Regexp is safe for concurrent use by multiple goroutines.
8282
type Regexp struct {
8383
// read-only after Compile
84+
regexpRO
85+
86+
// cache of machines for running regexp
87+
mu sync.Mutex
88+
machine []*machine
89+
}
90+
91+
type regexpRO struct {
8492
expr string // as passed to Compile
8593
prog *syntax.Prog // compiled program
8694
onepass *onePassProg // onepass program or nil
@@ -93,10 +101,6 @@ type Regexp struct {
93101
numSubexp int
94102
subexpNames []string
95103
longest bool
96-
97-
// cache of machines for running regexp
98-
mu sync.Mutex
99-
machine []*machine
100104
}
101105

102106
// String returns the source text used to compile the regular expression.
@@ -109,10 +113,11 @@ func (re *Regexp) String() string {
109113
// When using a Regexp in multiple goroutines, giving each goroutine
110114
// its own copy helps to avoid lock contention.
111115
func (re *Regexp) Copy() *Regexp {
112-
r := *re
113-
r.mu = sync.Mutex{}
114-
r.machine = nil
115-
return &r
116+
// It is not safe to copy Regexp by value
117+
// since it contains a sync.Mutex.
118+
return &Regexp{
119+
regexpRO: re.regexpRO,
120+
}
116121
}
117122

118123
// Compile parses a regular expression and returns, if successful,
@@ -174,13 +179,15 @@ func compile(expr string, mode syntax.Flags, longest bool) (*Regexp, error) {
174179
return nil, err
175180
}
176181
regexp := &Regexp{
177-
expr: expr,
178-
prog: prog,
179-
onepass: compileOnePass(prog),
180-
numSubexp: maxCap,
181-
subexpNames: capNames,
182-
cond: prog.StartCond(),
183-
longest: longest,
182+
regexpRO: regexpRO{
183+
expr: expr,
184+
prog: prog,
185+
onepass: compileOnePass(prog),
186+
numSubexp: maxCap,
187+
subexpNames: capNames,
188+
cond: prog.StartCond(),
189+
longest: longest,
190+
},
184191
}
185192
if regexp.onepass == notOnePass {
186193
regexp.prefix, regexp.prefixComplete = prog.Prefix()

0 commit comments

Comments
 (0)