50 comments

[ 4.1 ms ] story [ 54.2 ms ] thread
Scrolled all the way through; very impressive.

> We have implemented (fully or partially) 48 POSIX Functions from above. ...[however] These 24 POSIX Functions will Halt when TCC WebAssembly calls them…

I was just wondering this evening: I have seen WASM described as an environment for selectively subsetting interfaces, in part for security. Is the following sometimes done?: Compile and link to a "glibc" which implements only a subset of calls, again for runtime security?

Statically linking with musl and enabling LTO sounds like what you’re looking for.
That's basically what WASI is about (or now the specific derivation called WASIX). Essentially a POSIX runtime for WASM, but typically using musl instead of glibc.
A few months ago Wasmer tried add WASIX support to Zig so anything on Zig ecosystem could target the browser easily, which is quite relatable of what the TCC compiler is trying to achieve. I'm sure at some moment the community will pick it up.

I'll drop a link to WASIX in case is useful for the reader!

https://wasix.org

As usual, comment out all the error handling code. Also my experience with WASM.
Recently I created C compiler directly in TypeScript [1]. Maybe it is not super fast but at least adding new backends is much easier.

[1] https://github.com/Mati365/ts-c-compiler

This is super cool. I'm also trying to write a C compiler but in Rust and it's difficult.
I fail to see why zig had to be introduced, with Emscripten being there, other than "I want to use zig".
Zig is going to be the new Rust for some people
Except it is being used here as a wrapper for C and C++ clang packaging.

Also as remark, Zig is going to be the new Modula-2, with revamped syntax for C minded folks, and compile time support.

Assuming it takes off post 1.0, still a long to go in the adoption chasm graph.

I'm sorry to inform, but the new Modula-2 is already Nim, isn't it?
Not really, that is more like a compiled Python.
It's like saying a lizard is closer to a table than to a snake, because it has legs.
But he is saying it’s closer to a snake though...?
Zig is not memory safe.
Is it memory safe enough and if it helps mitigating other kinds of errors without being in the way. It will find its place in the programming world.

I think what zig really needs is something like the rust Axum ecosystem for web backend development. I would never be able to make a zig case at work without those sort of frameworks. People would say why zig without web related packages when you also have GOlang.

A recipe for CVE waiting to happen, plugging a memory-safe-enough into the Internet, for someone to take advantage of a UAF that wasn't tested.
The browser's WASM runtime is already a safe sandbox. There's really not much point in 'double sandboxing' both on the language and runtime level.
If that is the only place Zig is ever going to be used, then no worries, I guess.

WebAssembly sandboxes apparently are going to sort out all security issues in modern computing.

In order to be useful, a sandboxed program needs to communicate with the environment (the equivalent of system calls). If you can corrupt internal state, you can control the arguments to those calls, which may have security implications.

For example, if you corrupt a program that's allowed to use web sockets, you'll be able to port scan the user's local network.

If that actually works in a browser wasm environment then it's also possible from Javascript, which is a memory safe language (eg either the sandbox works or it doesn't, that also includes the external APIs).
Sure. Under that perspective, it's basically a new vector for XSS attacks.
You can still have memory safety bugs in WASM. The difference is that they can only do memory unsafe things within the sandbox. That's better than nothing but still not as good as actual memory safety.
From a security pov it doesn't make a difference though, the sandbox needs to be able to safely contain untrusted code, no matter if the code is riddled with memory bugs or not.
How do you figure? Imagine a server component that runs in wasm (pretty common). Memory safety bugs could easily lead to information leaks and privilege bypass entirely within the wasm sandbox.
The important part is within the wasm sandbox. Don't run multiple components in the same WASM instance because they can't be properly isolated from each other.

That's why traditional operating systems have processes that can't access each others memory. WASM instances don't have this sort of "internal isolation", anything running in the same instance can access all memory in that instance, memory safe language or not.

Again, language-level safety doesn't matter here. It makes a lot of sense to write the sandbox itself in Rust, but it must not matter whether code running inside the sandbox is written in Rust. If that would be required, the sandbox has already failed.

Again, language-level safety doesn't matter here

It very well can:

For example, let's assume you have a graphics editor running in the browser that stores files in the cloud. If it uses a vulnerable C library to decode image data, an attacker might be able to play havoc with your files despite the sandbox never technically having been breached.

This can be mitigated by either using a safe language, or having the decoder run in an isolated wasm instance. Either way, you have to design your application with these considerations in mind and can't just take arbitrary, potentially vulnerable applications, compile them to wasm and be done with it.

The worst that can happen is that the image tool saves back a corrupted image. But that's also possible with a buggy (but memory safe) Rust image loader/saver, memory safety doesn't automatically fix all classes of bugs.

