LanguagesArchitecture

Vale brings a lot of innovations to the table to make coding safe.

  • Hybrid-generational memory is memory safe, allowing zero unsafety in any Vale code.
  • Vale makes sure no two threads can reach an object at the same time.
  • With extern isolation, calling into C cannot cause Vale code to crash.

This page describes Vale's design, but it's still a work in progress. See the annotations for whether something's ready or not.

Memory Safety 0

All of today's native languages require some unsafe user code to function. For example, in C, you can bring in a library that causes mysterious crashes in other parts of your program, because there are no protections in C.

Rust does especially well here, though its guarantees are somewhat weakened by its unsafe keyword. Most think that memory unsafety can only happen inside unsafe blocks, but unfortunately, unsafe blocks can cause safe Rust code to trigger undefined behavior as well.

Vale uses hybrid-generational memory, which doesn't require any unsafe, even in its standard library.

Vale goes even further, by isolating all unsafe memory from safe memory. Even if we call into C, there's no way for accidental bugs there to trigger memory unsafety in Vale. 1

Safe Concurrency 2

Vale's design has seamless, fearless, structured concurrency to allow us to safely read existing data while doing fork-join parallelism.

When doing manual parallelism, one can either:

  • Use an iso object to send an object to another thread with zero cost.
  • "Transmigrate" an object, conceptually destroying and recreating it in the other thread. 3

Safe Externs 4

Vale can call into C code (and vice versa). So how does it maintain its safety guarantees? By using what we're calling extern isolation.

The behavior when sending an object into C depends on the object's mutability. 5

  • When we send a mutable struct (or interface) into C code, we only send a "scrambled" handle, one that C cannot read. We can then give that handle into functions to get or set any fields.
    • When coming back from C, the receiving thread does an O(1) check to make sure it's still alive and it still belongs to this thread.
  • When we send an immutable struct (or interface) into C code (or receive it from C code), we deeply copy it, right then.
    • If this is too expensive, one can wrap it in a mutable struct and have the C code interact through that instead.

This means that any bugs in our C code won't affect our Vale code. If we want to protect against not only bugs but maliciously written C code, we can "sandbox", by sending all of our extern calls across an IPC channel to another process. However, it's recommended to never run arbitrary untrusted code.

Dependency Extern Whitelisting 6

When Vale's package manager is ready, the user will have to whitelist every single dependency that wants to call into extern code.

This way, we can be more certain that none of our dependencies are making surprising extern calls.

Side Notes
(interesting tangential thoughts)
0

Vale is memory safe today via generational memory! Hybrid-generational memory is a planned optimization on top of that.

1

This is talking about accidental bugs because this is not a security feature. It's only meant as a debugging tool, because these protections can be worked around with some effort.

2

Safe concurrency is in the design, but not implemented yet. Stay tuned!

3

This isn't as expensive as one might think. We use a combination of assertions and generation increments to guarantee no further accesses from the source thread, and even those are often elided.

4

Safe externs are nearing completion. Everything in this section is done, except the handle scrambling and sandboxing option. Stay tuned!

5

As described in Structs / Mutability, a struct can either be mutable or immutable.

6

Vale doesn't have a package manager yet. Stay tuned!