NetBSD-Bugs archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
lib/48131: __type_fit: bug and floating-point requirement
>Number: 48131
>Category: lib
>Synopsis: __type_fit: bug and floating-point requirement
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: lib-bug-people
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Fri Aug 16 20:05:00 +0000 2013
>Originator: Grégoire Sutre
>Release: NetBSD 6.99.23 (201308140140Z)
>Organization:
>Environment:
System: NetBSD yosemite 6.99.23 NetBSD 6.99.23 (GENERIC) #0: Thu Aug 15
00:59:23 CEST 2013
instsoft@yosemite:/tmp/netbsd-drmgem.usr/src/sys/arch/amd64/compile/GENERIC
amd64
Architecture: x86_64
Machine: amd64
>Description:
This report addresses two problems with the macro __type_fix that
is defined /usr/include/sys/cdefs.h.
Firstly, on my NetBSD/amd64 system, for a signed integer type t, the
macro __type_fit(t, x) evaluates to 1 when x > LONG_MAX. See below
for an example.
Secondly, the macro __type_fit relies on the inline function
static __inline int __negative_p(double x) { return x < 0; }
This function definition introduces a dependency on a floating-point
data type in many (most?) system headers. This breaks programs that
explicitly require integer-only data types, such as GRUB (current
development version). See:
http://lists.gnu.org/archive/html/grub-devel/2013-08/msg00048.html
>How-To-Repeat:
As an example, consider the C program:
#include <sys/types.h>
#include <stdint.h>
#include <stdio.h>
#include <limits.h>
int main()
{
uintmax_t x = (uintmax_t)LONG_MAX+1;
printf("fit(int, %jx) : %d\n", x, __type_fit(int, x));
return 0;
}
Running this program gives fit(int, 8000000000000000) : 1
>Fix:
The attached patch attempts to fix both problems. However, there is
a build failure caused by lint with the patch. I believe that this
is because lint does not understand __typeof__.
The first part of the patch fixes the issue with the double data type.
This fix was suggested by Vladimir Serbinenko.
The second part fixes __type_fit(t, x) when x is positive by checking
that its sign bit is not set. There is a probably a better way to do
that.
Index: cdefs.h
===================================================================
RCS file: /cvsroot/src/sys/sys/cdefs.h,v
retrieving revision 1.107
diff -u -r1.107 cdefs.h
--- cdefs.h 29 May 2013 19:02:30 -0000 1.107
+++ cdefs.h 16 Aug 2013 16:57:10 -0000
@@ -555,12 +555,13 @@
#ifndef __ASSEMBLER__
static __inline long long __zeroll(void) { return 0; }
-static __inline int __negative_p(double x) { return x < 0; }
#else
#define __zeroll() (0LL)
-#define __negative_p(x) ((x) < 0)
#endif
+#define __negative_p(x) (__type_is_signed(__typeof__(x)) && \
+ ((x) & (1ULL << (sizeof(x) * NBBY - 1))))
+
#define __type_min_s(t) ((t)((1ULL << (sizeof(t) * NBBY - 1))))
#define __type_max_s(t) ((t)~((1ULL << (sizeof(t) * NBBY - 1))))
#define __type_min_u(t) ((t)0ULL)
@@ -575,7 +576,8 @@
#define __type_fit_s(t, a) (/*LINTED*/__negative_p(a) ? \
((intmax_t)((a) + __zeroll()) >= (intmax_t)__type_min_s(t)) : \
- ((intmax_t)((a) + __zeroll()) <= (intmax_t)__type_max_s(t)))
+ (((a) & (1ULL << (sizeof(intmax_t) * NBBY - 1))) == 0 && \
+ (intmax_t)((a) + __zeroll()) <= (intmax_t)__type_max_s(t)))
/*
* return true if value 'a' fits in type 't'
Home |
Main Index |
Thread Index |
Old Index