Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Panic in the new exec cache code #214

Closed
mstoykov opened this issue Oct 13, 2020 · 7 comments
Closed

Panic in the new exec cache code #214

mstoykov opened this issue Oct 13, 2020 · 7 comments
Labels

Comments

@mstoykov
Copy link
Contributor

mstoykov commented Oct 13, 2020

I haven't been able to reproduce this and I did try some sketchy uses including

var r = /(.)(?!some)/g;
console.log(r[Symbol.search](null));
console.log(r[Symbol.search]("asdas"));
console.log(r[Symbol.split](null));
console.log(r[Symbol.split]("asdas"));

Also unfortunately the stacktrace isn't full, although what is in it is probably the helpful part given that it still wouldn't have provided us with the source code :( :

panic: runtime error: invalid memory address or nil pointer dereference [recovered]
	panic: runtime error: invalid memory address or nil pointer dereference [recovered]
	panic: runtime error: invalid memory address or nil pointer dereference [recovered]
	panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x30 pc=0x94dbbd]

goroutine 80 [running]:
github.com/dop251/goja.AssertFunction.func1.1(0xc0451fdab8)
	/home/alpine/go/src/github.com/loadimpact/k6/vendor/github.com/dop251/goja/runtime.go:1967 +0x98
panic(0xe36ec0, 0x1abf270)
	/usr/local/go/src/runtime/panic.go:969 +0x166
github.com/dop251/goja.(*vm).try.func1(0xc0046e0d20, 0x0, 0xc0451fd978, 0x0, 0x0, 0x0, 0xc0451fda00)
	/home/alpine/go/src/github.com/loadimpact/k6/vendor/github.com/dop251/goja/vm.go:407 +0x647
panic(0xe36ec0, 0x1abf270)
	/usr/local/go/src/runtime/panic.go:969 +0x166
github.com/dop251/goja.(*vm).try.func1(0xc0046e0d20, 0x4, 0xc0451fd5d8, 0x17, 0x0, 0x0, 0xc0451fd660)
	/home/alpine/go/src/github.com/loadimpact/k6/vendor/github.com/dop251/goja/vm.go:407 +0x647
panic(0xe36ec0, 0x1abf270)
	/usr/local/go/src/runtime/panic.go:969 +0x166
github.com/dop251/goja.(*regexp2Wrapper).findUTF16Cached(0xc001476990, 0x11d93c0, 0xc0420878c0, 0x0, 0xc042087801, 0x10, 0x8, 0xde6a80, 0xc042087880, 0x16, ...)
	/home/alpine/go/src/github.com/loadimpact/k6/vendor/github.com/dop251/goja/regexp.go:186 +0x31d
github.com/dop251/goja.(*regexp2Wrapper).findSubmatchIndexUTF16(0xc001476990, 0x11d93c0, 0xc0420878c0, 0x0, 0xc0420c7d01, 0xc0451fd1a8, 0x95741a, 0x1b06220)
	/home/alpine/go/src/github.com/loadimpact/k6/vendor/github.com/dop251/goja/regexp.go:210 +0x76
github.com/dop251/goja.(*regexp2Wrapper).findSubmatchIndex(0xc001476990, 0x11d93c0, 0xc0420878c0, 0x0, 0x100, 0x0, 0x11d5e40, 0x1b06220)
	/home/alpine/go/src/github.com/loadimpact/k6/vendor/github.com/dop251/go

This is with a8e472c and as far as I can see cache.target is nil but given how r.cache is set this is impossible ?
Maybe it is a corrupt address which seems ... just as unlikely 🤔

@dop251
Copy link
Owner

dop251 commented Oct 13, 2020

Hm... I can't see any way of cache.target being nil if cache is not nil. Even if the string was somehow nil (which is also impossible) it would blow up much earlier.

