vugu / vugu

Vugu: A modern UI library for Go+WebAssembly (experimental)
https://www.vugu.org
MIT License
4.8k stars 175 forks source link

Panic: index out of range #233

Closed PotatoesFall closed 1 year ago

PotatoesFall commented 1 year ago

Describe the bug After running smoothly for quite some time, I have an app that is suddenly crashing. Certain actions will trigger a panic with index out of range. This is happening in the domrender package in the (*instructionList).writeValString, stack trace is included at the end.

I tried to do some checking but I'm not quite sure I understand the instructionList well enough to diagnose what is happening.

Software Versions Vugu version: 0.3.4 Go version: 1.18 and 1.19 (both) Browser and version: Firefox (version unclear), Brave 1.42.97 which is based on Chromium: 104.0.5112.102

To Reproduce unfortunately, I cannot reproduce this bug in a simple way, it seems to occur only with a very specify set of data.

Expected behavior I expect there not to be a panic.

Additional Notes

Stack Trace ``` panic: runtime error: slice bounds out of range [:16387] with capacity 16384 wasm_exec.js:51:14 wasm_exec.js:51:14 goroutine 1 [running]: wasm_exec.js:51:14 github.com/vugu/vugu/domrender.(*instructionList).writeValString(...) wasm_exec.js:51:14 /home/marty/go/pkg/mod/github.com/vugu/vugu@v0.3.4/domrender/renderer-js-instructions.go:559 wasm_exec.js:51:14 github.com/vugu/vugu/domrender.(*instructionList).writeSetAttrNSStr(0x848300, {0x0, 0x0}, {0x8ab00, 0x6}, {0x8e428, 0x11}) wasm_exec.js:51:14 /home/marty/go/pkg/mod/github.com/vugu/vugu@v0.3.4/domrender/renderer-js-instructions.go:204 +0x42 wasm_exec.js:51:14 github.com/vugu/vugu/domrender.(*JSRenderer).syncElement(0x83d1e0, 0x80a180, 0xb8e9c0, {0x885f40, 0x29, 0x40}) wasm_exec.js:51:14 /home/marty/go/pkg/mod/github.com/vugu/vugu@v0.3.4/domrender/renderer-js.go:584 +0x98 wasm_exec.js:51:14 github.com/vugu/vugu/domrender.(*JSRenderer).visitSyncElementEtc(0x83d1e0, 0x80a180, 0xb66fc0, 0xb6f930, 0xb8e9c0, {0x885f40, 0x29, 0x40}) wasm_exec.js:51:14 /home/marty/go/pkg/mod/github.com/vugu/vugu@v0.3.4/domrender/renderer-js.go:510 +0x2 wasm_exec.js:51:14 github.com/vugu/vugu/domrender.(*JSRenderer).visitSyncNode(0x83d1e0, 0x80a180, 0xb66fc0, 0xb6f930, 0xb8e9c0, {0x885f40, 0x29, 0x40}) wasm_exec.js:51:14 /home/marty/go/pkg/mod/github.com/vugu/vugu@v0.3.4/domrender/renderer-js.go:503 +0x47 wasm_exec.js:51:14 github.com/vugu/vugu/domrender.(*JSRenderer).visitSyncElementEtc(0x83d1e0, 0x80a180, 0xb66fc0, 0xb6f930, 0xb8e820, {0x885f40, 0x27, 0x40}) wasm_exec.js:51:14 /home/marty/go/pkg/mod/github.com/vugu/vugu@v0.3.4/domrender/renderer-js.go:544 +0x40 wasm_exec.js:51:14 github.com/vugu/vugu/domrender.(*JSRenderer).visitSyncNode(0x83d1e0, 0x80a180, 0xb66fc0, 0xb6f930, 0xb8e820, {0x885f40, 0x27, 0x40}) wasm_exec.js:51:14 /home/marty/go/pkg/mod/github.com/vugu/vugu@v0.3.4/domrender/renderer-js.go:503 +0x47 wasm_exec.js:51:14 github.com/vugu/vugu/domrender.(*JSRenderer).visitSyncElementEtc(0x83d1e0, 0x80a180, 0xb66fc0, 0xb6f930, 0xb8e410, {0x885f40, 0x25, 0x40}) wasm_exec.js:51:14 /home/marty/go/pkg/mod/github.com/vugu/vugu@v0.3.4/domrender/renderer-js.go:544 +0x40 wasm_exec.js:51:14 github.com/vugu/vugu/domrender.(*JSRenderer).visitSyncNode(0x83d1e0, 0x80a180, 0xb66fc0, 0xb6f930, 0xb8e410, {0x885f40, 0x25, 0x40}) wasm_exec.js:51:14 /home/marty/go/pkg/mod/github.com/vugu/vugu@v0.3.4/domrender/renderer-js.go:503 +0x47 wasm_exec.js:51:14 github.com/vugu/vugu/domrender.(*JSRenderer).visitSyncElementEtc(0x83d1e0, 0x80a180, 0xb66fc0, 0xb6f930, 0xb8e270, {0x885f40, 0x23, 0x40}) wasm_exec.js:51:14 /home/marty/go/pkg/mod/github.com/vugu/vugu@v0.3.4/domrender/renderer-js.go:544 +0x40 wasm_exec.js:51:14 github.com/vugu/vugu/domrender.(*JSRenderer).visitSyncNode(0x83d1e0, 0x80a180, 0xb66fc0, 0xb6f930, 0xb8e270, {0x885f40, 0x23, 0x40}) wasm_exec.js:51:14 /home/marty/go/pkg/mod/github.com/vugu/vugu@v0.3.4/domrender/renderer-js.go:503 +0x47 wasm_exec.js:51:14 github.com/vugu/vugu/domrender.(*JSRenderer).visitSyncNode(0x83d1e0, 0x80a180, 0xb66ea0, 0xb6f930, 0xb8dee0, {0x885f40, 0x23, 0x40}) wasm_exec.js:51:14 /home/marty/go/pkg/mod/github.com/vugu/vugu@v0.3.4/domrender/renderer-js.go:450 +0x6e wasm_exec.js:51:14 github.com/vugu/vugu/domrender.(*JSRenderer).visitSyncElementEtc(0x83d1e0, 0x80a180, 0xb66ea0, 0xb6f930, 0xb8cf70, {0x885f40, 0x21, 0x40}) wasm_exec.js:51:14 /home/marty/go/pkg/mod/github.com/vugu/vugu@v0.3.4/domrender/renderer-js.go:544 +0x40 wasm_exec.js:51:14 github.com/vugu/vugu/domrender.(*JSRenderer).visitSyncNode(0x83d1e0, 0x80a180, 0xb66ea0, 0xb6f930, 0xb8cf70, {0x885f40, 0x21, 0x40}) wasm_exec.js:51:14 /home/marty/go/pkg/mod/github.com/vugu/vugu@v0.3.4/domrender/renderer-js.go:503 +0x47 wasm_exec.js:51:14 github.com/vugu/vugu/domrender.(*JSRenderer).visitSyncElementEtc(0x83d1e0, 0x80a180, 0xb66ea0, 0xb6f930, 0xb8ca90, {0xab54e0, 0x1f, 0x20}) wasm_exec.js:51:14 /home/marty/go/pkg/mod/github.com/vugu/vugu@v0.3.4/domrender/renderer-js.go:544 +0x40 wasm_exec.js:51:14 github.com/vugu/vugu/domrender.(*JSRenderer).visitSyncNode(0x83d1e0, 0x80a180, 0xb66ea0, 0xb6f930, 0xb8ca90, {0xab54e0, 0x1f, 0x20}) wasm_exec.js:51:14 /home/marty/go/pkg/mod/github.com/vugu/vugu@v0.3.4/domrender/renderer-js.go:503 +0x47 wasm_exec.js:51:14 github.com/vugu/vugu/domrender.(*JSRenderer).visitSyncNode(0x83d1e0, 0x80a180, 0xb66e40, 0xb6f930, 0xb8c8f0, {0xab54e0, 0x1f, 0x20}) wasm_exec.js:51:14 /home/marty/go/pkg/mod/github.com/vugu/vugu@v0.3.4/domrender/renderer-js.go:450 +0x6e wasm_exec.js:51:14 github.com/vugu/vugu/domrender.(*JSRenderer).visitSyncNode(0x83d1e0, 0x80a180, 0xb66e40, 0xb6f930, 0xb8c750, {0xab54e0, 0x1b, 0x20}) wasm_exec.js:51:14 /home/marty/go/pkg/mod/github.com/vugu/vugu@v0.3.4/domrender/renderer-js.go:462 +0x7a wasm_exec.js:51:14 github.com/vugu/vugu/domrender.(*JSRenderer).visitSyncNode(0x83d1e0, 0x80a180, 0xb66de0, 0xb6f930, 0xb8c270, {0xab54e0, 0x1b, 0x20}) wasm_exec.js:51:14 /home/marty/go/pkg/mod/github.com/vugu/vugu@v0.3.4/domrender/renderer-js.go:450 +0x6e wasm_exec.js:51:14 github.com/vugu/vugu/domrender.(*JSRenderer).visitSyncElementEtc(0x83d1e0, 0x80a180, 0xb66de0, 0xb6f930, 0xb8b5f0, {0xab54e0, 0x19, 0x20}) wasm_exec.js:51:14 /home/marty/go/pkg/mod/github.com/vugu/vugu@v0.3.4/domrender/renderer-js.go:544 +0x40 wasm_exec.js:51:14 github.com/vugu/vugu/domrender.(*JSRenderer).visitSyncNode(0x83d1e0, 0x80a180, 0xb66de0, 0xb6f930, 0xb8b5f0, {0xab54e0, 0x19, 0x20}) wasm_exec.js:51:14 /home/marty/go/pkg/mod/github.com/vugu/vugu@v0.3.4/domrender/renderer-js.go:503 +0x47 wasm_exec.js:51:14 github.com/vugu/vugu/domrender.(*JSRenderer).visitSyncElementEtc(0x83d1e0, 0x80a180, 0xb66de0, 0xb6f930, 0xb8b2b0, {0xab54e0, 0x17, 0x20}) wasm_exec.js:51:14 /home/marty/go/pkg/mod/github.com/vugu/vugu@v0.3.4/domrender/renderer-js.go:544 +0x40 wasm_exec.js:51:14 github.com/vugu/vugu/domrender.(*JSRenderer).visitSyncNode(0x83d1e0, 0x80a180, 0xb66de0, 0xb6f930, 0xb8b2b0, {0xab54e0, 0x17, 0x20}) wasm_exec.js:51:14 /home/marty/go/pkg/mod/github.com/vugu/vugu@v0.3.4/domrender/renderer-js.go:503 +0x47 wasm_exec.js:51:14 github.com/vugu/vugu/domrender.(*JSRenderer).visitSyncElementEtc(0x83d1e0, 0x80a180, 0xb66de0, 0xb6f930, 0xb8b110, {0xab54e0, 0x15, 0x20}) wasm_exec.js:51:14 /home/marty/go/pkg/mod/github.com/vugu/vugu@v0.3.4/domrender/renderer-js.go:544 +0x40 wasm_exec.js:51:14 github.com/vugu/vugu/domrender.(*JSRenderer).visitSyncNode(0x83d1e0, 0x80a180, 0xb66de0, 0xb6f930, 0xb8b110, {0xab54e0, 0x15, 0x20}) wasm_exec.js:51:14 /home/marty/go/pkg/mod/github.com/vugu/vugu@v0.3.4/domrender/renderer-js.go:503 +0x47 wasm_exec.js:51:14 github.com/vugu/vugu/domrender.(*JSRenderer).visitSyncNode(0x83d1e0, 0x80a180, 0xb66c60, 0xb6f930, 0xb8a9c0, {0xab54e0, 0x15, 0x20}) wasm_exec.js:51:14 /home/marty/go/pkg/mod/github.com/vugu/vugu@v0.3.4/domrender/renderer-js.go:450 +0x6e wasm_exec.js:51:14 github.com/vugu/vugu/domrender.(*JSRenderer).visitSyncElementEtc(0x83d1e0, 0x80a180, 0xb66c60, 0xb6f930, 0xb88f70, {0xab54e0, 0x12, 0x20}) wasm_exec.js:51:14 /home/marty/go/pkg/mod/github.com/vugu/vugu@v0.3.4/domrender/renderer-js.go:544 +0x40 wasm_exec.js:51:14 github.com/vugu/vugu/domrender.(*JSRenderer).visitSyncNode(0x83d1e0, 0x80a180, 0xb66c60, 0xb6f930, 0xb88f70, {0xab54e0, 0x12, 0x20}) wasm_exec.js:51:14 /home/marty/go/pkg/mod/github.com/vugu/vugu@v0.3.4/domrender/renderer-js.go:503 +0x47 wasm_exec.js:51:14 github.com/vugu/vugu/domrender.(*JSRenderer).visitSyncNode(0x83d1e0, 0x80a180, 0xb66c00, 0xb6f930, 0xb88dd0, {0xab54e0, 0x12, 0x20}) wasm_exec.js:51:14 /home/marty/go/pkg/mod/github.com/vugu/vugu@v0.3.4/domrender/renderer-js.go:450 +0x6e wasm_exec.js:51:14 github.com/vugu/vugu/domrender.(*JSRenderer).visitSyncNode(0x83d1e0, 0x80a180, 0xb66c00, 0xb6f930, 0xb88c30, {0xb80390, 0xe, 0x10}) wasm_exec.js:51:14 /home/marty/go/pkg/mod/github.com/vugu/vugu@v0.3.4/domrender/renderer-js.go:462 +0x7a wasm_exec.js:51:14 github.com/vugu/vugu/domrender.(*JSRenderer).visitSyncNode(0x83d1e0, 0x80a180, 0xb66720, 0xb6f930, 0xb79930, {0xb80390, 0xe, 0x10}) wasm_exec.js:51:14 /home/marty/go/pkg/mod/github.com/vugu/vugu@v0.3.4/domrender/renderer-js.go:450 +0x6e wasm_exec.js:51:14 github.com/vugu/vugu/domrender.(*JSRenderer).visitSyncElementEtc(0x83d1e0, 0x80a180, 0xb66720, 0xb6f930, 0xb79790, {0xb80390, 0xc, 0x10}) wasm_exec.js:51:14 /home/marty/go/pkg/mod/github.com/vugu/vugu@v0.3.4/domrender/renderer-js.go:544 +0x40 wasm_exec.js:51:14 github.com/vugu/vugu/domrender.(*JSRenderer).visitSyncNode(0x83d1e0, 0x80a180, 0xb66720, 0xb6f930, 0xb79790, {0xb80390, 0xc, 0x10}) wasm_exec.js:51:14 /home/marty/go/pkg/mod/github.com/vugu/vugu@v0.3.4/domrender/renderer-js.go:503 +0x47 wasm_exec.js:51:14 github.com/vugu/vugu/domrender.(*JSRenderer).visitSyncElementEtc(0x83d1e0, 0x80a180, 0xb66720, 0xb6f930, 0xb780d0, {0xb80390, 0x9, 0x10}) wasm_exec.js:51:14 /home/marty/go/pkg/mod/github.com/vugu/vugu@v0.3.4/domrender/renderer-js.go:544 +0x40 wasm_exec.js:51:14 github.com/vugu/vugu/domrender.(*JSRenderer).visitSyncNode(0x83d1e0, 0x80a180, 0xb66720, 0xb6f930, 0xb780d0, {0xb80390, 0x9, 0x10}) wasm_exec.js:51:14 /home/marty/go/pkg/mod/github.com/vugu/vugu@v0.3.4/domrender/renderer-js.go:503 +0x47 wasm_exec.js:51:14 github.com/vugu/vugu/domrender.(*JSRenderer).visitSyncNode(0x83d1e0, 0x80a180, 0xb666c0, 0xb6f930, 0xb77e10, {0xb80390, 0x9, 0x10}) wasm_exec.js:51:14 /home/marty/go/pkg/mod/github.com/vugu/vugu@v0.3.4/domrender/renderer-js.go:450 +0x6e wasm_exec.js:51:14 github.com/vugu/vugu/domrender.(*JSRenderer).visitSyncElementEtc(0x83d1e0, 0x80a180, 0xb666c0, 0xb6f930, 0xb77c70, {0xb801c0, 0x7, 0x8}) wasm_exec.js:51:14 /home/marty/go/pkg/mod/github.com/vugu/vugu@v0.3.4/domrender/renderer-js.go:544 +0x40 wasm_exec.js:51:14 github.com/vugu/vugu/domrender.(*JSRenderer).visitSyncNode(0x83d1e0, 0x80a180, 0xb666c0, 0xb6f930, 0xb77c70, {0xb801c0, 0x7, 0x8}) wasm_exec.js:51:14 /home/marty/go/pkg/mod/github.com/vugu/vugu@v0.3.4/domrender/renderer-js.go:503 +0x47 wasm_exec.js:51:14 github.com/vugu/vugu/domrender.(*JSRenderer).visitSyncNode(0x83d1e0, 0x80a180, 0xb664e0, 0xb6f930, 0xb749c0, {0xb801c0, 0x7, 0x8}) wasm_exec.js:51:14 /home/marty/go/pkg/mod/github.com/vugu/vugu@v0.3.4/domrender/renderer-js.go:450 +0x6e wasm_exec.js:51:14 github.com/vugu/vugu/domrender.(*JSRenderer).visitSyncElementEtc(0x83d1e0, 0x80a180, 0xb664e0, 0xb6f930, 0xb74680, {0xb801c0, 0x5, 0x8}) wasm_exec.js:51:14 /home/marty/go/pkg/mod/github.com/vugu/vugu@v0.3.4/domrender/renderer-js.go:544 +0x40 wasm_exec.js:51:14 github.com/vugu/vugu/domrender.(*JSRenderer).visitSyncNode(0x83d1e0, 0x80a180, 0xb664e0, 0xb6f930, 0xb74680, {0xb801c0, 0x5, 0x8}) wasm_exec.js:51:14 /home/marty/go/pkg/mod/github.com/vugu/vugu@v0.3.4/domrender/renderer-js.go:503 +0x47 wasm_exec.js:51:14 github.com/vugu/vugu/domrender.(*JSRenderer).visitSyncElementEtc(0x83d1e0, 0x80a180, 0xb664e0, 0xb6f930, 0xb74340, {0xb801c0, 0x3, 0x8}) wasm_exec.js:51:14 /home/marty/go/pkg/mod/github.com/vugu/vugu@v0.3.4/domrender/renderer-js.go:544 +0x40 wasm_exec.js:51:14 github.com/vugu/vugu/domrender.(*JSRenderer).visitSyncNode(0x83d1e0, 0x80a180, 0xb664e0, 0xb6f930, 0xb74340, {0xb801c0, 0x3, 0x8}) wasm_exec.js:51:14 /home/marty/go/pkg/mod/github.com/vugu/vugu@v0.3.4/domrender/renderer-js.go:503 +0x47 wasm_exec.js:51:14 github.com/vugu/vugu/domrender.(*JSRenderer).visitSyncNode(0x83d1e0, 0x80a180, 0xb66420, 0xb6f930, 0xb6bd40, {0xb801c0, 0x3, 0x8}) wasm_exec.js:51:14 /home/marty/go/pkg/mod/github.com/vugu/vugu@v0.3.4/domrender/renderer-js.go:450 +0x6e wasm_exec.js:51:14 github.com/vugu/vugu/domrender.(*JSRenderer).visitSyncElementEtc(0x83d1e0, 0x80a180, 0xb66420, 0xb6f930, 0xb6ba00, {0xb80187, 0x1, 0x1}) wasm_exec.js:51:14 /home/marty/go/pkg/mod/github.com/vugu/vugu@v0.3.4/domrender/renderer-js.go:544 +0x40 wasm_exec.js:51:14 github.com/vugu/vugu/domrender.(*JSRenderer).visitMount(0x83d1e0, 0x80a180, 0xb66420, 0xb6f930, 0xb6ba00, {0xb80187, 0x1, 0x1}) wasm_exec.js:51:14 /home/marty/go/pkg/mod/github.com/vugu/vugu@v0.3.4/domrender/renderer-js.go:433 +0x9 wasm_exec.js:51:14 github.com/vugu/vugu/domrender.(*JSRenderer).visitFirst(0x83d1e0, 0x80a180, 0xb66420, 0xb6f930, 0xb6ba00, {0xb80187, 0x1, 0x1}) wasm_exec.js:51:14 /home/marty/go/pkg/mod/github.com/vugu/vugu@v0.3.4/domrender/renderer-js.go:380 +0x14 wasm_exec.js:51:14 github.com/vugu/vugu/domrender.(*JSRenderer).render(0x83d1e0, 0xb6f930) wasm_exec.js:51:14 /home/marty/go/pkg/mod/github.com/vugu/vugu@v0.3.4/domrender/renderer-js.go:257 +0x3f wasm_exec.js:51:14 github.com/vugu/vugu/domrender.(*JSRenderer).Render(0x83d1e0, 0xb6f930) wasm_exec.js:51:14 /home/marty/go/pkg/mod/github.com/vugu/vugu@v0.3.4/domrender/renderer-js-default.go:41 +0x5 wasm_exec.js:51:14 main.render(0x83d1e0, 0x830140, {0xfd380, 0x40a5d0}) wasm_exec.js:51:14 /home/marty/github.com/FallenTaters/streepjes/frontend/main.go:58 +0x3 wasm_exec.js:51:14 main.startVugu() wasm_exec.js:51:14 /home/marty/github.com/FallenTaters/streepjes/frontend/main.go:52 +0x23 wasm_exec.js:51:14 main.main() wasm_exec.js:51:14 /home/marty/github.com/FallenTaters/streepjes/frontend/main.go:18 +0x2 ```
PotatoesFall commented 1 year ago

