intel / hyperscan

High-performance regular expression matching library
https://www.hyperscan.io
Other
4.78k stars 710 forks source link

hsScanStream crashed when scan a reseted stream #30

Closed flier closed 8 years ago

flier commented 8 years ago

I'm working on a golang binding for Hyperscan.

After I upgrade from 4.1.0 to 4.2.0, the unit tests crashed when scan a reseted stream.

I have confirmed the same code could work with Hyperscan 4.1.0 and go version go1.6.2 darwin/amd64

Are there any changes in those API behaviors?

$go test github.com/flier/gohs/hyperscan
...
fatal error: unexpected signal during runtime execution
[signal 0xb code=0x1 addr=0xb01dfacedebac1e pc=0x4350861]

runtime stack:
runtime.throw(0x4641bc0, 0x2a)
    /usr/local/opt/go/libexec/src/runtime/panic.go:547 +0x90
runtime.sigpanic()
    /usr/local/opt/go/libexec/src/runtime/sigpanic_unix.go:12 +0x5a

goroutine 36 [syscall, locked to thread]:
runtime.cgocall(0x4177080, 0xc8200ba618, 0xc800000000)
    /usr/local/opt/go/libexec/src/runtime/cgocall.go:123 +0x11b fp=0xc8200ba5d0 sp=0xc8200ba5a0
github.com/flier/gohs/hyperscan._Cfunc_hs_scan_stream_cgo(0x4903370, 0xc8200ba6d0, 0x5, 0x7000000, 0xc8200ba658, 0xc800000000)
    ??:0 +0x41 fp=0xc8200ba618 sp=0xc8200ba5d0
github.com/flier/gohs/hyperscan.hsScanStream(0x4903370, 0xc8200ba6d0, 0x5, 0x5, 0x0, 0x7000000, 0xc8200ba740, 0x0, 0x0, 0x0, ...)
    /Users/flier/gocode/src/github.com/flier/gohs/hyperscan/internal.go:902 +0xaf fp=0xc8200ba678 sp=0xc8200ba618
github.com/flier/gohs/hyperscan.TestStreamScan.func1.1.1.3.1()
    /Users/flier/gocode/src/github.com/flier/gohs/hyperscan/internal_test.go:637 +0x1bd fp=0xc8200ba788 sp=0xc8200ba678
github.com/smartystreets/goconvey/convey.parseAction.func1(0x4c447f0, 0xc8200f9680)
    /Users/flier/gocode/src/github.com/smartystreets/goconvey/convey/discovery.go:80 +0x18 fp=0xc8200ba790 sp=0xc8200ba788
github.com/smartystreets/goconvey/convey.(*context).conveyInner(0xc8200f9680, 0x4642540, 0x30, 0xc820167ab0)
    /Users/flier/gocode/src/github.com/smartystreets/goconvey/convey/context.go:261 +0x21a fp=0xc8200ba7f8 sp=0xc8200ba790
github.com/smartystreets/goconvey/convey.(*context).Convey.func1()
    /Users/flier/gocode/src/github.com/smartystreets/goconvey/convey/context.go:163 +0x40 fp=0xc8200ba820 sp=0xc8200ba7f8
github.com/jtolds/gls._m(0x0, 0xc82014ff40)
    /Users/flier/gocode/src/github.com/jtolds/gls/stack_tags.go:70 +0x2b fp=0xc8200ba838 sp=0xc8200ba820
github.com/jtolds/gls.mark4(0x0, 0xc82014ff40)
    /Users/flier/gocode/src/github.com/jtolds/gls/stack_tags.go:26 +0x2b fp=0xc8200ba850 sp=0xc8200ba838
github.com/jtolds/gls._m(0x4, 0xc82014ff40)
    /Users/flier/gocode/src/github.com/jtolds/gls/stack_tags.go:72 +0x5a fp=0xc8200ba868 sp=0xc8200ba850
