Skip to contentSkip to conversation

m68k: Patch for broken lsl64() "old code" with incorrect shift

PATCH In review Jonathan Elchison 2 participants 3 messages Jun 11, 2011

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 m68k: Patch for broken lsl64() "old code" with incorrect shift

[1.] One line summary of the problem:

[PATCH] m68k: Patch for broken lsl64() "old code" with incorrect shift

[2.] Full description of the problem/report:

In arch/m68k/math-emu/multi_arith.h, lsl64() doesn't calculate a correct HI_WORD(*dest) when count < 32, due to an incorrect shift operation. This line:

    HI_WORD(*dest) = (HI_WORD(*dest) << count) | (LO_WORD(*dest) >> count);

...should be...

    HI_WORD(*dest) = (HI_WORD(*dest) << count) | (LO_WORD(*dest) >>

(32 - count));

This function is ifdef'd out, marked as "old code". However, I fell into the same trap into which I suspect others have fallen (or will fall): On rare occasion when I need to implement my own library functions, I depend on the Linux kernel to provide solid code. This bug, albeit in old code, led me astray.

I'm asking that this old code (lsl64) be corrected or removed.

[3.] Keywords (i.e., modules, networking, kernel):

kernel, arch, m68k, math-emu, multi_arith.h, lsl64

[4.] Kernel information

2.6.39.1

[5.] Most recent kernel version which did not have the bug:

Unknown

[6.] Output of Oops.. message (if applicable) with symbolic information resolved (see Documentation/oops-tracing.txt)

N/A

[7.] A small shell script or example program which triggers the problem (if possible)

-----------------------------------------------------------------
#include <stdio.h>

#define LO_WORD(ll) (((unsigned int *) &ll)[1])
#define HI_WORD(ll) (((unsigned int *) &ll)[0])

static inline void lsl64_broken(int count, unsigned long long *dest)

{
	if (count < 32) {
		HI_WORD(*dest) = (HI_WORD(*dest) << count)
		    | (LO_WORD(*dest) >> count);
		LO_WORD(*dest) <<= count;
		return;
	}
	count -= 32;
	HI_WORD(*dest) = LO_WORD(*dest) << count;
	LO_WORD(*dest) = 0;
}

static inline void lsl64_fixed(int count, unsigned long long *dest)

{
	if (count < 32) {
		HI_WORD(*dest) = (HI_WORD(*dest) << count)
		    | (LO_WORD(*dest) >> (32 - count));
		LO_WORD(*dest) <<= count;
		return;
	}
	count -= 32;
	HI_WORD(*dest) = LO_WORD(*dest) << count;
	LO_WORD(*dest) = 0;
}

static inline void lsr64(int count, unsigned long long *dest)

{
	if (count < 32) {
		LO_WORD(*dest) = (LO_WORD(*dest) >> count)
		    | (HI_WORD(*dest) << (32 - count));
		HI_WORD(*dest) >>= count;
		return;
	}
	count -= 32;
	LO_WORD(*dest) = HI_WORD(*dest) >> count;
	HI_WORD(*dest) = 0;
}

int main( void )

{
	long long testVal = 0x0000100000001000L;
	long long testVal_broken = testVal;
	long long testVal_fixed = testVal;
	
	printf( "begin testVal_broken =\t\t0x%016llx\n", testVal_broken );
	lsr64( 1, &testVal_broken );
	printf( "intermediate testVal_broken =\t0x%016llx\n", testVal_broken );
	lsl64_broken( 1, &testVal_broken );
	printf( "final testVal_broken =\t\t0x%016llx\n", testVal_broken );
	printf( "final matches begin?\t\t%s\n", testVal_broken == testVal ?

"TRUE" : "FALSE" );

	printf( "\nbegin testVal_fixed =\t\t0x%016llx\n", testVal_fixed );
	lsr64( 1, &testVal_fixed );
	printf( "intermediate testVal_fixed =\t0x%016llx\n", testVal_fixed );
	lsl64_fixed( 1, &testVal_fixed );
	printf( "final testVal_fixed =\t\t0x%016llx\n", testVal_fixed );
	printf( "final matches begin?\t\t%s\n", testVal_fixed == testVal ?

"TRUE" : "FALSE" );

	return 0;
}

