Kinda annoying, but not surprising. VMs and bytecode formats make simplifying assumptions based on the languages they expect to be hosted on top of them, and that usually means "Something with control flow like C." Creative uses of computed jumps, messing with the stack, dynamic codegen, all sorts of weird things your new language might do to efficiently implement some new control or data structure aren't likely to b…
How does dynamic dispatch work in WebAssembly?
11–20 of 22 posts
Re: How does dynamic dispatch work in WebAssembly?
#12Kinda annoying, but not surprising. VMs and bytecode formats make simplifying assumptions based on the languages they expect to be hosted on top of them, and that usually means "Something with control flow like C." Creative uses of computed jumps, messing with the stack, dynamic codegen, all sorts of weird things your new language might do to efficiently implement some new control or data structure aren't likely to b…
I've heard about alternative CPU architectures in the Lisp machine days that never gone popular, and just wonder if there're such things in the modern era.
Re: How does dynamic dispatch work in WebAssembly?
#13So how are function pointers in (say) C implemented?
Re: How does dynamic dispatch work in WebAssembly?
#14Kinda annoying, but not surprising. VMs and bytecode formats make simplifying assumptions based on the languages they expect to be hosted on top of them, and that usually means "Something with control flow like C." Creative uses of computed jumps, messing with the stack, dynamic codegen, all sorts of weird things your new language might do to efficiently implement some new control or data structure aren't likely to b…
Re: How does dynamic dispatch work in WebAssembly?
#15Do you have to analyze the source program & know where every possible call to a yield is, and store all resulting suffixes of a function as new functions?
Re: How does dynamic dispatch work in WebAssembly?
#16Kinda annoying, but not surprising. VMs and bytecode formats make simplifying assumptions based on the languages they expect to be hosted on top of them, and that usually means "Something with control flow like C." Creative uses of computed jumps, messing with the stack, dynamic codegen, all sorts of weird things your new language might do to efficiently implement some new control or data structure aren't likely to b…
Curious if we're gonna have a complete redesigned virtual machine without considering C-like conventions, how do you think we should do that? I've heard about alternative CPU architectures in the Lisp machine days that never gone popular, and just wonder if there're such things in the modern era.
Of course, portability and safety are going to be problematic there, and those can't be compromised on for a project like WASM. And even if I can't get the power I want out of the base programming model, I can approximate it more slowly in other ways. Turing completeness and all that.
I'm not familiar enough with how CPUs are laid out to know whether a hypothetical instruction set or programming model is supportable in silicon and I haven't read or thought much about it either. In any case I think that would be pretty far outside the scope of what WASM is trying to do.
Re: How does dynamic dispatch work in WebAssembly?
#17Kinda annoying, but not surprising. VMs and bytecode formats make simplifying assumptions based on the languages they expect to be hosted on top of them, and that usually means "Something with control flow like C." Creative uses of computed jumps, messing with the stack, dynamic codegen, all sorts of weird things your new language might do to efficiently implement some new control or data structure aren't likely to b…
The reason behind the limited branching instructions in wasm is validation, not compatibility with C. C compilers on real architectures emit all sorts of crazy indirection mechanisms.
Providing additional flexibility on top of those semantics is "expensive" in terms of implementor-time and effort to get safety, portability and future-proofing. There's no promise that the fun extensions they might want today go "in the right direction", and the cost of going down a bad path is high for standards.
Re: How does dynamic dispatch work in WebAssembly?
#18Someone should make a CPU that does this. Intel CET is a bit of a start, but a CALL instruction that takes a “type” operand and only calls functions of that type would be a big improvement. So would a totally separate return address stack.
What class of errors do you think this would catch that aren't already covered by CET? Simply bolting on another equality check doesn't strike me as all that useful. The type has to live with the code or data, neither one strikes me as easy, both have huge downsides. And what about CET's shadow stack is deficient compared to a "totally separate return address stack"?
AFAICT the CET shadow stack isn’t protected. An attacker that can write (using a regular write-what-where primitive) could modify the shadow stack. It should have been a new type of memory that is only accessible with special instructions.
Re: How does dynamic dispatch work in WebAssembly?
#19Someone should make a CPU that does this. Intel CET is a bit of a start, but a CALL instruction that takes a “type” operand and only calls functions of that type would be a big improvement. So would a totally separate return address stack.
There is also pointer authentication in ARM: https://lwn.net/Articles/718888/ It seems pretty difficult to define function types at the ISA level, since anything to do with typing is language/VM-specific. What types can arguments have? Are varargs supported? Multiple parameter returns? Maybe the type would just be an integer that the ABI would assign meaning to. But if you did that, how would the function's type be d…
Exactly.
Re: How does dynamic dispatch work in WebAssembly?
#20Earlier quoted context omitted.
What class of errors do you think this would catch that aren't already covered by CET? Simply bolting on another equality check doesn't strike me as all that useful. The type has to live with the code or data, neither one strikes me as easy, both have huge downsides. And what about CET's shadow stack is deficient compared to a "totally separate return address stack"?
This would catch attempts to use wrong-typed gadgets. With current CET, if I can corrupt a branch target to point to, say, system(), then I win. With type checking, I would need to corrupt an indirect branch that has the right type. AFAICT the CET shadow stack isn’t protected. An attacker that can write (using a regular write-what-where primitive) could modify the shadow stack. It should have been a new type of memor…
Gosh, seems like you could've read all the way to page 6 of the whitepaper: The shadow stack is protected from tamper through the page table protections such that regular store instructions cannot modify the contents of the shadow stack.
It goes on to detail the types of faults that are generated. Any scheme to add further checks should start from a baseline understanding of existing mechanisms, much less chiding on what they should have done. You have to encode the type somewhere, "with type checking" is woefully inadequate. Adding a byte to the opcode? Tagging the function's memory with a preamble? It seems quite difficult to come up with something that doesn't bloat code size and doesn't just marginally increase the attacker difficulty. Plus, why wouldn't an indirect branch have a type?