github.com/jtolds/gls.markS(0x4, 0xc82014ff40)
    /Users/flier/gocode/src/github.com/jtolds/gls/stack_tags.go:21 +0x2b fp=0xc8200ba880 sp=0xc8200ba868
github.com/jtolds/gls.addStackTag(0x4, 0xc82014ff40)
    /Users/flier/gocode/src/github.com/jtolds/gls/stack_tags.go:18 +0x37 fp=0xc8200ba898 sp=0xc8200ba880
github.com/jtolds/gls.(*ContextManager).SetValues(0xc820014560, 0xc82016adb0, 0xc82014ff40)
    /Users/flier/gocode/src/github.com/jtolds/gls/context.go:98 +0x4f0 fp=0xc8200baa28 sp=0xc8200ba898
github.com/smartystreets/goconvey/convey.(*context).Convey(0xc8200f94a0, 0xc8200bac20, 0x2, 0x2)
    /Users/flier/gocode/src/github.com/smartystreets/goconvey/convey/context.go:164 +0x36b fp=0xc8200bab20 sp=0xc8200baa28
github.com/smartystreets/goconvey/convey.Convey(0xc8200bac20, 0x2, 0x2)
    /Users/flier/gocode/src/github.com/smartystreets/goconvey/convey/doc.go:77 +0x62 fp=0xc8200bab48 sp=0xc8200bab20
github.com/flier/gohs/hyperscan.TestStreamScan.func1.1.1.3()
    /Users/flier/gocode/src/github.com/flier/gohs/hyperscan/internal_test.go:639 +0x36c fp=0xc8200bac48 sp=0xc8200bab48
github.com/smartystreets/goconvey/convey.parseAction.func1(0x4c447f0, 0xc8200f94a0)
    /Users/flier/gocode/src/github.com/smartystreets/goconvey/convey/discovery.go:80 +0x18 fp=0xc8200bac50 sp=0xc8200bac48
github.com/smartystreets/goconvey/convey.(*context).conveyInner(0xc8200f94a0, 0x4621b20, 0x15, 0xc8201679c0)
    /Users/flier/gocode/src/github.com/smartystreets/goconvey/convey/context.go:261 +0x21a fp=0xc8200bacb8 sp=0xc8200bac50
github.com/smartystreets/goconvey/convey.(*context).Convey.func1()
    /Users/flier/gocode/src/github.com/smartystreets/goconvey/convey/context.go:163 +0x40 fp=0xc8200bace0 sp=0xc8200bacb8
github.com/jtolds/gls._m(0x0, 0xc82014fec0)
    /Users/flier/gocode/src/github.com/jtolds/gls/stack_tags.go:70 +0x2b fp=0xc8200bacf8 sp=0xc8200bace0
github.com/jtolds/gls.mark3(0x0, 0xc82014fec0)
    /Users/flier/gocode/src/github.com/jtolds/gls/stack_tags.go:25 +0x2b fp=0xc8200bad10 sp=0xc8200bacf8
github.com/jtolds/gls._m(0x3, 0xc82014fec0)
    /Users/flier/gocode/src/github.com/jtolds/gls/stack_tags.go:72 +0x5a fp=0xc8200bad28 sp=0xc8200bad10
github.com/jtolds/gls.markS(0x3, 0xc82014fec0)
    /Users/flier/gocode/src/github.com/jtolds/gls/stack_tags.go:21 +0x2b fp=0xc8200bad40 sp=0xc8200bad28
github.com/jtolds/gls.addStackTag(0x3, 0xc82014fec0)
    /Users/flier/gocode/src/github.com/jtolds/gls/stack_tags.go:18 +0x37 fp=0xc8200bad58 sp=0xc8200bad40
github.com/jtolds/gls.(*ContextManager).SetValues(0xc820014560, 0xc82016ac60, 0xc82014fec0)
    /Users/flier/gocode/src/github.com/jtolds/gls/context.go:98 +0x4f0 fp=0xc8200baee8 sp=0xc8200bad58
