Panic when running twiggy on multithreaded wasm module
Closed this issue · 14 comments
I ran into an assertion when running twiggy top
on a multithreaded wasm module (attached here)
$ twiggy top raytrace_parallel_bg.wasm
thread 'main' panicked at 'should not parse the same key into multiple items', /home/alex/.cargo/registry/src/github.com-1ecc6299db9ec823/twiggy-ir-0.6.0/./ir.rs:53:9
note: Run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
Thank you for filing an issue! I will start taking a look into the cause of this.
Just wanted to follow up and say sorry that this has taken a while to get to, I've been a little caught up with life things but this is at the top of my docket 🙂
Here's a smaller test case, could likely make it even smaller with wasm-reduce
or creduce
. I suspect that just including passive data segments or something like that is enough.
(module
(type $FUNCSIG$i (func (result i32)))
(type $FUNCSIG$vi (func (param i32)))
(type $FUNCSIG$vj (func (param i64)))
(type $FUNCSIG$vf (func (param f32)))
(type $FUNCSIG$vd (func (param f64)))
(type $FUNCSIG$fifdddfVi (func (param i32 f32 f64 f64 f64 f32 v128 i32) (result f32)))
(import "fuzzing-support" "log-i32" (func $log-i32 (param i32)))
(import "fuzzing-support" "log-i64" (func $log-i64 (param i64)))
(import "fuzzing-support" "log-f32" (func $log-f32 (param f32)))
(import "fuzzing-support" "log-f64" (func $log-f64 (param f64)))
(memory $0 1 1)
(data (i32.const 0) "\1c\03a;")
(table $0 1 funcref)
(elem (i32.const 0) $func_6)
(global $global$0 (mut i32) (i32.const 2))
(global $global$1 (mut i32) (i32.const -268435456))
(global $global$2 (mut i64) (i64.const 1024))
(global $global$3 (mut i64) (i64.const -87))
(global $global$4 (mut f32) (f32.const 18231))
(global $hangLimit (mut i32) (i32.const 10))
(export "hashMemory" (func $hashMemory))
(export "func_6" (func $func_6))
(export "hangLimitInitializer" (func $hangLimitInitializer))
(func $hashMemory (; 4 ;) (type $FUNCSIG$i) (result i32)
(local $0 i32)
(local.set $0
(i32.const 5381)
)
(local.set $0
(i32.xor
(i32.add
(i32.shl
(local.get $0)
(i32.const 5)
)
(local.get $0)
)
(i32.load8_u
(i32.const 0)
)
)
)
(local.set $0
(i32.xor
(i32.add
(i32.shl
(local.get $0)
(i32.const 5)
)
(local.get $0)
)
(i32.load8_u offset=1
(i32.const 0)
)
)
)
(local.set $0
(i32.xor
(i32.add
(i32.shl
(local.get $0)
(i32.const 5)
)
(local.get $0)
)
(i32.load8_u offset=2
(i32.const 0)
)
)
)
(local.set $0
(i32.xor
(i32.add
(i32.shl
(local.get $0)
(i32.const 5)
)
(local.get $0)
)
(i32.load8_u offset=3
(i32.const 0)
)
)
)
(local.set $0
(i32.xor
(i32.add
(i32.shl
(local.get $0)
(i32.const 5)
)
(local.get $0)
)
(i32.load8_u offset=4
(i32.const 0)
)
)
)
(local.set $0
(i32.xor
(i32.add
(i32.shl
(local.get $0)
(i32.const 5)
)
(local.get $0)
)
(i32.load8_u offset=5
(i32.const 0)
)
)
)
(local.set $0
(i32.xor
(i32.add
(i32.shl
(local.get $0)
(i32.const 5)
)
(local.get $0)
)
(i32.load8_u offset=6
(i32.const 0)
)
)
)
(local.set $0
(i32.xor
(i32.add
(i32.shl
(local.get $0)
(i32.const 5)
)
(local.get $0)
)
(i32.load8_u offset=7
(i32.const 0)
)
)
)
(local.set $0
(i32.xor
(i32.add
(i32.shl
(local.get $0)
(i32.const 5)
)
(local.get $0)
)
(i32.load8_u offset=8
(i32.const 0)
)
)
)
(local.set $0
(i32.xor
(i32.add
(i32.shl
(local.get $0)
(i32.const 5)
)
(local.get $0)
)
(i32.load8_u offset=9
(i32.const 0)
)
)
)
(local.set $0
(i32.xor
(i32.add
(i32.shl
(local.get $0)
(i32.const 5)
)
(local.get $0)
)
(i32.load8_u offset=10
(i32.const 0)
)
)
)
(local.set $0
(i32.xor
(i32.add
(i32.shl
(local.get $0)
(i32.const 5)
)
(local.get $0)
)
(i32.load8_u offset=11
(i32.const 0)
)
)
)
(local.set $0
(i32.xor
(i32.add
(i32.shl
(local.get $0)
(i32.const 5)
)
(local.get $0)
)
(i32.load8_u offset=12
(i32.const 0)
)
)
)
(local.set $0
(i32.xor
(i32.add
(i32.shl
(local.get $0)
(i32.const 5)
)
(local.get $0)
)
(i32.load8_u offset=13
(i32.const 0)
)
)
)
(local.set $0
(i32.xor
(i32.add
(i32.shl
(local.get $0)
(i32.const 5)
)
(local.get $0)
)
(i32.load8_u offset=14
(i32.const 0)
)
)
)
(local.set $0
(i32.xor
(i32.add
(i32.shl
(local.get $0)
(i32.const 5)
)
(local.get $0)
)
(i32.load8_u offset=15
(i32.const 0)
)
)
)
(local.get $0)
)
(func $func_5 (; 5 ;) (param $0 i32)
(block
(if
(i32.eqz
(global.get $hangLimit)
)
(return)
)
(global.set $hangLimit
(i32.sub
(global.get $hangLimit)
(i32.const 1)
)
)
)
(data.drop 0)
)
(func $func_6 (; 6 ;) (type $FUNCSIG$fifdddfVi) (param $0 i32) (param $1 f32) (param $2 f64) (param $3 f64) (param $4 f64) (param $5 f32) (param $6 v128) (param $7 i32) (result f32)
(block
(if
(i32.eqz
(global.get $hangLimit)
)
(return
(local.get $5)
)
)
(global.set $hangLimit
(i32.sub
(global.get $hangLimit)
(i32.const 1)
)
)
)
(block $label$0 (result f32)
(local.get $5)
)
)
(func $hangLimitInitializer (; 7 ;)
(global.set $hangLimit
(i32.const 10)
)
)
)
Running into the same issue. Trying to inspect a wasm module generated by wasm-pack
to find out more about the binary size.
Any updates?
Very cool! Thanks 🙏
I just hit the same problem, I also noticed that a binary without atomic support is smaller.
You can trigger the same bug with the following code example as well:
(module
(func $main
i32.const 42
drop
)
(start $main)
)
Thanks for this example code. If I get some time these weeks I'll check if the PR above can be fixed-up and merged!
Hey @d3lm, I'm sorry about that! I've opened up a draft PR, working on it.
I'm guessing not, but have you had any luck?
@RReverser It's been so long. I think I may need to check it again, tho I am seeing that the bug is still present and there's also a minimal reproducable.
Hey, is there any update to this ?
If not, where could I look into it?
If anyone wants a work around:
- Clone the repo
- Comment out the assertion
- Run
cargo run --bin twiggy -- top path/to/file.wasm
I don't know if the results are still correct, but I'm at least getting some output to play around with.
diff --git a/ir/ir.rs b/ir/ir.rs
index f36af5d..4d9930e 100644
--- a/ir/ir.rs
+++ b/ir/ir.rs
@@ -50,10 +50,10 @@ impl ItemsBuilder {
self.items.insert(id, item);
let old_value = self.parsed.insert(id);
- assert!(
- old_value,
- "should not parse the same key into multiple items"
- );
+ // assert!(
+ // old_value,
+ // "should not parse the same key into multiple items"
+ // );
id
}