From 248c3a3c7b376e128c14fcb13eebf28733553d03 Mon Sep 17 00:00:00 2001 From: David Symonds Date: Fri, 18 Mar 2016 09:55:18 +1100 Subject: [PATCH] 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 Reviewed-by: Andrew Gerrand --- src/regexp/regexp.go | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/src/regexp/regexp.go b/src/regexp/regexp.go index e1da9ed421..92af6bb45b 100644 --- a/src/regexp/regexp.go +++ b/src/regexp/regexp.go @@ -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() -- 2.48.1