github.com/smartystreets/goconvey/convey.(*context).Convey(0xc8200f9380, 0xc8200bb128, 0x2, 0x2)
    /Users/flier/gocode/src/github.com/smartystreets/goconvey/convey/context.go:164 +0x36b fp=0xc8200bafe0 sp=0xc8200baee8
github.com/smartystreets/goconvey/convey.Convey(0xc8200bb128, 0x2, 0x2)
    /Users/flier/gocode/src/github.com/smartystreets/goconvey/convey/doc.go:77 +0x62 fp=0xc8200bb008 sp=0xc8200bafe0
github.com/flier/gohs/hyperscan.TestStreamScan.func1.1.1()
    /Users/flier/gocode/src/github.com/flier/gohs/hyperscan/internal_test.go:640 +0x737 fp=0xc8200bb190 sp=0xc8200bb008
github.com/smartystreets/goconvey/convey.parseAction.func1(0x4c447f0, 0xc8200f9380)
    /Users/flier/gocode/src/github.com/smartystreets/goconvey/convey/discovery.go:80 +0x18 fp=0xc8200bb198 sp=0xc8200bb190
github.com/smartystreets/goconvey/convey.(*context).conveyInner(0xc8200f9380, 0x463bd40, 0x29, 0xc820167840)
    /Users/flier/gocode/src/github.com/smartystreets/goconvey/convey/context.go:261 +0x21a fp=0xc8200bb200 sp=0xc8200bb198
github.com/smartystreets/goconvey/convey.(*context).Convey.func1()
    /Users/flier/gocode/src/github.com/smartystreets/goconvey/convey/context.go:163 +0x40 fp=0xc8200bb228 sp=0xc8200bb200
github.com/jtolds/gls._m(0x0, 0xc82014fda0)
    /Users/flier/gocode/src/github.com/jtolds/gls/stack_tags.go:70 +0x2b fp=0xc8200bb240 sp=0xc8200bb228
github.com/jtolds/gls.mark2(0x0, 0xc82014fda0)
    /Users/flier/gocode/src/github.com/jtolds/gls/stack_tags.go:24 +0x2b fp=0xc8200bb258 sp=0xc8200bb240
github.com/jtolds/gls._m(0x2, 0xc82014fda0)
    /Users/flier/gocode/src/github.com/jtolds/gls/stack_tags.go:72 +0x5a fp=0xc8200bb270 sp=0xc8200bb258
github.com/jtolds/gls.markS(0x2, 0xc82014fda0)
    /Users/flier/gocode/src/github.com/jtolds/gls/stack_tags.go:21 +0x2b fp=0xc8200bb288 sp=0xc8200bb270
github.com/jtolds/gls.addStackTag(0x2, 0xc82014fda0)
    /Users/flier/gocode/src/github.com/jtolds/gls/stack_tags.go:18 +0x37 fp=0xc8200bb2a0 sp=0xc8200bb288
github.com/jtolds/gls.(*ContextManager).SetValues(0xc820014560, 0xc82016aba0, 0xc82014fda0)
    /Users/flier/gocode/src/github.com/jtolds/gls/context.go:98 +0x4f0 fp=0xc8200bb430 sp=0xc8200bb2a0
github.com/smartystreets/goconvey/convey.(*context).Convey(0xc8200f9320, 0xc8200bb620, 0x2, 0x2)
    /Users/flier/gocode/src/github.com/smartystreets/goconvey/convey/context.go:164 +0x36b fp=0xc8200bb528 sp=0xc8200bb430
github.com/smartystreets/goconvey/convey.Convey(0xc8200bb620, 0x2, 0x2)
    /Users/flier/gocode/src/github.com/smartystreets/goconvey/convey/doc.go:77 +0x62 fp=0xc8200bb550 sp=0xc8200bb528
github.com/flier/gohs/hyperscan.TestStreamScan.func1.1()
    /Users/flier/gocode/src/github.com/flier/gohs/hyperscan/internal_test.go:641 +0x2f0 fp=0xc8200bb648 sp=0xc8200bb550