@bradleypeabody this is what I've figured out so far:

(il *instructionList) writeValString(s string) seems to write 4 bytes containing the length of the string, and then the string itself:

func (il *instructionList) writeValString(s string) {

    lenstr := len(s)
    pos := il.pos

    // write length as uint32
    binary.BigEndian.PutUint32(il.buf[pos:pos+4], uint32(lenstr))

    // copy bytes directly from string into buf
    copy(il.buf[pos+4:pos+4+lenstr], s)

    il.pos = pos + 4 + lenstr
}

However, in this case it is being called by (il *instructionList) writeSetAttrNSStr(namespace, name, value string) error :

func (il *instructionList) writeSetAttrNSStr(namespace, name, value string) error {

    il.logf("writeSetAttrNSStr[%d](ns=%q, name=%q, value=%q)", opcodeSetAttrNSStr, namespace, name, value)

    size := len(namespace) + len(name) + len(value) + 9

    err := il.checkLenAndFlush(size)
    if err != nil {
        return err
    }

    il.writeValUint8(opcodeSetAttrNSStr)
    il.writeValString(namespace)
    il.writeValString(name)
    il.writeValString(value) // PANIC OCCURS HERE

    return nil
}

which adds 9 bytes to the total length of bytes written. I think this needs to be 13 bytes, since we are writing three values plus the opcodeSetAttrNSStr ?

I made this pull request: https://github.com/vugu/vugu/pull/234

bradleypeabody commented 1 year ago

Yup, you're absolutely right. Good catch! And sorry for the delay getting back to on this. I'll merge the PR now.