-----------------------------------------------------------------

[8.] Environment

Found via code inspection

[9.] Patch

-----------------------------------------------------------------
diff -up linux-2.6/arch/m68k/math-emu/multi_arith.h linux-2.6_orig/arch/m68k/math-emu/multi_arith.h
--- linux-2.6/arch/m68k/math-emu/multi_arith.h 2011-06-10
22:50:32.538711320 -0400
+++ linux-2.6_orig/arch/m68k/math-emu/multi_arith.h 2011-06-10
22:47:43.407285452 -0400
@@ -236,7 +236,7 @@ static inline void lsl64(int count, unsi
{
if (count < 32) {
HI_WORD(*dest) = (HI_WORD(*dest) << count)
- | (LO_WORD(*dest) >> (32 - count));
+ | (LO_WORD(*dest) >> count);
LO_WORD(*dest) <<= count;
return;
}
-----------------------------------------------------------------

[10.] Responses

Please personally CC me on responses to this post.

--
Jonathan Elchison
[email protected]

#1 lore raw
Quoted 11 lines · Jonathan Elchison

In arch/m68k/math-emu/multi_arith.h, lsl64() doesn't calculate a correct HI_WORD(*dest) when count < 32, due to an incorrect shift operation.  This line:

   HI_WORD(*dest) = (HI_WORD(*dest) << count) | (LO_WORD(*dest) >> count);

...should be...

   HI_WORD(*dest) = (HI_WORD(*dest) << count) | (LO_WORD(*dest) >> (32 - count));

Quoted 7 lines

This function is ifdef'd out, marked as "old code".  However, I fell into the same trap into which I suspect others have fallen (or will fall):  On rare occasion when I need to implement my own library functions, I depend on the Linux kernel to provide solid code.  This bug, albeit in old code, led me astray.

I'm asking that this old code (lsl64) be corrected or removed.

I think it's better to just remove all #ifdefed out parts in the code.

Quoted 7 lines

diff -up linux-2.6/arch/m68k/math-emu/multi_arith.h linux-2.6_orig/arch/m68k/math-emu/multi_arith.h
--- linux-2.6/arch/m68k/math-emu/multi_arith.h  2011-06-10 22:50:32.538711320 -0400
+++ linux-2.6_orig/arch/m68k/math-emu/multi_arith.h     2011-06-10 22:47:43.407285452 -0400

Review static inline void lsl64(int count, unsi · line 242

Quoted 8 lines
(quoted diff) +1 -1
@@ -236,7 +236,7 @@ static inline void lsl64(int count, unsi
  {
        if (count < 32) {
                HI_WORD(*dest) = (HI_WORD(*dest) << count)
-                   | (LO_WORD(*dest) >> (32 - count));
+                   | (LO_WORD(*dest) >> count);
                LO_WORD(*dest) <<= count;
                return;
        }

The patch is reversed?

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- [email protected]

In personal conversations with technical people, I call myself a hacker. But when I'm talking to journalists I just say "programmer" or something like that. -- Linus Torvalds

#2 lore raw
Quoted 1 line · Geert Uytterhoeven

I think it's better to just remove all #ifdefed out parts in the code.

I'm good either way, as long as the broken "old code" is no longer present.

Quoted 1 line

The patch is reversed?

My apologies, you're correct. In case anyone is interested in the correct patch:

-----------------------------------------------------------------
diff -up linux-2.6_orig/arch/m68k/math-emu/multi_arith.h linux-2.6/arch/m68k/math-emu/multi_arith.h
--- linux-2.6_orig/arch/m68k/math-emu/multi_arith.h 2011-06-10
22:47:43.407285452 -0400
+++ linux-2.6/arch/m68k/math-emu/multi_arith.h 2011-06-10
22:50:32.538711320 -0400
@@ -236,7 +236,7 @@ static inline void lsl64(int count, unsi
{
if (count < 32) {
HI_WORD(*dest) = (HI_WORD(*dest) << count)
- | (LO_WORD(*dest) >> count);
+ | (LO_WORD(*dest) >> (32 - count));
LO_WORD(*dest) <<= count;
return;
}
-----------------------------------------------------------------

Please personally CC me on responses to this post.

v/r,

--
Jonathan Elchison
[email protected]