Apart from that it would be quite a feat to use internal memory corruption for anything useful in WASM, because both the code and callstack live outside the sandbox and are not accessible from within (e.g. tricks like return-oriented programming are not possible in WASM.

https://www.youtube.com/watch?v=glL__xjviro&t=450s

Instead of popping up an alert, you could have requested the deletion of all files in the cloud storage.

Thanks for the link, very interesting! But TBF: the 'host program' has to be written in a very specific way to allow that rogue Javascript execution, it's very similar to allowing an SQL injection to happen.

I also wonder why stack canaries wouldn't work on WASM, since the compiler creates stack frames on the data-only stack just the same (but maybe Clang's `-fstack-protector` doesn't work for some reason in WASM, I'll actually need to check that).

You're talking about compartmentalisation which is still just a proposal (wasm component model). You can't use it yet.
> Is it memory safe enough

I'd say for the vast majority of use cases, it is.

Pluggable allocators + good test coverage make it trivial to catch a lot of the more common memory issues and exhaustive switches are quite robust (though it can be tricky when the branches vary according to the target platform).

Also, it is far easier to code in an exploratory, iterative fashion in Zig than it is in Rust.

Overall, I think with Zig and Go you can cover a lot of programming use cases. In fact, I find Go to be pretty damn fast out-of-the-box and in a lot of real world scenarios can match Zig/Rust (production builds). All three have room for fine tuning (at the expense of readability), though of course the ceiling is much higher in Zig and Rust.

Not to mention, Rust won't protect you from logic issues, you can definitely do the wrong thing correctly.

For some of the biggest C++ use cases, video games and HFT, this absolutely doesn't matter.
Why use a custom compiler for one specific target when you could have a single compiler that support any target you want? It doesn’t look like emscripten has an integrated build system either?

I think that’s the genius of Zig.. one of the main goals is to build a better and faster C compiler. It might end up being the only C compiler with really solid hot-swapping support. And then if you’re already using the compiler you might as well start using the language too.

clang also supports cross compiling.

Sometimes I wonder how much people nowadays actually bother to learn about compiled languages.

The Zig compiler bundles the SDKs of supported targets while Clang does not, so you can cross compile out of the box without any extra steps. It also defines targets for various GLIBC versions which AFAICT Clang does not.
It is so hard to install additional OS packages.
Did you actually try it? Across Windows, Linux and macOS? Setting up a vanilla Clang toolchain for cross-compilation is by far not as trivial as you make it sound.
You mean like cross compiling from Windows to Symbian, Windows CE/Pocket PC, Palm, Android, PlayStation, Nintendo, XBox?

It is not a walk in the park, but it hardly a task only worthy of Hercules.

Nobody said it was a task only worthy of Hercules. Just that it is a royal pain, and Zig removes that pain. You asked "why zig?". That's your answer.
And then did you try the same on Linux and macOS? That's what the Zig toolchain gives you, it doesn't lock you into a specific OS.
Yeah, and zig solves that. Instead of installing, trying the right header files, you just untar 70mb and you are good to go.
There is a heck of a lot to be said for making it a painless process. Yes, you can cross compile C and C++. No, it is not at all simple to set up. I've used rust for projects for similar reasons: if I want to cross compile from windows to linux it is ridiculously less painful to compile pure rust than C or C++ (especially if I want to set up a new machine for it).
One reason is that the Zig toolchain has fewer "moving parts" than the Emscripten toolchain (e.g. Emscripten depends on Node.js, Python, the Google Closure compiler with an embedded Java runtime, and various WABT tools), and while all these tools are installed automatically by the Emscripten SDK installer, it's still a lot of individual parts that can break.

OTH the Clang compiler doesn't come with the necessary cross-compilation C library and headers.

From that pov, the Zig toolchain is indeed the best option to compile a WASM blob that's not WASI (in that case, there's also the WASI SDK, which is a similar self-contained toolchain as the Zig toolchain) - PS: Zig can also compile to WASI out of the box though.

Just one toolchain to install in order to compile to the native CPU, using any glibc version, to other architectures, and, for WebAssembly, to any variant (emscripten, freestanding, WASI). Zig a very common way to compile C/C++ code to WASI and the only one that can optimize it for a given runtime.

Same, consistent tools and versions everywhere. No need to have 10 different LLVM copies on your system.

Plus, the toolchain already includes a build system, a package manager, a cache, a way to run tests, etc.

Because it's the new cool tech.
Because the author chose zig.
Not only we have a compiler but we have a full blown IDE in the browser: try.moonbitlang.com