github.com/smartystreets/goconvey/convey.parseAction.func1(0x4c447f0, 0xc8200f9320)
    /Users/flier/gocode/src/github.com/smartystreets/goconvey/convey/discovery.go:80 +0x18 fp=0xc8200bb650 sp=0xc8200bb648
github.com/smartystreets/goconvey/convey.(*context).conveyInner(0xc8200f9320, 0x4621b00, 0x12, 0xc820167720)
    /Users/flier/gocode/src/github.com/smartystreets/goconvey/convey/context.go:261 +0x21a fp=0xc8200bb6b8 sp=0xc8200bb650
github.com/smartystreets/goconvey/convey.(*context).Convey.func1()
    /Users/flier/gocode/src/github.com/smartystreets/goconvey/convey/context.go:163 +0x40 fp=0xc8200bb6e0 sp=0xc8200bb6b8
github.com/jtolds/gls._m(0x0, 0xc82014fd60)
    /Users/flier/gocode/src/github.com/jtolds/gls/stack_tags.go:70 +0x2b fp=0xc8200bb6f8 sp=0xc8200bb6e0
github.com/jtolds/gls.mark1(0x0, 0xc82014fd60)
    /Users/flier/gocode/src/github.com/jtolds/gls/stack_tags.go:23 +0x2b fp=0xc8200bb710 sp=0xc8200bb6f8
github.com/jtolds/gls._m(0x1, 0xc82014fd60)
    /Users/flier/gocode/src/github.com/jtolds/gls/stack_tags.go:72 +0x5a fp=0xc8200bb728 sp=0xc8200bb710
github.com/jtolds/gls.markS(0x1, 0xc82014fd60)
    /Users/flier/gocode/src/github.com/jtolds/gls/stack_tags.go:21 +0x2b fp=0xc8200bb740 sp=0xc8200bb728
github.com/jtolds/gls.addStackTag(0x1, 0xc82014fd60)
    /Users/flier/gocode/src/github.com/jtolds/gls/stack_tags.go:18 +0x37 fp=0xc8200bb758 sp=0xc8200bb740
github.com/jtolds/gls.(*ContextManager).SetValues(0xc820014560, 0xc82016aab0, 0xc82014fd60)
    /Users/flier/gocode/src/github.com/jtolds/gls/context.go:98 +0x4f0 fp=0xc8200bb8e8 sp=0xc8200bb758
github.com/smartystreets/goconvey/convey.(*context).Convey(0xc8200f92c0, 0xc8200bbad0, 0x2, 0x2)
    /Users/flier/gocode/src/github.com/smartystreets/goconvey/convey/context.go:164 +0x36b fp=0xc8200bb9e0 sp=0xc8200bb8e8
github.com/smartystreets/goconvey/convey.Convey(0xc8200bbad0, 0x2, 0x2)
    /Users/flier/gocode/src/github.com/smartystreets/goconvey/convey/doc.go:77 +0x62 fp=0xc8200bba08 sp=0xc8200bb9e0
github.com/flier/gohs/hyperscan.TestStreamScan.func1()
    /Users/flier/gocode/src/github.com/flier/gohs/hyperscan/internal_test.go:644 +0x430 fp=0xc8200bbaf8 sp=0xc8200bba08
github.com/smartystreets/goconvey/convey.parseAction.func1(0x4c447f0, 0xc8200f92c0)
    /Users/flier/gocode/src/github.com/smartystreets/goconvey/convey/discovery.go:80 +0x18 fp=0xc8200bbb00 sp=0xc8200bbaf8
github.com/smartystreets/goconvey/convey.(*context).conveyInner(0xc8200f92c0, 0x46213e0, 0x17, 0xc820166340)
    /Users/flier/gocode/src/github.com/smartystreets/goconvey/convey/context.go:261 +0x21a fp=0xc8200bbb68 sp=0xc8200bbb00
github.com/smartystreets/goconvey/convey.rootConvey.func1()
    /Users/flier/gocode/src/github.com/smartystreets/goconvey/convey/context.go:110 +0x142 fp=0xc8200bbbc0 sp=0xc8200bbb68
