This is an archive of the discontinued LLVM Phabricator instance.

[WebAssembly] Ban all TLS on non-emscripten targets (even local-exec)
AbandonedPublic

Authored by sbc100 on Nov 11 2020, 9:04 AM.

Details

Reviewers
sunfish
tlively
Summary

Without this change it's possible for non-emscripten users (e.g. wasi-sdk
users) o end up with TLS usage in their object files. e.g:

$ clang -pthread --target=wasm32-wasi tls_test.c -ftls-model=local-exec

Diff Detail

Event Timeline

sbc100 created this revision.Nov 11 2020, 9:04 AM
Herald added a project: Restricted Project. · View Herald TranscriptNov 11 2020, 9:04 AM
sbc100 requested review of this revision.Nov 11 2020, 9:04 AM
tlively accepted this revision.Nov 11 2020, 9:58 PM
tlively added a subscriber: alexcrichton.

LGTM if we can verify that neither Rust nor WASI use this functionality.

@alexcrichton, do non-Emscripten Rust targets use the current TLS implementation?

This revision is now accepted and ready to land.Nov 11 2020, 9:58 PM

Thanks for the cc! By default rustc doesn't use TLS vars this should be fine. With the atomics feature enabled, however, it does use TLS but I imagine this doesn't affect that?

tlively requested changes to this revision.Nov 12 2020, 10:17 AM

Thanks, Alex! I suspected that might be the case. Follow-up question: What kind of binary compatibility guarantees does Rust have when mixing compiler versions? Would it be a problem for example if we rewrote the TLS mechanism from scratch so that it worked differently in LLVM 12 than it does in LLVM 11?

Sam, I don't think we can land this change because it would prevent Rust from working with tip-of-tree LLVM.

This revision now requires changes to proceed.Nov 12 2020, 10:17 AM

Currently Rust is able to get away with 0 binary compatibility between rustc versions, so if LLVM 12 is entirely different from LLVM 11, that's totally fine by us!

But surely rust doesn't build with +bulk-memory?

The only way that rust could be hitting this code bath is by passing both +bulk-memory and -ftls-model=local-exec` right? ... without and explicit ftls-model rust already hits this error.

Does rust actually support building multi-threaded code? Or do you rely on the TLS / atomics lowering pass?

WASI for sure doesn't support any kind of threading yet.

Currently we specify the TLS model as "local-exec" for non-threaded wasm code, but we never emit thread_local for globals. When the atomics feature is enabled we do use thread_local for globals as needed. Rust does not by default enable bulk-memory and we still rely on users when compiling with atomics to also enable bulk-memory.

We don't have a precompiled target for threads and wasm but we do have support for recompiling the standard library and running the result. There's an example at https://rustwasm.github.io/wasm-bindgen/examples/raytrace.html.

It's also probably worth pointing out that we rely on the atomics lowering pass by default for wasm targets, and only with -Ctarget-feature=+atomics do we disable that.

Currently we specify the TLS model as "local-exec" for non-threaded wasm code, but we never emit thread_local for globals. When the atomics feature is enabled we do use thread_local for globals as needed. Rust does not by default enable bulk-memory and we still rely on users when compiling with atomics to also enable bulk-memory.

Ah so you do actually end up with real TLS variables and in that case you would hit this error if I land this change. Do you have code for setting up TLS on your newly created threads (like emscripten does)?

What triple do you compile with?

We don't have a precompiled target for threads and wasm but we do have support for recompiling the standard library and running the result. There's an example at https://rustwasm.github.io/wasm-bindgen/examples/raytrace.html.

It's also probably worth pointing out that we rely on the atomics lowering pass by default for wasm targets, and only with -Ctarget-feature=+atomics do we disable that.

Currently rustc's threading-in-wasm story is still very DIY in that you're expected to take the low-level primitives that LLD emits and build your own tooling around initializing thread-locals and such. For example in wasm-bindgen we've got code to glue everything together, but that's all wasm-bindgen-specific and there's nothing more general AFAIK in Rust

For compilation we compile with wasm32-unknown-unknown, which is another big drawback of our story today because we don't have a dedicated target for threads, you just have to compile with the right flags. This is a reflection of how under-baked the story is in Rust today. FWIW I'd be happy to change whatever is necessary in rustc since I think we have very few users of threaded-wasm right now. I suspect whatever Emscripten is doing aligns pretty closely with where we'd want to end up!

sbc100 abandoned this revision.Nov 12 2020, 7:18 PM