Running Zig with WASI on Cloudflare Workers
blog.cloudflare.com
blog.cloudflare.com
We (Wasmer) have been working with the Zig team (special thanks to Topolarity here!) to get Zig on WASI and WAPM! We also want to have it automatically deployed to WAPM on each new version released.
For anyone that wants to try Zig online, this might be of your interest! https://wapm.io/topolarity/zig
For some applications, rust's borrowchecker is not something you're going to want to be without, but is "memory safety" actually a concern when compiling to web assembly? In that case, is Zig all pros and no cons? You get its easy to use interfaces for allocation and working with raw bytes, but without the chance of memory vulnerabilities, like when running in a sandboxed browser environment or Cloudflare's V8 isolates?
Whenever I read something like this, I think: "Why is it some people will dream up niches for other languages to fill that are about people not liking Rust?" It's interesting if only because it seems lots of people really like writing Rust. Have these people tried Rust? Shouldn't Zig stand on its own -- "Zig is better because it solves X and Y" or even some matter ease or style "Zig makes it easier to X and Y which is important for WASI apps"?
.NET + C++/CLI, Java/Kotlin + JNI/NDK, JavaScript + C++ addons, and so on.
Many developers get lost trying to use an hammer for every nail.
Does Zig also have the memory safety guarantees of Rust? It seems like a much nicer language to learn and use IMO
There are attempts to achieve this in a simpler way (such as Vale) but right now you're better off using something with GC if you want that sort of safety.
It does not enforce temporal memory safety, which is the harder one. Rust does have that (but it has unsafe blocks due to the limitations), and GC does have that (but it has overhead).
Zig might add a temporal memory safety mode in some way eventually, but it will almost certainly add overhead. Example options for that: never release allocated blocks to the OS, or Type-After-Type (different allocation regions per type). Both add enough overhead that it won't be good enough for some use cases, but fine for others.
Concurrency related races accessing external resources, nope.
I don't think spatial memory safety alone is a large improvement over C++ in particular, since most memory safety vulnerabilities nowadays are UAF. For C, maybe; I'd have to look at LazyFishBarrel to see how many bugs nowadays are spatial as opposed to temporal (I'd guess that temporal vulnerabilities are more common nowadays in C too).
https://www.scattered-thoughts.net/writing/how-safe-is-zig/
Agreed that UAF is the larger factor these days for C++. Those are just impossible to really get rid of in such a language, without the overhead of something like Type-After-Type (which in some cases is just too much).
Hence why it would be nice if Zig would be a bit better in that regard.
Much safer than plain C, but use-after-free and double free will still get you.
https://blog.cloudflare.com/introducing-workers-durable-obje...
I am not affiliated with Cloudflare, but Workers is by far my favorite cloud/serverless platform -- so much simpler and faster than Lambda, etc. (if your use case is simple enough)
As far as I know, CFW heavily leans on V8 isolates for scaling.
Why reinvent the wheel?
I also did this recently but with the shim approach: a small Rust program that needs to run a cryptography operation on some input[1], compiled to wasi and operating on stdin/stdout, and then invoked by a larger Typescript program invoking it with the proper stream. Worked great.
There is also a thing called workers-rs[2] which will let you write the entire worker in Rust, but it does not use WASI. WASI isn't really enough for anything beyond simple stdin/stdout pipelines without something "wrapping it" to provide the needed fds, env vars, arguments, etc. So instead workers-rs binds to the underlying Worker runtime primitives, the ones normal JavaScript uses, and exposes that -- but it does all of the mangling/bindgen/shim bullshit for you in the background. The shim is unavoidable, and always exists behind the curtain, but this approach lets you completely ignore it. workers-rs doesn't support every API, though (e.g. no R2 support.) In theory, assuming you ported the workers-wasi interface to Rust[3] yourself, you could then write a Worker in Rust using workers-rs that load WASI-conformant WASM programs (written in XYZ) and execute that program on the request object. Sounds confusing but I think you get what I mean.
[1] No, this operation wasn't provided by the WebCrypto API, as far as I'm aware, otherwise I probably wouldn't have bothered with the added complexity.
[2] https://github.com/cloudflare/workers-rs
[3] The underlying WebAssembly support comes from V8; WASI, then, is "just" an implementation of some very well known functions/APIs in the surrounding environment that the WASM program expects to exist, and behave in a certain way. So actually the entire workers-wasi framework is here, and if you ported this TypeScript interface to Rust, using workers-rs, you could invoke any WASI program similarly: https://github.com/cloudflare/workers-wasi/blob/main/src/ind...