1,688 karma · joined June 6, 2017
I really like Nim the most. It's Python spiritually, but with types. Types just really really necessary, and it does have FFI support so you can forward arguments either from a wrapper or use {.cdecl} directly. It's still not a barneskirenn (as we say in Norway), but definitely the most fun I've had using another language in my various sandboxes.
Nelua and Zig are close seconds. Both are just so easy to work with C-based FFI. Nelua is probably not safe to use, as it's still a work in progress. At least last I checked. Zig is very much ready to use. Maybe not your cup of tea, though.
Golang has a complex run-time and I don't recommend using it. It's definitely possible though as my sandbox does have a full MMU. Just expect integration to be long and ardous. And the ABI changes potentially every version.
Rust is one of the easier ones. I didn't find it fun to work with though. It has by far the best inline assembly, but too much fighting with the compiler. I know that people love Rust, and it is fully supported in my emulator.
C/C++ has the benefit of having the ability to have their underlying functions overridden by native helper system calls. Eg. replacing memcpy() with a system call that has native performance. It's too long a long topic to talk about here, but Nim and Nelua also falls under this umbrella along with other languages that can compile to C/C++.
Kotlin is definitely possible to use. A bit hard to understand how the native stuff actually works, but I did manage to run a hello world program in several sandboxes with some effort. I'm not 100% sure but I think I managed to convert a C API header directly to something kotlin understands using a one-liner in the terminal. I would say it scores high just on that. Again, just a bit hard to understand how to talk to Kotlin from an external FFI looking in.
JavaScript is of course possible with both jitless v8 and QuickJS. v8 requires writing some C++ scaffolding + host API functions, and QuickJS requires the same in C. Either works.
And I think that's all the languages I have tried. If you think there's a missing language here, then I would love to try it!
wasmtime uses cranelift, which has a complex register allocator. wasm3 uses a simple register file.
> In M3/Wasm, the stack machine model is translated into a more direct and efficient "register file" approach.
https://github.com/wasm3/wasm3/blob/main/docs/Interpreter.md
There is a lot of information there, but it doesn't seem to be able to handle resource exhaustion, execution time limits or even give any guarantees. It does indicate that it's possible to use as a sandbox, and has a decent example of the most restrictive setup. But I would for example compare it with Luau's SECURITY.md.
From https://github.com/luau-lang/luau/blob/master/SECURITY.md:
> Luau provides a safe sandbox that scripts can not escape from, short of vulnerabilities in custom C functions exposed by the host. This includes the virtual machine and builtin libraries. Notably this currently does not include the work-in-progress native code generation facilities.
> Any source code can not result in memory safety errors or crashes during its compilation or execution. Violations of memory safety are considered vulnerabilities.
> Note that Luau does not provide termination guarantees - some code may exhaust CPU or RAM resources on the system during compilation or execution.
So, even luau will have trouble with untrusted code, but it does give certain guarantees, and writes specifically about what is not covered. I think that's fair. And then libriscv.
From https://github.com/fwsGonzo/libriscv/blob/master/SECURITY.md:
> libriscv provides a safe sandbox that guests can not escape from, short of vulnerabilities in custom system calls installed by the host. This includes the virtual machine and the native helper libraries. Do not use binary translation in production at this time. Do not use linux filesystem or socket system calls in production at this time.
> libriscv provides termination guarantees and default resource limits - code should not be able to exhaust CPU or RAM resources on the system during initialization or execution. If blocking calls are used during system calls, use socket timeouts or timers + signals to cancel.
So, it is possible to provide limits while still running fast. I imagine many WebAssembly emulators can give the same guarantees.
See: http://lua-users.org/lists/lua-l/2011-02/msg01582.html
I'm not sure what you mean by code generation constraints though.
There is a reason we like to think of objects as something that when constructed is valid and reusable, regardless of language. Even most decent C code looks like conservative object-oriented programming.
But what it says is that it required 24MB of HDD (12MB after installation), and a 386 or equivalent computer. An i386 is quite powerful, to be honest. It even has protected mode!
And, 4MB RAM, which is more than what I had on my 286 laptop back in the day.
Undefined-sanitizer also has a minimal-run-time mode designed to be able to run in production: https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html#...
As for ASan and MSan I think that will be quite a bit of work. I have worked in embedded a lot, and my advice here is to split off your project into static libraries, and make it so that you can run parts of it as a regular Linux program. I don't know if that's possible for you.
For example, when I was fuzzing a network stack, I would just use TAP devices to fuzz almost all of it, except the actual devices. So I partially compiled the operating system as a regular Linux program.
EDIT: Back up!
Also this commit: https://github.com/Anuken/Mindustry/commit/5548e727501793479...
Also, I'm obviously talking about porting here. You will need to tailor the code to your needs, thinking of it as a library. You cannot run an unmodified program.
Launching a new VM is not something that should be done outside of a restart or reconfiguration.
I think for me, what WASM brings to the table is perhaps reduced Linux-isms. Everything has become a little bit Linux-or-nothing, and if WASM presents a unified API towards all operating systems that is a good thing. I'm still not happy that Browsers are de-facto operating systems now, and with WASM even more so.
Some of these WASM run-times are literally hundreds of thousands of lines of code running just-in-time compilation. Inferno-level safety hazard.
There is even a simpler RV32E spec, for those (like me) with little hardware experience. Perhaps RV32E is reasonable to start with?
https://five-embeddev.com/riscv-isa-manual/latest/rv32e.html
In theory, companies make room for others when customers get pissed off and move on. It's hard to move on from these tech giants though.