Why is glibc's __random_r assigning variables it immediately overwrites?

4

I was looking for the source for glibc's rand() function, which an answer here links to.

Following the link, I'm puzzled about the code for the __random_r() TYPE_0 branch:

int32_t val = state[0];
val = ((state[0] * 1103515245) + 12345) & 0x7fffffff;
state[0] = val;
*result = val;

What is the point of the val variable, getting assigned and then immediately overwritten? The random_data struct that holds state is nothing unusual.

As one would expect, compiling with -O2 on godbolt gives the same code if you just eliminate val. Is there a known reason for this pattern?


UPDATE: This seems it was an aberration in the version linked to from that answer, I've updated the links there to the 2.28 version. It might have been something that was done temporarily to aid in debugging by making the contents of state[0] easier to see in a local watchlist?

c
random
glibc

1 Answer

1

Wow, that is indeed some unbelievable garbage code.

There is no justification for this.

And not only is initialization of val not needed, the fact is that state[0] is an int32_t, and multiplication by 1103515245 will trigger undefined behaviour in GCC (integer overflow) on any platform with 32-bit ints (= basically every one). And GCC is the compiler most often used to compile Glibc.


As noted by HostileFork, the code in more recent 2.28 reads:

int32_t val = ((state[0] * 1103515245U) + 12345U) & 0x7fffffff;
state[0] = val;
*result = val;

With this, not only is the useless initialization removed, but the U suffix makes the multiplication happen with unsigned integers, avoiding undefined behaviour. The & 0x7fffffff ensures that the resulting value fits into an int32_t and is positive.

answered on Stack Overflow Nov 11, 2018 by Antti Haapala • edited Nov 11, 2018 by Antti Haapala

User contributions licensed under CC BY-SA 3.0