github.com/jtolds/gls._m(0x0, 0xc82014f280)
    /Users/flier/gocode/src/github.com/jtolds/gls/stack_tags.go:70 +0x2b fp=0xc8200bbbd8 sp=0xc8200bbbc0
github.com/jtolds/gls.markS(0x0, 0xc82014f280)
    /Users/flier/gocode/src/github.com/jtolds/gls/stack_tags.go:21 +0x2b fp=0xc8200bbbf0 sp=0xc8200bbbd8
github.com/jtolds/gls.addStackTag(0x0, 0xc82014f280)
    /Users/flier/gocode/src/github.com/jtolds/gls/stack_tags.go:18 +0x37 fp=0xc8200bbc08 sp=0xc8200bbbf0
github.com/jtolds/gls.(*ContextManager).SetValues(0xc820014560, 0xc82016a030, 0xc82014f280)
    /Users/flier/gocode/src/github.com/jtolds/gls/context.go:98 +0x4f0 fp=0xc8200bbd98 sp=0xc8200bbc08
github.com/smartystreets/goconvey/convey.rootConvey(0xc8200bbf10, 0x3, 0x3)
    /Users/flier/gocode/src/github.com/smartystreets/goconvey/convey/context.go:113 +0x3eb fp=0xc8200bbe70 sp=0xc8200bbd98
github.com/smartystreets/goconvey/convey.Convey(0xc8200bbf10, 0x3, 0x3)
    /Users/flier/gocode/src/github.com/smartystreets/goconvey/convey/doc.go:75 +0x45 fp=0xc8200bbe98 sp=0xc8200bbe70
github.com/flier/gohs/hyperscan.TestStreamScan(0xc8200b2b40)
    /Users/flier/gocode/src/github.com/flier/gohs/hyperscan/internal_test.go:647 +0x1ae fp=0xc8200bbf48 sp=0xc8200bbe98
testing.tRunner(0xc8200b2b40, 0x47593a8)
    /usr/local/opt/go/libexec/src/testing/testing.go:473 +0x98 fp=0xc8200bbf80 sp=0xc8200bbf48
runtime.goexit()
    /usr/local/opt/go/libexec/src/runtime/asm_amd64.s:1998 +0x1 fp=0xc8200bbf88 sp=0xc8200bbf80
created by testing.RunTests
    /usr/local/opt/go/libexec/src/testing/testing.go:582 +0x892

goroutine 1 [chan receive]:
testing.RunTests(0x4658a88, 0x47591e0, 0x18, 0x18, 0xc820068f01)
    /usr/local/opt/go/libexec/src/testing/testing.go:583 +0x8d2
testing.(*M).Run(0xc820089ef8, 0x400b567)
    /usr/local/opt/go/libexec/src/testing/testing.go:515 +0x81
main.main()
    github.com/flier/gohs/hyperscan/_test/_testmain.go:100 +0x117

goroutine 17 [syscall, locked to thread]:
runtime.goexit()
    /usr/local/opt/go/libexec/src/runtime/asm_amd64.s:1998 +0x1
flier commented 8 years ago

very strange, only impact OSX, seems ok on Linux

mdb256 commented 8 years ago

Yes, we've also just reproduced it on OSX, but cannot on Linux.

We don't really know anything about Go or the integration, but our own unit tests pass on OSX, so we suspect it is something to do with the Go layer. Between 4.1 and 4.2 the only change in the API was adding a new error for HS_SCRATCH_IN_USE.

jviiret commented 8 years ago

@flier: Have you had any luck tracking down what was causing this? The pointer 0xb01dfacedebac1e from the Go runtime apparently indicates a memory corruption issue on OS X -- perhaps a Hyperscan allocated pointer is getting freed by Go's GC when it shouldn't be?

flier commented 8 years ago

I have upgrade to hyperscan v4.3.0 with golang 1.7, it still crash when I reuse/scan a reseted stream.

