gcc 2.7.2 common subexpression bug with possible kernel implications

Tom May (ftom@netcom.com)
Wed, 10 Apr 1996 10:49:59 -0700


Hi,

I just sent a bug report and patch to bug-gcc concerning a problem in
gcc 2.7.2 common subexpression elimination that has possible
implications in the linux kernel. Until it is fixed, I would
recommend compiling with the "-fno-cse-skip-blocks" switch. This bug
may exist in earlier compilers also, but I don't know for sure.

Here's the explanation and example I submitted, which was originally
from the linux kernel but has been pared down extremely to make the
bug easier to find. I found this bug while compiling a version of the
kernel that I had been tweaking, so I don't know if it breaks the real
kernel, but the potential is certainly there.

Explanation: The common subexpression elimination code is currently
ignoring clobbers of "memory" in __asm__ constructs which occur in
skipped blocks (e.g., inside an `if'). I'm using gcc 2.7.2 configured
with "./configure --prefix=/usr i486-linux", for this example, but
this is an architecture-independent problem.

Example: The test for `p->len == 0' is being deleted by cse because of
the `p->len = 0' a few lines earlier. This is incorrect, because
__memcpy() may clobber that memory.

extern inline void * __memcpy(void * to, const void * from, unsigned n)
{
__asm__ __volatile__(
"cld\n\t"
"rep ; movsl\n\t"
"testb $2,%b1\n\t"
"je 1f\n\t"
"movsw\n"
"1:\ttestb $1,%b1\n\t"
"je 2f\n\t"
"movsb\n"
"2:"
:
:"c" (n/4), "q" (n),"D" ((long) to),"S" ((long) from)
: "cx","di","si","memory");
return (to);
}

struct thing {
int len;
int data;
};

void spud (struct thing *in, int copy)
{
unsigned char buf[sizeof(struct thing)+40];
struct thing * p = (struct thing*)buf;

p->len = 0;
if (copy)
__memcpy (buf, in, sizeof(struct thing) + in->len);
if (p->len == 0)
{
p->len = 1;
}
}

That's all for now.
Tom.