]> Cypherpunks repositories - gostls13.git/commitdiff
regexp: avoid copying mutex in (*Regexp).Copy.
authorDavid Symonds <dsymonds@golang.org>
Thu, 17 Mar 2016 22:55:18 +0000 (09:55 +1100)
committerDavid Symonds <dsymonds@golang.org>
Fri, 18 Mar 2016 03:56:28 +0000 (03:56 +0000)
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>
src/regexp/regexp.go

index e1da9ed421d69ac9edd90589dd8728d47b912466..92af6bb45bfb8d74c949b49d82d5437b40799c21 100644 (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()