Opt in leak thread on panic

Today the only way to handle a thread panicking is by unwinding and catching. Can we add a second option, which will leak the thread on panic, while not doing any unwinding.

That leaking can be basically equipment to loop {}. Unfortunately, due to Pin guarantees we can't actually free the stack, so can indeed loop { std::thread::park(} } on std targets and just call panic handler (maybe another one?) on no_std targets.

It will be good middle ground between panic=unwind and panic=abort: web servers would still be able to recover from threads panicking without using catch_unwind, as well as other use cases.

It will be a step towards linear/unleakable types and many async features like scope, as their main problem is unwind, while not everyone wants to accept the whole program aborting if linear type is around during unwind.

Please only put topics into "Unsafe Code Guidelines" if it is about how people write unsafe code. As far as I can see, your topic does not fit into the UCG category, it's a general language design proposal.

One of the goals of unleakable types is to prevent leaks. Your proposal will create a huge amount of extra leaks, in processes that panic. So your proposel seems to be diametrically opposed to the goals of unleakable types.

1 Like

I removed ucg label.

I use unleakable types as those where destructor cannot be skipped before continuing execution. If thread is leaked that way, then it is not "that" leak - those are different leaks.

let foo = 42;
let bar = &foo;
core::mem::forget(bar);

// Foo is not borrowed anymore, `foo` can be used again

let foo = 42;

scope(|s| {
  s.spawn(|| {
    let bar = &foo;
    panic_leaking();
  });
});

// foo is unusable, *safety* guarantee

It would leak memory and eventually cause a hard abort anyway due to running out of memory as well as cause deadlocks when you share any mutex between threads. Unwinding normally prevents deadlocks on panics by unlocking all mutexes (and poisoning them). If unwinding doesn't happen, all mutexes will remain locked forever and any other threads that may want to access the same data will deadlock.

2 Likes

Yes, but leaking panics are should be opt-in and used to enforce memory safety, notifying main thread somehow. Today there are 0 methods to enforce memory safety in a lot of situations requiring liveness guarantees.

If anything leaking threads would have less liveness than panic=unwind because it will deadlock in many cases. Also you can already implement this yourself if you really want:

std::panic::set_hook(|info| {
    panic_notifier.send(info).unwrap();
    loop { std::thread::park(); }
});

As for scope I'm pretty sure you will have to make the thread that called scope itself leak whenever one of the scoped threads leaked as otherwise you could get access to all variables that were borrowed by scoped threads after scope returns.

1 Like

To put my proposal in context:

If there is linear type in the thread and there is a panic, you can only abort the program. That proposal will add another option.

That panic hook looks great, but I'm not sure whether it will affect all threads or only one? If only one, then use case is solved - thank you very much! That way argument against linear types is reduced, as workloads that need to recover from panics can be compatible with them.

Panic hooks are global, though inside of a panic hook you can read a thread local variable to determine if it should unwind or leak.