Date: Mon, 15 Nov 1999 17:48:31 +0100 From: Pierre Beyssac <beyssac@enst.fr> To: freebsd-current@freebsd.org Subject: egcs -O breaks ping.c:in_cksum() Message-ID: <19991115174831.B30139@enst.fr>
next in thread | raw e-mail | index | archive | help
--azLHFNyN32YCQGCU Content-Type: text/plain; charset=us-ascii I've discovered the following problem, either due to egcs or the source code for in_cksum in ping, I'm not sure. The symptom is that in_cksum() returns an invalid result on an odd-size buffer, when compile optimization is on. You can check this by trying "ping -s 65 localhost" and seeing that no reply is ever received. The kernel ICMP bad checksum count just increases. The problem is apparently due to the following code fragment: register u_short answer = 0; [...] /* mop up an odd byte, if necessary */ if (nleft == 1) { *(u_char *)(&answer) = *(u_char *)w ; sum += answer; } Removing the "register" declaration for 'answer' doesn't help. OTOH, adding "volatile" does help and seems to fix the problem. Only I'm not sure that's the correct fix because I'm unsure about the exact semantics of "volatile"; it might well be an egcs bug. Attached is a test program if anyone wishes to experiment. Try to compile with and without -O and see the difference. The correct output is "cksum=f9f6", the wrong output is "cksum=f5f6". -- Pierre Beyssac pb@enst.fr --azLHFNyN32YCQGCU Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="ck.c" #include <sys/types.h> #include <stdio.h> /* * in_cksum -- * Checksum routine for Internet Protocol family headers (C Version) */ u_short in_cksum(addr, len) u_short *addr; int len; { register int nleft = len; register u_short *w = addr; int sum = 0; volatile u_short answer = 0; /* * Our algorithm is simple, using a 32 bit accumulator (sum), we add * sequential 16 bit words to it, and at the end, fold back all the * carry bits from the top 16 bits into the lower 16 bits. */ while (nleft > 1) { sum += *w++; nleft -= 2; } /* mop up an odd byte, if necessary */ if (nleft == 1) { *(u_char *)(&answer) = *(u_char *)w ; sum += answer; } /* add back carry outs from top 16 bits to low 16 bits */ sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ sum += (sum >> 16); /* add carry */ answer = ~sum; /* truncate to 16 bits */ return(answer); } int main() { unsigned char tb[] = { 1, 2, 3, 4, 5 }; printf("cksum=%04x\n", in_cksum(tb, sizeof tb)); } --azLHFNyN32YCQGCU-- To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-current" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?19991115174831.B30139>