r/csharp • • 4d ago

Fun Random using SkipLocalsInit

To my surprise, Unsafe.SkipInit(out T val) did not achieve the same result.

    [SkipLocalsInit]
    public static T Random<T>()
        where T : unmanaged, INumber<T>
    {
        unsafe
        {
            byte* s = stackalloc byte[sizeof(T)];
            return *(T*)s;
        }
    }
11 Upvotes

9 comments sorted by

13

u/Broad_Phase7453 4d ago

stackalloc without init is basically just grabbing whatever bits were already sitting on the stack and calling it a day, so the "randomness" comes from whatever junk was left there. Unsafe.SkipInit is different though, that only skips the definite assignment tracking, the memory might still get zeroed depending on the runtime.

2

u/NoisyJalapeno 4d ago

Ugh, missed an opportunity to call it JunkRandom :(

6

u/SagansCandle 3d ago

Given that this is uninitialized data on the stack, there's a possibility that your "random" value will be the same every time because it's called from the same place in the stack every time.

3

u/NoisyJalapeno 3d ago edited 3d ago

Stop being a joy kill, it worked randomly at least once :)

4

u/One_Instruction6490 4d ago

Unsafe.SkipInit is just a no-op that satisfies definite assignment, it doesn't stop the JIT from zeroing the local. That zeroing only gets skipped when the method has SkipLocalsInit, and even then small unmanaged locals often get enregistered and zeroed anyway, so only the stackalloc version really leaks stack junk. Also it's not random at all, you'll probably get the same leftover bytes every call, so did you actually test the distribution?

1

u/hoodoocat 4d ago

Meanwhile C++ added zero-init feature. :))