go-pcre icon indicating copy to clipboard operation
go-pcre copied to clipboard

CompileJIT is not threadsafe

Open d4l3k opened this issue 8 years ago • 2 comments

pcrejit requires a separate thread specific stack. This leads to some very weird issues when using this library with multiple threads. I naively called CompileJIT in one part of the program and then used it in other parts without realizing that per thread stacks were required. This isn't featured in the documentation, nor is there a way to handle it in the current Go API.

http://www.pcre.org/original/doc/html/pcrejit.html#SEC9

http://www.pcre.org/original/doc/html/pcreapi.html#SEC8

https://stackoverflow.com/questions/28738674/is-the-pcre-library-thread-safe-if-not-which-do-you-recommend

package main

import (
	"log"

	pcre "github.com/gijsbers/go-pcre"
)

func findIndex(a pcre.Regexp) {
	for {
		// Compile a new function with JIT. Since this is running in a goroutine and
		// probably a different thread the JIT stack will be violated.
		b := pcre.MustCompileJIT("[^\\/><\\s]+", 0, 0)
		if b.FindIndex([]byte(" <p>"), 0) == nil {
			log.Fatal("b.FindIndex(...) should never equal nil")
		}

		if a.FindIndex([]byte(" <p>"), 0) == nil {
			log.Fatal("a.FindIndex(...) should never equal nil")
		}
	}
}

func main() {
	a := pcre.MustCompileJIT("[^\\/><\\s]+", 0, 0)
	for i := 0; i < 4; i++ {
		go findIndex(a)
	}
	findIndex(a)
}

d4l3k avatar Dec 14 '16 22:12 d4l3k

FYI in the above example it fails with "a.FindIndex(...) should never equal nil"

d4l3k avatar Dec 14 '16 23:12 d4l3k

Very well researched!

Likely using pcre JIT in go requires the use of LockOSThread, such that it is guaranteed that findIndex is executing on the same OS thread as MustCompileJIT.

gijsbers avatar Jan 02 '17 22:01 gijsbers