From: Arnd Bergmann <arnd@arndb.de>
To: Cliff Wickman <cpw@sgi.com>
Subject: Re: libnuma on big-endian 64-bit systems
Date: Tue, 20 Jan 2009 20:49:31 +0100

Sorry for the long delay. I have now been able to work on this a bit
and come up with a not so broken version of the read_mask function.
The patch you have in 2.0.3-rc1 did not fix the original problem,
but also introduced other bugs, so please revert it.

This is the best I could come up with, haven't tested on little-endian
though because I lack appropriate hardware.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>

 libnuma.c |   40 ++++++++++++++++++++++------------------
 numaint.h |    1 +
 2 files changed, 23 insertions(+), 18 deletions(-)

Index: numactl-dev/libnuma.c
===================================================================
--- numactl-dev.orig/libnuma.c
+++ numactl-dev/libnuma.c
@@ -368,11 +368,10 @@ static int
 read_mask(char *s, struct bitmask *bmp)
 {
 	char *end = s;
-	unsigned int *start = (unsigned int *)bmp->maskp;
-	unsigned int *p = start;
-	unsigned int *q;
-	unsigned int i;
-	unsigned int n = 0;
+	int tmplen = (bmp->size + bitsperint - 1) / bitsperint;
+	unsigned int tmp[tmplen];
+	unsigned int *start = tmp;
+	unsigned int i, n = 0, m = 0;
 
 	i = strtoul(s, &end, 16);
 
@@ -380,7 +379,6 @@ read_mask(char *s, struct bitmask *bmp)
 	while (!i && *end++ == ',') {
 		i = strtoul(end, &end, 16);
 	}
-	end++; /* past the , */
 
 	if (!i)
 		/* End of string. No mask */
@@ -388,33 +386,39 @@ read_mask(char *s, struct bitmask *bmp)
 
 	start[n++] = i;
 	/* Read sequence of ints */
-	do {
+	while (*end++ == ',') {
 		i = strtoul(end, &end, 16);
-		if (i)
-			start[n++] = i;
-	} while (*end++ == ',');
-	n--;
+		start[n++] = i;
+
+		/* buffer overflow */
+		if (n > tmplen)
+			return -1;
+	}
 
 	/*
 	 * Invert sequence of ints if necessary since the first int
 	 * is the highest and we put it first because we read it first.
 	 */
-	for (q = start + n, p = start; p < q; q--, p++) {
-		unsigned int x = *q;
+	while (n) {
+		int w;
+		unsigned long x = 0;
+		/* read into long values in an endian-safe way */
+		for (w = 0; n && w < bitsperlong; w += bitsperint)
+			x |= ((unsigned long)start[n-- - 1] << w);
 
-		*q = *p;
-		*p = x;
+		bmp->maskp[m++] = x;
 	}
+	m--;
 
 	/* Poor mans fls() */
-	for(i = 31; i >= 0; i--)
-		if (test_bit(i, start + n))
+	for(i = bitsperlong - 1; i >= 0; i--)
+		if (test_bit(i, bmp->maskp + m))
 			break;
 
 	/*
 	 * Return the last bit set
 	 */
-	return ((sizeof(unsigned int)*8) * n) + i;
+	return bitsperlong * m + i;
 }
 
 /*
Index: numactl-dev/numaint.h
===================================================================
--- numactl-dev.orig/numaint.h
+++ numactl-dev/numaint.h
@@ -33,5 +33,6 @@ enum numa_warn {
 
 #define howmany(x,y) (((x)+((y)-1))/(y))
 #define bitsperlong (8 * sizeof(unsigned long))
+#define bitsperint (8 * sizeof(unsigned int))
 #define longsperbits(n) howmany(n, bitsperlong)
 #define bytesperbits(x) ((x+7)/8)
