Compiler optimisation bug

From: Nick Hibma <nick_at_van-laarhoven.org>
Date: Tue, 2 May 2017 10:26:17 +0200
There is a bug in sbin/dhclient.c for large expiry values on 32 bit platforms where time_t is a uint32_t (bug #218980, https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=218980). It is caused by a compiler optimisation that removes an if-statement. The code below shows the following output, clearly showing that the optimised case provides a different answer:


	% cc -O2 main.c -o main.a && ./main.a
	no opt: 0x7fffffff
	with opt: 0xfffffffe
	rephrased: 0x7fffffff

The code is as follows:

	% cat main.c
	#include <stdio.h>
	#include <sys/time.h>
	#define TIME_MAX 2147483647

	time_t a = TIME_MAX;
	time_t b = TIME_MAX;

	time_t
	add_noopt(time_t a, time_t b) __attribute__((optnone))
	{
    		a += b;
    		if (a < b)
        		a = TIME_MAX;
    		return a;
	}

	time_t
	add_withopt(time_t a, time_t b)
	{
 		a += b;
    		if (a < b)
        		a = TIME_MAX;
   		return a;
	}

	time_t
	add_rephrased(time_t a, time_t b)
	{
		if (a < 0 || a > TIME_MAX - b)
			a = TIME_MAX;
		else
        		a += b;
		return a;
	}

	int
	main(int argc, char **argv)
	{
    		printf("no opt:    0x%08x\n", add_noopt(a, b));
    		printf("with opt:  0x%08x\n", add_withopt(a, b));
		printf("rephrased: 0x%08x\n", add_rephrased(a, b));
	}

Should this be reported to the clang folks? Or is this to be expected when abusing integer overflows this way?

Also: The underlying problem is the fact that time_t is a 32 bit signed int. Any pointers as to a general method of resolving these time_t issues?

Regards,

Nick Hibma
nick_at_van-laarhoven.org

-- Open Source: We stand on the shoulders of giants.




Received on Tue May 02 2017 - 06:26:21 UTC

This archive was generated by hypermail 2.4.0 : Wed May 19 2021 - 11:41:11 UTC