If I replace the hs_reset_stream with a pair of hs_close_stream/hs_open_stream, it could works.

                Convey("Then reset the stream", func() {
                    //So(hsResetStream(stream, 0, s, h.Handle, nil), ShouldBeNil)
                    So(hsCloseStream(stream, s, h.Handle, nil), ShouldBeNil)

                    stream, err := hsOpenStream(db, 0)

                    So(stream, ShouldNotBeNil)
                    So(err, ShouldBeNil)

                    Convey("When scan the second part, should not be matched", func() {
                        So(hsScanStream(stream, []byte("stdef"), 0, s, h.Handle, nil), ShouldBeNil)
                        So(h.matched, ShouldBeNil)
                    })
                })

When I use hs_reset_and_copy_stream in similar scene, it also could works very well.

                Convey("Then copy the stream", func() {
                    stream2, err := hsCopyStream(stream)

                    So(stream2, ShouldNotBeNil)
                    So(err, ShouldBeNil)

                    Convey("When copied stream2 scan the second part, should be matched", func() {
                        So(hsScanStream(stream2, []byte("stdef"), 0, s, h.Handle, nil), ShouldBeNil)
                        So(h.matched, ShouldResemble, []matchEvent{{0, 0, 7, 0}})

                        Convey("When copied stream2 scan the second part again, should not be matched", func() {
                            h.matched = nil
                            So(hsScanStream(stream2, []byte("stdef"), 0, s, h.Handle, nil), ShouldBeNil)
                            So(h.matched, ShouldBeNil)

                            Convey("When copy and reset stream2", func() {
                                So(hsResetAndCopyStream(stream2, stream, s, h.Handle, nil), ShouldBeNil)

                                Convey("When copied and reset stream2 scan the second part again, should be matched", func() {
                                    h.matched = nil
                                    So(hsScanStream(stream2, []byte("stdef"), 0, s, h.Handle, nil), ShouldBeNil)
                                    So(h.matched, ShouldResemble, []matchEvent{{0, 0, 7, 0}})
                                })
                            })
                        })
                    })

                    So(hsCloseStream(stream2, s, h.Handle, nil), ShouldBeNil)
                })

It seems hs_reset_stream will write some pointer and corrupt memory, because when I call hs_reset_stream twice, it also crash

                Convey("Then reset the stream", func() {
                    So(hsResetStream(stream, 0, s, h.Handle, nil), ShouldBeNil)
                    So(hsResetStream(stream, 0, s, h.Handle, nil), ShouldBeNil)

                    Convey("When scan the second part, should not be matched", func() {
                        So(hsScanStream(stream, []byte("stdef"), 0, s, h.Handle, nil), ShouldBeNil)
                        So(h.matched, ShouldBeNil)
                    })
                })
func hsResetStream(stream hsStream, flags ScanFlag, scratch hsScratch, onEvent hsMatchEventHandler, context interface{}) error {
    ctxt := &hsMatchEventContext{onEvent, context}

    ret := C.hs_reset_stream_cgo(C.uintptr_t(uintptr(unsafe.Pointer(stream))), C.uint(flags),
        C.uintptr_t(uintptr(unsafe.Pointer(scratch))), C.uintptr_t(uintptr(unsafe.Pointer(ctxt))))

    if ret != C.HS_SUCCESS {
        return HsError(ret)
    }

    return nil
}
static inline
hs_error_t hs_reset_stream_cgo(uintptr_t id, unsigned int flags, uintptr_t scratch, uintptr_t context) {
    return hs_reset_stream((hs_stream_t *) id, flags, (hs_scratch_t *) scratch, hs_event_callback, (void *) context);
}
mdb256 commented 8 years ago

Thank you for reporting this - this turns out to be an issue with Clang builds (as found in Xcode) and the changes we had made in hs_reset_stream() - it did not affect gcc builds.

We have pushed v4.3.1 with a fix for this.

flier commented 8 years ago

Verified, it could works now, thanks