Martin Natano wrote:
> Hi,
> 
> The add_entropy_words() function performs a right shift by
> (32 - entropy_input_rotate) bits, with entropy_input_rotate being an
> integer between [0..31]. This can lead to a shift of 32 on a 32 bit
> value, which is undefined behaviour in C. The standard says this: "If
> the value of the right operand is negative or is greater than or equal
> to the width of the promoted left operand, the behaviour is undefined."
> In our case the value is 32 and the width of the promoted left operand
> is 32 too, thus the behaviour is undefined.
> 
> As a matter of fact the expression doesn't yield the (probably) expected
> result of 0 on i386 and amd64 machines. The reason being, that the shift
> exponent is truncated to 5 bits on x86.
> 
> natano@obsd:~$ uname -a
> OpenBSD obsd.my.domain 5.9 GENERIC.MP#1862 amd64
> natano@obsd:~$ cat test.c
> #include <stdio.h>
> 
> int
> main(void)
> {
>         unsigned int x = 0xffffffff;
>         printf("x >> 32: 0x%x\n", x >> 32);
>         return 0;
> }
> natano@obsd:~$ cc test.c
> test.c: In function 'main':
> test.c:7: warning: right shift count >= width of type
> natano@obsd:~$ ./a.out
> x >> 32: 0xffffffff
> natano@obsd:~$
> 
> On the other hand ppc truncates the shift exponent to 6 bits. (I didn't
> try it, but
> http://blog.llvm.org/2011/05/what-every-c-programmer-should-know.html
> says so).
> 
> In the specific instance below, the differing behaviour between x86 and
> pcc doesn't matter, because of the equality (x | x) == (x | 0) == x.
> 
> However, I think it might be still worth fixing this, because we can't
> rely on future versions of gcc and other compilers retaining this
> behaviour. The behaviour is undefined, so the compiler can do whatever
> it wants (insert obligatory reference to nasal demons here).
 
I think we don't mix declarations and code.
Would this be an option?

diff --git a/dev/rnd.c b/dev/rnd.c
index 819ce0d..0f57b1b 100644
--- a/dev/rnd.c
+++ b/dev/rnd.c
@@ -421,7 +421,7 @@ add_entropy_words(const u_int32_t *buf, u_int n)
 
        for (; n--; buf++) {
                u_int32_t w = (*buf << entropy_input_rotate) |
-                   (*buf >> (32 - entropy_input_rotate));
+                   (*buf >> ((32 - entropy_input_rotate) & 31));
                u_int i = entropy_add_ptr =
                    (entropy_add_ptr - 1) & POOLMASK;
                /*
 
> Index: dev/rnd.c
> ===================================================================
> RCS file: /cvs/src/sys/dev/rnd.c,v
> retrieving revision 1.178
> diff -u -p -u -r1.178 rnd.c
> --- dev/rnd.c 8 Jan 2016 07:54:02 -0000       1.178
> +++ dev/rnd.c 31 Jan 2016 10:11:17 -0000
> @@ -420,8 +420,9 @@ add_entropy_words(const u_int32_t *buf, 
>       };
>  
>       for (; n--; buf++) {
> -             u_int32_t w = (*buf << entropy_input_rotate) |
> -                 (*buf >> (32 - entropy_input_rotate));
> +             u_int32_t w = *buf << entropy_input_rotate;
> +             if (entropy_input_rotate > 0)
> +                     w |= *buf >> (32 - entropy_input_rotate);
>               u_int i = entropy_add_ptr =
>                   (entropy_add_ptr - 1) & POOLMASK;
>               /*
> 
> cheers,
> natano
> 

Reply via email to