This looks like a data race to me (which could be the reason for the original panic you saw in #212 as well).

@dop251
Copy link
Owner

dop251 commented Dec 8, 2020

Were you able to get to the bottom of this?

@mstoykov
Copy link
Contributor Author

mstoykov commented Dec 9, 2020

Sorry, I haven't had any real leads until yesterday when ... I think I hit it, but I am not certain it is the same thing as I changed stuff ... and the current thing that looks wrong is that goja.Program somehow shares stuff... which seems unlikely to me.

My change was that instead of having a single goja.Runtime running babel for us, we will have a single goja.Program parsed by goja.Compile and then a separate goja.Runtime which runs the goja.Program for each instance that we need it (with a lot of asterisks all over the place obviously). Given that we do something similar in other places .... this seems completely unlikely to me and I guess it is something completely different, that this change just made more likely or something. Also, this only happens if the test (go test) actually ends prematurely ... so 🤷

Unfortunately, I have to prioritize another thing before I come back to look at it again, as after 1-2 hours of running test after test I was nowhere .. I am going to try again in January, and hopefully come back to you :D

@mstoykov
Copy link
Contributor Author

mstoykov commented Jan 6, 2021

I think I ... found it, although I have no idea why, except that it seems to be a much bigger problem.

The following code is racing (fairly consistently, but you might need to run it more than once).
Note: I got this in the k6 codebase and so I am getting the babel.min.js from there, but the current latest version(the commented code) also reproduced it.

Edit: simpler example in the next comment

func TestPanic(t *testing.T) {
        // r, _ := http.Get("https://unpkg.com/@babel/standalone/babel.min.js")
        r, _ := http.Get("https://raw.githubusercontent.com/loadimpact/k6/master/js/compiler/lib/babel.min.js")
        b, _ := ioutil.ReadAll(r.Body)

        s := MustCompile("babel.min.js", string(b), false)
        fmt.Println(len(b))

        for i := 0; i < 10; i++ {
                go func() {
                        vm := New()
                        for i := 0; i < 10; i++ {
                                _, err := vm.RunProgram(s)
                                if err != nil {
                                        panic(err)
                                }
                        }
                }()
        }
}

Bisecting goja ... obviously leads to b2a8925 but IMO this is just what made it noticeable, and the bug is actually that goja.Program isn't safe for concurrent goja.RunProgram usage. Which IMO makes it way outside my ability to dig deeper :(.

You might need to follow golang/go#10661 (comment) to get the full stacks, btw.

The actual race on my machine( but I have seen smaller and they change so it is not the same code always):

==================
WARNING: DATA RACE
Read at 0x00c001de5148 by goroutine 31:
  github.com/dop251/goja.(*regexp2Wrapper).findUTF16Cached()
      github.com/dop251/goja/regexp.go:185 +0x7c
  github.com/dop251/goja.(*regexp2Wrapper).findAllSubmatchIndexUTF16()
      github.com/dop251/goja/regexp.go:295 +0xa4
  github.com/dop251/goja.(*regexp2Wrapper).findAllSubmatchIndex()
      github.com/dop251/goja/regexp.go:420 +0x2ba
  github.com/dop251/goja.(*regexpPattern).findAllSubmatchIndex()
      github.com/dop251/goja/regexp.go:134 +0x76a
  github.com/dop251/goja.(*Runtime).regexpproto_stdReplacer()
      github.com/dop251/goja/builtin_regexp.go:1091 +0x36b
  github.com/dop251/goja.(*Runtime).regexpproto_stdReplacer-fm()
      github.com/dop251/goja/builtin_regexp.go:1073 +0x8d
  github.com/dop251/goja.(*Runtime).stringproto_replace()
      github.com/dop251/goja/builtin_string.go:628 +0x650
  github.com/dop251/goja.(*Runtime).stringproto_replace-fm()
      github.com/dop251/goja/builtin_string.go:622 +0x8d
  github.com/dop251/goja.(*vm)._nativeCall()
      github.com/dop251/goja/vm.go:1818 +0x7fe
  github.com/dop251/goja.call.exec()
      github.com/dop251/goja/vm.go:1790 +0x201a
  github.com/dop251/goja.(*call).exec()
      <autogenerated>:1 +0x64
  github.com/dop251/goja.(*vm).run()
      github.com/dop251/goja/vm.go:307 +0x176
  github.com/dop251/goja.(*funcObject).call()
      github.com/dop251/goja/func.go:161 +0xbe8
  github.com/dop251/goja.(*funcObject).Call()
      github.com/dop251/goja/func.go:129 +0xa9
  github.com/dop251/goja.(*funcObject).Call-fm()
      github.com/dop251/goja/func.go:128 +0x34
  github.com/dop251/goja.(*Runtime).functionproto_call()
      github.com/dop251/goja/builtin_function.go:109 +0x1a5
  github.com/dop251/goja.(*Runtime).functionproto_call-fm()
      github.com/dop251/goja/builtin_function.go:102 +0x8d
  github.com/dop251/goja.(*vm)._nativeCall()
      github.com/dop251/goja/vm.go:1818 +0x7fe
  github.com/dop251/goja.call.exec()
      github.com/dop251/goja/vm.go:1790 +0x201a
  github.com/dop251/goja.(*call).exec()
      <autogenerated>:1 +0x64
  github.com/dop251/goja.(*vm).run()
      github.com/dop251/goja/vm.go:307 +0x176
  github.com/dop251/goja.(*funcObject).call()
      github.com/dop251/goja/func.go:161 +0xbe8
  github.com/dop251/goja.(*funcObject).Call()
      github.com/dop251/goja/func.go:129 +0xa9
  github.com/dop251/goja.(*funcObject).Call-fm()
      github.com/dop251/goja/func.go:128 +0x34
  github.com/dop251/goja.(*Runtime).functionproto_call()
      github.com/dop251/goja/builtin_function.go:109 +0x1a5
  github.com/dop251/goja.(*Runtime).functionproto_call-fm()
      github.com/dop251/goja/builtin_function.go:102 +0x8d
  github.com/dop251/goja.(*vm)._nativeCall()
      github.com/dop251/goja/vm.go:1818 +0x7fe
  github.com/dop251/goja.call.exec()
      github.com/dop251/goja/vm.go:1790 +0x201a
  github.com/dop251/goja.(*call).exec()
      <autogenerated>:1 +0x64
  github.com/dop251/goja.(*vm).run()
      github.com/dop251/goja/vm.go:307 +0x176
  github.com/dop251/goja.(*funcObject).call()
      github.com/dop251/goja/func.go:161 +0xbe8
  github.com/dop251/goja.(*funcObject).Call()
      github.com/dop251/goja/func.go:129 +0xa9
  github.com/dop251/goja.(*funcObject).Call-fm()
      github.com/dop251/goja/func.go:128 +0x34
  github.com/dop251/goja.(*Runtime).functionproto_call()
      github.com/dop251/goja/builtin_function.go:109 +0x1a5
  github.com/dop251/goja.(*Runtime).functionproto_call-fm()
      github.com/dop251/goja/builtin_function.go:102 +0x8d
  github.com/dop251/goja.(*vm)._nativeCall()
      github.com/dop251/goja/vm.go:1818 +0x7fe
  github.com/dop251/goja.call.exec()
      github.com/dop251/goja/vm.go:1790 +0x201a
  github.com/dop251/goja.(*call).exec()
      <autogenerated>:1 +0x64
  github.com/dop251/goja.(*vm).run()
      github.com/dop251/goja/vm.go:307 +0x176
  github.com/dop251/goja.(*funcObject).call()
      github.com/dop251/goja/func.go:161 +0xbe8
  github.com/dop251/goja.(*funcObject).Call()
      github.com/dop251/goja/func.go:129 +0xa9
  github.com/dop251/goja.(*funcObject).Call-fm()
      github.com/dop251/goja/func.go:128 +0x34
  github.com/dop251/goja.(*Runtime).functionproto_call()
      github.com/dop251/goja/builtin_function.go:109 +0x1a5
  github.com/dop251/goja.(*Runtime).functionproto_call-fm()
      github.com/dop251/goja/builtin_function.go:102 +0x8d
  github.com/dop251/goja.(*vm)._nativeCall()
      github.com/dop251/goja/vm.go:1818 +0x7fe
  github.com/dop251/goja.call.exec()
      github.com/dop251/goja/vm.go:1790 +0x201a
  github.com/dop251/goja.(*call).exec()
      <autogenerated>:1 +0x64
  github.com/dop251/goja.(*vm).run()
      github.com/dop251/goja/vm.go:307 +0x176
  github.com/dop251/goja.(*funcObject).call()
      github.com/dop251/goja/func.go:161 +0xbe8
  github.com/dop251/goja.(*funcObject).Call()
      github.com/dop251/goja/func.go:129 +0xa9
  github.com/dop251/goja.(*funcObject).Call-fm()
      github.com/dop251/goja/func.go:128 +0x34
  github.com/dop251/goja.(*Runtime).functionproto_call()
      github.com/dop251/goja/builtin_function.go:109 +0x1a5
  github.com/dop251/goja.(*Runtime).functionproto_call-fm()
      github.com/dop251/goja/builtin_function.go:102 +0x8d
  github.com/dop251/goja.(*vm)._nativeCall()
      github.com/dop251/goja/vm.go:1818 +0x7fe
  github.com/dop251/goja.call.exec()
      github.com/dop251/goja/vm.go:1790 +0x201a
  github.com/dop251/goja.(*call).exec()
      <autogenerated>:1 +0x64
  github.com/dop251/goja.(*vm).run()
      github.com/dop251/goja/vm.go:307 +0x176
  github.com/dop251/goja.(*funcObject).call()
      github.com/dop251/goja/func.go:161 +0xbe8
  github.com/dop251/goja.(*funcObject).Call()
      github.com/dop251/goja/func.go:129 +0xa9
  github.com/dop251/goja.(*funcObject).Call-fm()
      github.com/dop251/goja/func.go:128 +0x34
  github.com/dop251/goja.(*Runtime).functionproto_call()
      github.com/dop251/goja/builtin_function.go:109 +0x1a5
  github.com/dop251/goja.(*Runtime).functionproto_call-fm()
      github.com/dop251/goja/builtin_function.go:102 +0x8d
  github.com/dop251/goja.(*vm)._nativeCall()
      github.com/dop251/goja/vm.go:1818 +0x7fe
  github.com/dop251/goja.call.exec()
      github.com/dop251/goja/vm.go:1790 +0x201a
  github.com/dop251/goja.(*call).exec()
      <autogenerated>:1 +0x64
  github.com/dop251/goja.(*vm).run()
      github.com/dop251/goja/vm.go:307 +0x176
  github.com/dop251/goja.(*funcObject).call()
      github.com/dop251/goja/func.go:161 +0xbe8
  github.com/dop251/goja.(*funcObject).Call()
      github.com/dop251/goja/func.go:129 +0xa9
  github.com/dop251/goja.(*funcObject).Call-fm()
      github.com/dop251/goja/func.go:128 +0x34
  github.com/dop251/goja.(*Runtime).functionproto_call()
      github.com/dop251/goja/builtin_function.go:109 +0x1a5
  github.com/dop251/goja.(*Runtime).functionproto_call-fm()
      github.com/dop251/goja/builtin_function.go:102 +0x8d
  github.com/dop251/goja.(*vm)._nativeCall()
      github.com/dop251/goja/vm.go:1818 +0x7fe
  github.com/dop251/goja.call.exec()
      github.com/dop251/goja/vm.go:1790 +0x201a
  github.com/dop251/goja.(*call).exec()
      <autogenerated>:1 +0x64
  github.com/dop251/goja.(*vm).run()
      github.com/dop251/goja/vm.go:307 +0x176
  github.com/dop251/goja.(*funcObject).call()
      github.com/dop251/goja/func.go:161 +0xbe8
  github.com/dop251/goja.(*funcObject).Call()
      github.com/dop251/goja/func.go:129 +0xa9
  github.com/dop251/goja.(*funcObject).Call-fm()
      github.com/dop251/goja/func.go:128 +0x34
  github.com/dop251/goja.(*Runtime).functionproto_call()
      github.com/dop251/goja/builtin_function.go:109 +0x1a5
  github.com/dop251/goja.(*Runtime).functionproto_call-fm()
      github.com/dop251/goja/builtin_function.go:102 +0x8d
  github.com/dop251/goja.(*vm)._nativeCall()
      github.com/dop251/goja/vm.go:1818 +0x7fe
  github.com/dop251/goja.call.exec()
      github.com/dop251/goja/vm.go:1790 +0x201a
  github.com/dop251/goja.(*call).exec()
      <autogenerated>:1 +0x64
  github.com/dop251/goja.(*vm).run()
      github.com/dop251/goja/vm.go:307 +0x176
  github.com/dop251/goja.(*funcObject).call()
      github.com/dop251/goja/func.go:161 +0xbe8
  github.com/dop251/goja.(*funcObject).Call()
      github.com/dop251/goja/func.go:129 +0xa9
  github.com/dop251/goja.(*funcObject).Call-fm()
      github.com/dop251/goja/func.go:128 +0x34
  github.com/dop251/goja.(*Runtime).functionproto_call()
      github.com/dop251/goja/builtin_function.go:109 +0x1a5
  github.com/dop251/goja.(*Runtime).functionproto_call-fm()
      github.com/dop251/goja/builtin_function.go:102 +0x8d
  github.com/dop251/goja.(*vm)._nativeCall()
      github.com/dop251/goja/vm.go:1818 +0x7fe
  github.com/dop251/goja.call.exec()
      github.com/dop251/goja/vm.go:1790 +0x201a
  github.com/dop251/goja.(*call).exec()
      <autogenerated>:1 +0x64
  github.com/dop251/goja.(*vm).run()
      github.com/dop251/goja/vm.go:307 +0x176
  github.com/dop251/goja.(*funcObject).call()
      github.com/dop251/goja/func.go:161 +0xbe8
  github.com/dop251/goja.(*funcObject).Call()
      github.com/dop251/goja/func.go:129 +0xa9
  github.com/dop251/goja.(*funcObject).Call-fm()
      github.com/dop251/goja/func.go:128 +0x34
  github.com/dop251/goja.(*Runtime).functionproto_call()
      github.com/dop251/goja/builtin_function.go:109 +0x1a5
  github.com/dop251/goja.(*Runtime).functionproto_call-fm()
      github.com/dop251/goja/builtin_function.go:102 +0x8d
  github.com/dop251/goja.(*vm)._nativeCall()
      github.com/dop251/goja/vm.go:1818 +0x7fe
  github.com/dop251/goja.call.exec()
      github.com/dop251/goja/vm.go:1790 +0x201a
  github.com/dop251/goja.(*call).exec()
      <autogenerated>:1 +0x64
  github.com/dop251/goja.(*vm).run()
      github.com/dop251/goja/vm.go:307 +0x176
  github.com/dop251/goja.(*funcObject).call()
      github.com/dop251/goja/func.go:161 +0xbe8
  github.com/dop251/goja.(*funcObject).Call()
      github.com/dop251/goja/func.go:129 +0xa9
  github.com/dop251/goja.(*funcObject).Call-fm()
      github.com/dop251/goja/func.go:128 +0x34
  github.com/dop251/goja.(*Runtime).functionproto_call()
      github.com/dop251/goja/builtin_function.go:109 +0x1a5
  github.com/dop251/goja.(*Runtime).functionproto_call-fm()
      github.com/dop251/goja/builtin_function.go:102 +0x8d
  github.com/dop251/goja.(*vm)._nativeCall()
      github.com/dop251/goja/vm.go:1818 +0x7fe
  github.com/dop251/goja.call.exec()
      github.com/dop251/goja/vm.go:1790 +0x201a
  github.com/dop251/goja.(*call).exec()
      <autogenerated>:1 +0x64
  github.com/dop251/goja.(*vm).run()
      github.com/dop251/goja/vm.go:307 +0x176
  github.com/dop251/goja.(*funcObject).call()
      github.com/dop251/goja/func.go:161 +0xbe8
  github.com/dop251/goja.(*funcObject).Call()
      github.com/dop251/goja/func.go:129 +0xa9
  github.com/dop251/goja.(*funcObject).Call-fm()
      github.com/dop251/goja/func.go:128 +0x34
  github.com/dop251/goja.(*Runtime).functionproto_call()
      github.com/dop251/goja/builtin_function.go:109 +0x1a5
  github.com/dop251/goja.(*Runtime).functionproto_call-fm()
      github.com/dop251/goja/builtin_function.go:102 +0x8d
  github.com/dop251/goja.(*vm)._nativeCall()
      github.com/dop251/goja/vm.go:1818 +0x7fe
  github.com/dop251/goja.call.exec()
      github.com/dop251/goja/vm.go:1790 +0x201a
  github.com/dop251/goja.(*call).exec()
      <autogenerated>:1 +0x64
  github.com/dop251/goja.(*vm).run()
      github.com/dop251/goja/vm.go:307 +0x176
  github.com/dop251/goja.(*funcObject).call()
      github.com/dop251/goja/func.go:161 +0xbe8
  github.com/dop251/goja.(*funcObject).Call()
      github.com/dop251/goja/func.go:129 +0xa9
  github.com/dop251/goja.(*funcObject).Call-fm()
      github.com/dop251/goja/func.go:128 +0x34
  github.com/dop251/goja.(*Runtime).functionproto_call()
      github.com/dop251/goja/builtin_function.go:109 +0x1a5
  github.com/dop251/goja.(*Runtime).functionproto_call-fm()
      github.com/dop251/goja/builtin_function.go:102 +0x8d
  github.com/dop251/goja.(*vm)._nativeCall()
      github.com/dop251/goja/vm.go:1818 +0x7fe
  github.com/dop251/goja.call.exec()
      github.com/dop251/goja/vm.go:1790 +0x201a
  github.com/dop251/goja.(*call).exec()
      <autogenerated>:1 +0x64
  github.com/dop251/goja.(*vm).run()
      github.com/dop251/goja/vm.go:307 +0x176
  github.com/dop251/goja.(*funcObject).call()
      github.com/dop251/goja/func.go:161 +0xbe8
  github.com/dop251/goja.(*funcObject).Call()
      github.com/dop251/goja/func.go:129 +0xa9
  github.com/dop251/goja.(*funcObject).Call-fm()
      github.com/dop251/goja/func.go:128 +0x34
  github.com/dop251/goja.(*Runtime).functionproto_call()
      github.com/dop251/goja/builtin_function.go:109 +0x1a5
  github.com/dop251/goja.(*Runtime).functionproto_call-fm()
      github.com/dop251/goja/builtin_function.go:102 +0x8d
  github.com/dop251/goja.(*vm)._nativeCall()
      github.com/dop251/goja/vm.go:1818 +0x7fe
  github.com/dop251/goja.call.exec()
      github.com/dop251/goja/vm.go:1790 +0x201a
  github.com/dop251/goja.(*call).exec()
      <autogenerated>:1 +0x64
  github.com/dop251/goja.(*vm).run()
      github.com/dop251/goja/vm.go:307 +0x176
  github.com/dop251/goja.(*funcObject).call()
      github.com/dop251/goja/func.go:161 +0xbe8
  github.com/dop251/goja.(*funcObject).Call()
      github.com/dop251/goja/func.go:129 +0xa9
  github.com/dop251/goja.(*funcObject).Call-fm()
      github.com/dop251/goja/func.go:128 +0x34
  github.com/dop251/goja.(*Runtime).functionproto_call()
      github.com/dop251/goja/builtin_function.go:109 +0x1a5
  github.com/dop251/goja.(*Runtime).functionproto_call-fm()
      github.com/dop251/goja/builtin_function.go:102 +0x8d
  github.com/dop251/goja.(*vm)._nativeCall()
      github.com/dop251/goja/vm.go:1818 +0x7fe
  github.com/dop251/goja.call.exec()
      github.com/dop251/goja/vm.go:1790 +0x201a
  github.com/dop251/goja.(*call).exec()
      <autogenerated>:1 +0x64
  github.com/dop251/goja.(*vm).run()
      github.com/dop251/goja/vm.go:307 +0x176
  github.com/dop251/goja.(*vm).run-fm()
      github.com/dop251/goja/vm.go:299 +0x44
  github.com/dop251/goja.(*vm).try()
      github.com/dop251/goja/vm.go:413 +0x3c5
  github.com/dop251/goja.(*vm).runTry()
      github.com/dop251/goja/vm.go:418 +0x5b
  github.com/dop251/goja.(*Runtime).RunProgram()
      github.com/dop251/goja/runtime.go:1231 +0x1c9
  github.com/dop251/goja.TestPanic.func1()
      github.com/dop251/goja/panic_test.go:22 +0xd4

Previous write at 0x00c001de5148 by goroutine 32:
  github.com/dop251/goja.(*regexp2Wrapper).findUTF16Cached()
      github.com/dop251/goja/regexp.go:204 +0x167
  github.com/dop251/goja.(*regexp2Wrapper).findAllSubmatchIndexUTF16()
      github.com/dop251/goja/regexp.go:295 +0xa4
  github.com/dop251/goja.(*regexp2Wrapper).findAllSubmatchIndex()
      github.com/dop251/goja/regexp.go:420 +0x2ba
  github.com/dop251/goja.(*regexpPattern).findAllSubmatchIndex()
      github.com/dop251/goja/regexp.go:134 +0x76a
  github.com/dop251/goja.(*Runtime).regexpproto_stdReplacer()
      github.com/dop251/goja/builtin_regexp.go:1091 +0x36b
  github.com/dop251/goja.(*Runtime).regexpproto_stdReplacer-fm()
      github.com/dop251/goja/builtin_regexp.go:1073 +0x8d
  github.com/dop251/goja.(*Runtime).stringproto_replace()
      github.com/dop251/goja/builtin_string.go:628 +0x650
  github.com/dop251/goja.(*Runtime).stringproto_replace-fm()
      github.com/dop251/goja/builtin_string.go:622 +0x8d
  github.com/dop251/goja.(*vm)._nativeCall()
      github.com/dop251/goja/vm.go:1818 +0x7fe
  github.com/dop251/goja.call.exec()
      github.com/dop251/goja/vm.go:1790 +0x201a
  github.com/dop251/goja.(*call).exec()
      <autogenerated>:1 +0x64
  github.com/dop251/goja.(*vm).run()
      github.com/dop251/goja/vm.go:307 +0x176
  github.com/dop251/goja.(*funcObject).call()
      github.com/dop251/goja/func.go:161 +0xbe8
  github.com/dop251/goja.(*funcObject).Call()
      github.com/dop251/goja/func.go:129 +0xa9
  github.com/dop251/goja.(*funcObject).Call-fm()
      github.com/dop251/goja/func.go:128 +0x34
  github.com/dop251/goja.(*Runtime).functionproto_call()
      github.com/dop251/goja/builtin_function.go:109 +0x1a5
  github.com/dop251/goja.(*Runtime).functionproto_call-fm()
      github.com/dop251/goja/builtin_function.go:102 +0x8d
  github.com/dop251/goja.(*vm)._nativeCall()
      github.com/dop251/goja/vm.go:1818 +0x7fe
  github.com/dop251/goja.call.exec()
      github.com/dop251/goja/vm.go:1790 +0x201a
  github.com/dop251/goja.(*call).exec()
      <autogenerated>:1 +0x64
  github.com/dop251/goja.(*vm).run()
      github.com/dop251/goja/vm.go:307 +0x176
  github.com/dop251/goja.(*funcObject).call()
      github.com/dop251/goja/func.go:161 +0xbe8
  github.com/dop251/goja.(*funcObject).Call()
      github.com/dop251/goja/func.go:129 +0xa9
  github.com/dop251/goja.(*funcObject).Call-fm()
      github.com/dop251/goja/func.go:128 +0x34
  github.com/dop251/goja.(*Runtime).functionproto_call()
      github.com/dop251/goja/builtin_function.go:109 +0x1a5
  github.com/dop251/goja.(*Runtime).functionproto_call-fm()
      github.com/dop251/goja/builtin_function.go:102 +0x8d
  github.com/dop251/goja.(*vm)._nativeCall()
      github.com/dop251/goja/vm.go:1818 +0x7fe
  github.com/dop251/goja.call.exec()
      github.com/dop251/goja/vm.go:1790 +0x201a
  github.com/dop251/goja.(*call).exec()
      <autogenerated>:1 +0x64
  github.com/dop251/goja.(*vm).run()
      github.com/dop251/goja/vm.go:307 +0x176
  github.com/dop251/goja.(*funcObject).call()
      github.com/dop251/goja/func.go:161 +0xbe8
  github.com/dop251/goja.(*funcObject).Call()
      github.com/dop251/goja/func.go:129 +0xa9
  github.com/dop251/goja.(*funcObject).Call-fm()
      github.com/dop251/goja/func.go:128 +0x34
  github.com/dop251/goja.(*Runtime).functionproto_call()
      github.com/dop251/goja/builtin_function.go:109 +0x1a5
  github.com/dop251/goja.(*Runtime).functionproto_call-fm()
      github.com/dop251/goja/builtin_function.go:102 +0x8d
  github.com/dop251/goja.(*vm)._nativeCall()
      github.com/dop251/goja/vm.go:1818 +0x7fe
  github.com/dop251/goja.call.exec()
      github.com/dop251/goja/vm.go:1790 +0x201a
  github.com/dop251/goja.(*call).exec()
      <autogenerated>:1 +0x64
  github.com/dop251/goja.(*vm).run()
      github.com/dop251/goja/vm.go:307 +0x176
  github.com/dop251/goja.(*funcObject).call()
      github.com/dop251/goja/func.go:161 +0xbe8
  github.com/dop251/goja.(*funcObject).Call()
      github.com/dop251/goja/func.go:129 +0xa9
  github.com/dop251/goja.(*funcObject).Call-fm()
      github.com/dop251/goja/func.go:128 +0x34
  github.com/dop251/goja.(*Runtime).functionproto_call()
      github.com/dop251/goja/builtin_function.go:109 +0x1a5
  github.com/dop251/goja.(*Runtime).functionproto_call-fm()
      github.com/dop251/goja/builtin_function.go:102 +0x8d
  github.com/dop251/goja.(*vm)._nativeCall()
      github.com/dop251/goja/vm.go:1818 +0x7fe
  github.com/dop251/goja.call.exec()
      github.com/dop251/goja/vm.go:1790 +0x201a
  github.com/dop251/goja.(*call).exec()
      <autogenerated>:1 +0x64
  github.com/dop251/goja.(*vm).run()
      github.com/dop251/goja/vm.go:307 +0x176
  github.com/dop251/goja.(*funcObject).call()
      github.com/dop251/goja/func.go:161 +0xbe8
  github.com/dop251/goja.(*funcObject).Call()
      github.com/dop251/goja/func.go:129 +0xa9
  github.com/dop251/goja.(*funcObject).Call-fm()
      github.com/dop251/goja/func.go:128 +0x34
  github.com/dop251/goja.(*Runtime).functionproto_call()
      github.com/dop251/goja/builtin_function.go:109 +0x1a5
  github.com/dop251/goja.(*Runtime).functionproto_call-fm()
      github.com/dop251/goja/builtin_function.go:102 +0x8d
  github.com/dop251/goja.(*vm)._nativeCall()
      github.com/dop251/goja/vm.go:1818 +0x7fe
  github.com/dop251/goja.call.exec()
      github.com/dop251/goja/vm.go:1790 +0x201a
  github.com/dop251/goja.(*call).exec()
      <autogenerated>:1 +0x64
  github.com/dop251/goja.(*vm).run()
      github.com/dop251/goja/vm.go:307 +0x176
  github.com/dop251/goja.(*funcObject).call()
      github.com/dop251/goja/func.go:161 +0xbe8
  github.com/dop251/goja.(*funcObject).Call()
      github.com/dop251/goja/func.go:129 +0xa9
  github.com/dop251/goja.(*funcObject).Call-fm()
      github.com/dop251/goja/func.go:128 +0x34
  github.com/dop251/goja.(*Runtime).functionproto_call()
      github.com/dop251/goja/builtin_function.go:109 +0x1a5
  github.com/dop251/goja.(*Runtime).functionproto_call-fm()
      github.com/dop251/goja/builtin_function.go:102 +0x8d
  github.com/dop251/goja.(*vm)._nativeCall()
      github.com/dop251/goja/vm.go:1818 +0x7fe
  github.com/dop251/goja.call.exec()
      github.com/dop251/goja/vm.go:1790 +0x201a
  github.com/dop251/goja.(*call).exec()
      <autogenerated>:1 +0x64
  github.com/dop251/goja.(*vm).run()
      github.com/dop251/goja/vm.go:307 +0x176
  github.com/dop251/goja.(*funcObject).call()
      github.com/dop251/goja/func.go:161 +0xbe8
  github.com/dop251/goja.(*funcObject).Call()
      github.com/dop251/goja/func.go:129 +0xa9
  github.com/dop251/goja.(*funcObject).Call-fm()
      github.com/dop251/goja/func.go:128 +0x34
  github.com/dop251/goja.(*Runtime).functionproto_call()
      github.com/dop251/goja/builtin_function.go:109 +0x1a5
  github.com/dop251/goja.(*Runtime).functionproto_call-fm()
      github.com/dop251/goja/builtin_function.go:102 +0x8d
  github.com/dop251/goja.(*vm)._nativeCall()
      github.com/dop251/goja/vm.go:1818 +0x7fe
  github.com/dop251/goja.call.exec()
      github.com/dop251/goja/vm.go:1790 +0x201a
  github.com/dop251/goja.(*call).exec()
      <autogenerated>:1 +0x64
  github.com/dop251/goja.(*vm).run()
      github.com/dop251/goja/vm.go:307 +0x176
  github.com/dop251/goja.(*funcObject).call()
      github.com/dop251/goja/func.go:161 +0xbe8
  github.com/dop251/goja.(*funcObject).Call()
      github.com/dop251/goja/func.go:129 +0xa9
  github.com/dop251/goja.(*funcObject).Call-fm()
      github.com/dop251/goja/func.go:128 +0x34
  github.com/dop251/goja.(*Runtime).functionproto_call()
      github.com/dop251/goja/builtin_function.go:109 +0x1a5
  github.com/dop251/goja.(*Runtime).functionproto_call-fm()
      github.com/dop251/goja/builtin_function.go:102 +0x8d
  github.com/dop251/goja.(*vm)._nativeCall()
      github.com/dop251/goja/vm.go:1818 +0x7fe
  github.com/dop251/goja.call.exec()
      github.com/dop251/goja/vm.go:1790 +0x201a
  github.com/dop251/goja.(*call).exec()
      <autogenerated>:1 +0x64
  github.com/dop251/goja.(*vm).run()
      github.com/dop251/goja/vm.go:307 +0x176
  github.com/dop251/goja.(*funcObject).call()
      github.com/dop251/goja/func.go:161 +0xbe8
  github.com/dop251/goja.(*funcObject).Call()
      github.com/dop251/goja/func.go:129 +0xa9
  github.com/dop251/goja.(*funcObject).Call-fm()
      github.com/dop251/goja/func.go:128 +0x34
  github.com/dop251/goja.(*Runtime).functionproto_call()
      github.com/dop251/goja/builtin_function.go:109 +0x1a5
  github.com/dop251/goja.(*Runtime).functionproto_call-fm()
      github.com/dop251/goja/builtin_function.go:102 +0x8d
  github.com/dop251/goja.(*vm)._nativeCall()
      github.com/dop251/goja/vm.go:1818 +0x7fe
  github.com/dop251/goja.call.exec()
      github.com/dop251/goja/vm.go:1790 +0x201a
  github.com/dop251/goja.(*call).exec()
      <autogenerated>:1 +0x64
  github.com/dop251/goja.(*vm).run()
      github.com/dop251/goja/vm.go:307 +0x176
  github.com/dop251/goja.(*funcObject).call()
      github.com/dop251/goja/func.go:161 +0xbe8
  github.com/dop251/goja.(*funcObject).Call()
      github.com/dop251/goja/func.go:129 +0xa9
  github.com/dop251/goja.(*funcObject).Call-fm()
      github.com/dop251/goja/func.go:128 +0x34
  github.com/dop251/goja.(*Runtime).functionproto_call()
      github.com/dop251/goja/builtin_function.go:109 +0x1a5
  github.com/dop251/goja.(*Runtime).functionproto_call-fm()
      github.com/dop251/goja/builtin_function.go:102 +0x8d
  github.com/dop251/goja.(*vm)._nativeCall()
      github.com/dop251/goja/vm.go:1818 +0x7fe
  github.com/dop251/goja.call.exec()
      github.com/dop251/goja/vm.go:1790 +0x201a
  github.com/dop251/goja.(*call).exec()
      <autogenerated>:1 +0x64
  github.com/dop251/goja.(*vm).run()
      github.com/dop251/goja/vm.go:307 +0x176
  github.com/dop251/goja.(*funcObject).call()
      github.com/dop251/goja/func.go:161 +0xbe8
  github.com/dop251/goja.(*funcObject).Call()
      github.com/dop251/goja/func.go:129 +0xa9
  github.com/dop251/goja.(*funcObject).Call-fm()
      github.com/dop251/goja/func.go:128 +0x34
  github.com/dop251/goja.(*Runtime).functionproto_call()
      github.com/dop251/goja/builtin_function.go:109 +0x1a5
  github.com/dop251/goja.(*Runtime).functionproto_call-fm()
      github.com/dop251/goja/builtin_function.go:102 +0x8d
  github.com/dop251/goja.(*vm)._nativeCall()
      github.com/dop251/goja/vm.go:1818 +0x7fe
  github.com/dop251/goja.call.exec()
      github.com/dop251/goja/vm.go:1790 +0x201a
  github.com/dop251/goja.(*call).exec()
      <autogenerated>:1 +0x64
  github.com/dop251/goja.(*vm).run()
      github.com/dop251/goja/vm.go:307 +0x176
  github.com/dop251/goja.(*funcObject).call()
      github.com/dop251/goja/func.go:161 +0xbe8
  github.com/dop251/goja.(*funcObject).Call()
      github.com/dop251/goja/func.go:129 +0xa9
  github.com/dop251/goja.(*funcObject).Call-fm()
      github.com/dop251/goja/func.go:128 +0x34
  github.com/dop251/goja.(*Runtime).functionproto_call()
      github.com/dop251/goja/builtin_function.go:109 +0x1a5
  github.com/dop251/goja.(*Runtime).functionproto_call-fm()
      github.com/dop251/goja/builtin_function.go:102 +0x8d
  github.com/dop251/goja.(*vm)._nativeCall()
      github.com/dop251/goja/vm.go:1818 +0x7fe
  github.com/dop251/goja.call.exec()
      github.com/dop251/goja/vm.go:1790 +0x201a
  github.com/dop251/goja.(*call).exec()
      <autogenerated>:1 +0x64
  github.com/dop251/goja.(*vm).run()
      github.com/dop251/goja/vm.go:307 +0x176
  github.com/dop251/goja.(*funcObject).call()
      github.com/dop251/goja/func.go:161 +0xbe8
  github.com/dop251/goja.(*funcObject).Call()
      github.com/dop251/goja/func.go:129 +0xa9
  github.com/dop251/goja.(*funcObject).Call-fm()
      github.com/dop251/goja/func.go:128 +0x34
  github.com/dop251/goja.(*Runtime).functionproto_call()
      github.com/dop251/goja/builtin_function.go:109 +0x1a5
  github.com/dop251/goja.(*Runtime).functionproto_call-fm()
      github.com/dop251/goja/builtin_function.go:102 +0x8d
  github.com/dop251/goja.(*vm)._nativeCall()
      github.com/dop251/goja/vm.go:1818 +0x7fe
  github.com/dop251/goja.call.exec()
      github.com/dop251/goja/vm.go:1790 +0x201a
  github.com/dop251/goja.(*call).exec()
      <autogenerated>:1 +0x64
  github.com/dop251/goja.(*vm).run()
      github.com/dop251/goja/vm.go:307 +0x176
  github.com/dop251/goja.(*funcObject).call()
      github.com/dop251/goja/func.go:161 +0xbe8
  github.com/dop251/goja.(*funcObject).Call()
      github.com/dop251/goja/func.go:129 +0xa9
  github.com/dop251/goja.(*funcObject).Call-fm()
      github.com/dop251/goja/func.go:128 +0x34
  github.com/dop251/goja.(*Runtime).functionproto_call()
      github.com/dop251/goja/builtin_function.go:109 +0x1a5
  github.com/dop251/goja.(*Runtime).functionproto_call-fm()
      github.com/dop251/goja/builtin_function.go:102 +0x8d
  github.com/dop251/goja.(*vm)._nativeCall()
      github.com/dop251/goja/vm.go:1818 +0x7fe
  github.com/dop251/goja.call.exec()
      github.com/dop251/goja/vm.go:1790 +0x201a
  github.com/dop251/goja.(*call).exec()
      <autogenerated>:1 +0x64
  github.com/dop251/goja.(*vm).run()
      github.com/dop251/goja/vm.go:307 +0x176
  github.com/dop251/goja.(*funcObject).call()
      github.com/dop251/goja/func.go:161 +0xbe8
  github.com/dop251/goja.(*funcObject).Call()
      github.com/dop251/goja/func.go:129 +0xa9
  github.com/dop251/goja.(*funcObject).Call-fm()
      github.com/dop251/goja/func.go:128 +0x34
  github.com/dop251/goja.(*Runtime).functionproto_call()
      github.com/dop251/goja/builtin_function.go:109 +0x1a5
  github.com/dop251/goja.(*Runtime).functionproto_call-fm()
      github.com/dop251/goja/builtin_function.go:102 +0x8d
  github.com/dop251/goja.(*vm)._nativeCall()
      github.com/dop251/goja/vm.go:1818 +0x7fe
  github.com/dop251/goja.call.exec()
      github.com/dop251/goja/vm.go:1790 +0x201a
  github.com/dop251/goja.(*call).exec()
      <autogenerated>:1 +0x64
  github.com/dop251/goja.(*vm).run()
      github.com/dop251/goja/vm.go:307 +0x176
  github.com/dop251/goja.(*vm).run-fm()
      github.com/dop251/goja/vm.go:299 +0x44
  github.com/dop251/goja.(*vm).try()
      github.com/dop251/goja/vm.go:413 +0x3c5
  github.com/dop251/goja.(*vm).runTry()
      github.com/dop251/goja/vm.go:418 +0x5b
  github.com/dop251/goja.(*Runtime).RunProgram()
      github.com/dop251/goja/runtime.go:1231 +0x1c9
  github.com/dop251/goja.TestPanic.func1()
      github.com/dop251/goja/panic_test.go:22 +0xd4

Goroutine 31 (running) created at:
  github.com/dop251/goja.TestPanic()
      github.com/dop251/goja/panic_test.go:19 +0x1cf
  testing.tRunner()
      testing/testing.go:1123 +0x202

Goroutine 32 (running) created at:
  github.com/dop251/goja.TestPanic()
      github.com/dop251/goja/panic_test.go:19 +0x1cf
  testing.tRunner()
      testing/testing.go:1123 +0x202
==================

@lujjjh
Copy link

lujjjh commented Jan 6, 2021

I guess the reason is that regexp literals will be compiled to *regexpPattern at compile time and shared in multiple *Runtimes.

@mstoykov
Copy link
Contributor Author

mstoykov commented Jan 6, 2021

I did some more digging and it seems to be

values []Value
and with this MUCH smaller program it is also reproducible and even gives different places where it breaks:

package goja

import (
        "testing"
)

func TestPanic(t *testing.T) {
        s := MustCompile("babel.min.js",
                `
                var s = "a\nb\r\c\nd\r\e\n\f\rg\nh\ra\nb\r\c\nd\r\e\n\f\rg\nh\ra\nb\r\c\nd\r\e\n\f\rg\nh\ra\nb\r\c\nd\r\e\n\f\rg\nh\r\
         a\nb\r\c\nd\r\e\n\f\rg\nh\ra\nb\r\c\nd\r\e\n\f\rg\nh\ra\nb\r\c\nd\r\e\n\f\rg\nh\ra\nb\r\c\nd\r\e\n\f\rg\nh\r\
        "
                var r = /[^\r\n]+/g
                while(r.exec(s)) {};

        `, false)
        s.dumpCode(t.Logf)

        for i := 0; i < 10; i++ {
                go func() {
                        vm := New()
                        for i := 0; i < 10; i++ {
                                _, err := vm.RunProgram(s)
                                if err != nil {
                                        panic(err)
                                }
                        }
                }()
        }
}

Using dumpCode shows that the string is in values

edit: but it looks like @lujjjh is correct.

The following

e.c.emit(&newRegexp{pattern: pattern, src: newStringValue(e.expr.Pattern)})
will emit a single copy of

goja/regexp.go

Line 59 in 6b6d5e2

type regexpPattern struct {
that will be shared between all runs. And it is also the place the cache is at so ... yeah.

I still find it strange that we have values shared ...

@dop251
Copy link
Owner

dop251 commented Jan 6, 2021

Literals... of course! Thanks for finding out, I'll fix it shortly.

As for values, it only contains primitive values which are safe for concurrent use.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants