NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

bin/59522: jot random seed handling relies upon undefined float to integer conversion



>Number:         59522
>Category:       bin
>Synopsis:       jot random seed handling relies upon undefined float to integer conversion
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    bin-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Wed Jul 09 06:45:00 +0000 2025
>Originator:     matthew green
>Release:        10.1 or so
>Organization:
>Environment:
evbmips64eb.  i also heard it affects evbarmv7.
>Description:
i noticed that jot -r output was identical for different runs where the
-r option is supposed to generate random data.

eventually i tracked this down to the way the random seed is generated
by default.  this first bit is the initialisation of 'step':

static double   step = STEP_DEF;
...
        if (randomize) {
                /* 'step' is the seed here, use pseudo-random default */
                if (!(have & STEP))
                        step = time(NULL) * getpid();

'step' is them passed into srandom(3):

                srandom((unsigned long) step);

note that this is also converted to unsigned int via srandom prototype.
on x86 and most platforms, this conversion from double -> 32-bit int
provides the lower 32-bits that would be set in the converted value, 
but on evbmips64-eb, the value is saturated, and so srandom() is passed
2^32-1 in all cases, as getpid() will be more than 2, and time(NULL)
will be more than 1/3rd of 32-bits (the range from pid 3 to pid 30000
here is 5254448208 to 52544482080000, clearly well beyond what can be
represented in a 32-bit value.)


as far as i can tell, depending on whether something is handled by the
builtin conversions, or via some libgcc/etc function, the result may
be even different on the same platform, as GCC and compiler-rt don't
agree about it always.

unfortunately, this conversion is undefined behaviour (C11):

6.3.1.4 Real floating and integer
When a finite value of real floating type is converted to an integer type other than _Bool,
the fractional part is discarded (i.e., the value is truncated toward zero). If the value of
the integral part cannot be represented by the integer type, the behavior is undefined.
>How-To-Repeat:
run "jot -r 1 0 21600" on a platform with the problem.
see the same output always.
>Fix:
since the seed is 32 bits, and the "step" range is basically between 30,000 * <latest epoch value>, this fits comfortably into a 64-bit
value for the next few millennia and beyond, i think the simplest
fix here is to change the srandom() call to:

   srandom((unsigned int)(unsigned long long)step);

which works in my testing.


i couldn't find a good way to perform this truncation directly without
some sort of loop, otherwise i'd do that..



Home | Main Index | Thread Index | Old Index