Closed
Description
Currently, task-local data (TLS) is implemented by keying off the code pointer of a closure that takes the desired type as its argument. You use it like this:
fn my_tls_key(+_x: @my_type) { }
local_data_set(my_key, value);
assert local_data_get(my_key).get() == my_value; // can be in a different function or module
This has three known flaws:
- As per Move std::test into core or change the way coretest works #2912, TLS may randomly fail to retrieve values if used in coretest test cases if the other access is done in core itself.
- On windows, TLS does not work cross-crate because of the way linking is done.
- It has to be marked 'unsafe' because you could instantiate a polymorphic function at multiple types for easy type coercion.
An alternative proposal would be to key off the address of a global constant. A couple issues to address:
- Shouldn't have to provide an inhabitant of the type to generate the key (maybe inhabitants can only be generated at runtime). Hence, use an empty vector:
const my_key: &[my_type] = [];
- Shouldn't allow an attacker to collide addresses by having differently-typed vectors on multiple stack frames. This would be solved by requiring the pointer to have the
static
region.type local_data_key<T> = &static/[T];
- Finally, we should make sure that LLVM does not fold constants that are identical into each other. If you write
const key1: &[my_type] = [], key2: &[my_type] = [];
in order to have two different TLS slots to store the same type, then they shouldn't "accidentally" end up with the same data address and overwrite each other.
This last, 3rd point is really the major thing blocking this bug being easy. May require a special attribute to tell llvm not to put it in rodata.
I wrote more about this here: http://bubblingbeebles.livejournal.com/111016.html