gdtoaimp.h.patch   [plain text]


--- gdtoaimp.h.orig	2010-01-29 16:43:20.000000000 -0800
+++ gdtoaimp.h	2010-02-01 10:58:41.000000000 -0800
@@ -172,6 +172,91 @@
 
 #ifndef GDTOAIMP_H_INCLUDED
 #define GDTOAIMP_H_INCLUDED
+/*
+ * Paranoia: Protect exported symbols, including ones in files we don't
+ * compile right now.  The standard strtof and strtod survive.
+ */
+#define	dtoa		__dtoa
+#define	gdtoa		__gdtoa
+#define	freedtoa	__freedtoa
+#define	strtodg		__strtodg
+#define	g_ddfmt		__g_ddfmt
+#define	g_dfmt		__g_dfmt
+#define	g_ffmt		__g_ffmt
+#define	g_Qfmt		__g_Qfmt
+#define	g_xfmt		__g_xfmt
+#define	g_xLfmt		__g_xLfmt
+#define	strtoId		__strtoId
+#define	strtoIdd	__strtoIdd
+#define	strtoIf		__strtoIf
+#define	strtoIQ		__strtoIQ
+#define	strtoIx		__strtoIx
+#define	strtoIxL	__strtoIxL
+#define	strtord		__strtord
+#define	strtordd	__strtordd
+#define	strtorf		__strtorf
+#define	strtorQ		__strtorQ
+#define	strtorx		__strtorx
+#define	strtorxL	__strtorxL
+#define	strtodI		__strtodI
+#define	strtopd		__strtopd
+#define	strtopdd	__strtopdd
+#define	strtopf		__strtopf
+#define	strtopQ		__strtopQ
+#define	strtopx		__strtopx
+#define	strtopxL	__strtopxL
+
+/* Protect gdtoa-internal symbols */
+#define	Balloc		__Balloc_D2A
+#define	Bfree		__Bfree_D2A
+#define	ULtoQ		__ULtoQ_D2A
+#define	ULtof		__ULtof_D2A
+#define	ULtod		__ULtod_D2A
+#define	ULtodd		__ULtodd_D2A
+#define	ULtox		__ULtox_D2A
+#define	ULtoxL		__ULtoxL_D2A
+#define	any_on		__any_on_D2A
+#define	b2d		__b2d_D2A
+#define	bigtens		__bigtens_D2A
+#define	cmp		__cmp_D2A
+#define	copybits	__copybits_D2A
+#define	d2b		__d2b_D2A
+#define	decrement	__decrement_D2A
+#define	diff		__diff_D2A
+#define	dtoa_result	__dtoa_result_D2A
+#define	g__fmt		__g__fmt_D2A
+#define	gethex		__gethex_D2A
+#define	hexdig		__hexdig_D2A
+#define	hexdig_init_D2A	__hexdig_init_D2A
+#define	hexnan		__hexnan_D2A
+#define	hi0bits		__hi0bits_D2A
+#define	hi0bits_D2A	__hi0bits_D2A
+#define	i2b		__i2b_D2A
+#define	increment	__increment_D2A
+#define	lo0bits		__lo0bits_D2A
+#define	lshift		__lshift_D2A
+#define	match		__match_D2A
+#define	mult		__mult_D2A
+#define	multadd		__multadd_D2A
+#define	nrv_alloc	__nrv_alloc_D2A
+#define	pow5mult	__pow5mult_D2A
+#define	quorem		__quorem_D2A
+#define	ratio		__ratio_D2A
+#define	rshift		__rshift_D2A
+#define	rv_alloc	__rv_alloc_D2A
+#define	s2b		__s2b_D2A
+#define	set_ones	__set_ones_D2A
+#define	strcp		__strcp_D2A
+#define	strcp_D2A      	__strcp_D2A
+#define	strtoIg		__strtoIg_D2A
+#define	sum		__sum_D2A
+#define	tens		__tens_D2A
+#define	tinytens	__tinytens_D2A
+#define	tinytens	__tinytens_D2A
+#define	trailz		__trailz_D2A
+#define	ulp		__ulp_D2A
+
+#include <xlocale.h>
 #include "gdtoa.h"
 #include "gd_qnan.h"
 #ifdef Honor_FLT_ROUNDS
@@ -183,8 +268,11 @@
 #define Bug(x) {fprintf(stderr, "%s\n", x); exit(1);}
 #endif
 
+#include "limits.h"
 #include "stdlib.h"
 #include "string.h"
+#include "libc_private.h"
+#include "spinlock.h"
 
 #ifdef KR_headers
 #define Char char
@@ -198,6 +286,10 @@
 #define MALLOC malloc
 #endif
 
+#define INFNAN_CHECK
+#define USE_LOCALE
+#define NO_LOCALE_CACHE
+
 #undef IEEE_Arith
 #undef Avoid_Underflow
 #ifdef IEEE_MC68k
@@ -446,10 +538,14 @@
 #define ALL_ON 0xffff
 #endif
 
-#ifndef MULTIPLE_THREADS
-#define ACQUIRE_DTOA_LOCK(n)	/*nothing*/
-#define FREE_DTOA_LOCK(n)	/*nothing*/
-#endif
+#define MULTIPLE_THREADS
+extern spinlock_t __gdtoa_locks[2];
+#define ACQUIRE_DTOA_LOCK(n)	do {				\
+	if (__isthreaded) _SPINLOCK(&__gdtoa_locks[n]);		\
+} while(0)
+#define FREE_DTOA_LOCK(n)	do {				\
+	if (__isthreaded) _SPINUNLOCK(&__gdtoa_locks[n]);	\
+} while(0)
 
 #define Kmax 9
 
@@ -472,52 +568,6 @@
 #define Bcopy(x,y) memcpy(&x->sign,&y->sign,y->wds*sizeof(ULong) + 2*sizeof(int))
 #endif /* NO_STRING_H */
 
-#define Balloc Balloc_D2A
-#define Bfree Bfree_D2A
-#define ULtoQ ULtoQ_D2A
-#define ULtof ULtof_D2A
-#define ULtod ULtod_D2A
-#define ULtodd ULtodd_D2A
-#define ULtox ULtox_D2A
-#define ULtoxL ULtoxL_D2A
-#define any_on any_on_D2A
-#define b2d b2d_D2A
-#define bigtens bigtens_D2A
-#define cmp cmp_D2A
-#define copybits copybits_D2A
-#define d2b d2b_D2A
-#define decrement decrement_D2A
-#define diff diff_D2A
-#define dtoa_result dtoa_result_D2A
-#define g__fmt g__fmt_D2A
-#define gethex gethex_D2A
-#define hexdig hexdig_D2A
-#define hexnan hexnan_D2A
-#define hi0bits(x) hi0bits_D2A((ULong)(x))
-#define i2b i2b_D2A
-#define increment increment_D2A
-#define lo0bits lo0bits_D2A
-#define lshift lshift_D2A
-#define match match_D2A
-#define mult mult_D2A
-#define multadd multadd_D2A
-#define nrv_alloc nrv_alloc_D2A
-#define pow5mult pow5mult_D2A
-#define quorem quorem_D2A
-#define ratio ratio_D2A
-#define rshift rshift_D2A
-#define rv_alloc rv_alloc_D2A
-#define s2b s2b_D2A
-#define set_ones set_ones_D2A
-#define strcp strcp_D2A
-#define strtoIg strtoIg_D2A
-#define sum sum_D2A
-#define tens tens_D2A
-#define tinytens tinytens_D2A
-#define tinytens tinytens_D2A
-#define trailz trailz_D2A
-#define ulp ulp_D2A
-
  extern char *dtoa_result;
  extern CONST double bigtens[], tens[], tinytens[];
  extern unsigned char hexdig[];
@@ -540,7 +590,7 @@
  extern char *dtoa ANSI((double d, int mode, int ndigits,
 			int *decpt, int *sign, char **rve));
  extern char *g__fmt ANSI((char*, char*, char*, int, ULong, size_t));
- extern int gethex ANSI((CONST char**, FPI*, Long*, Bigint**, int));
+ extern int gethex ANSI((CONST char**, FPI*, Long*, Bigint**, int, locale_t));
  extern void hexdig_init_D2A(Void);
  extern int hexnan ANSI((CONST char**, FPI*, ULong*));
  extern int hi0bits_D2A ANSI((ULong));
@@ -562,6 +612,7 @@
  extern char *strcp ANSI((char*, const char*));
  extern int strtoIg ANSI((CONST char*, char**, FPI*, Long*, Bigint**, int*));
  extern double strtod ANSI((const char *s00, char **se));
+ extern double strtod_l ANSI((const char *s00, char **se, locale_t));
  extern Bigint *sum ANSI((Bigint*, Bigint*));
  extern int trailz ANSI((Bigint*));
  extern double ulp ANSI((U*));
@@ -613,4 +664,78 @@
 #define SI 0
 #endif
 
+/*
+ * For very large strings, strtod and family might exhaust memory in tight
+ * memory conditions (especially in 32-bits).  Such large strings could also
+ * tie up a CPU for minutes at a time.  Either can be considered a denial-of-
+ * service vunerability.
+ *
+ * To fix, we limit the string size to the maximum we need to calculate the
+ * rounding point correctly.  The longest string corresponding to the exact
+ * value of a floating point number occuring at 1.f...f p^-n, where n is
+ * the (absolute value of the) smallest exponent for a normalize number.
+ *
+ * To calculate this number of decimal digits, we use the formula:
+ *
+ * (n + m) - int(n * log10(2)) + 3
+ *
+ * where m is the number of bits in the f...f fraction.  This is the number
+ * of decimal digits for the least significant bit minus the number of leading
+ * zeros for the most significant bit (the '1'), plus a few to compensate for
+ * an extra digits due to the full 1.f...f value, an extra digit for the
+ * mid-way point for rounding and an extra guard digit.
+ *
+ * Using the approximation log10(2) ~ 1233 / (2^12), converting to the fpi.emin
+ * and fpi.nbits values, we get:
+ *
+ * -fpi.emin -((1233 * (-fpi.nbits - fpi.emin)) >> 12) + 3
+ *
+ * Finally, we add an extra digit, either '1' or '0', to represent whether
+ * to-be-truncated digits contain a non-zero digit, or are all zeros,
+ * respectively.
+ *
+ * The truncated string is allocated on the heap, so code using
+ * TRUNCATE_DIGITS() will need to free that space when no longer needed.
+ * Pass a char * as the second argument, initialized to NULL; if its value
+ * becomes non-NULL, memory was allocated.
+ */
+#define LOG2NUM 1233
+#define LOG2DENOMSHIFT 12
+#define TRUNCATEDIGITS(_nbits, _emin)	(-(_emin) - ((LOG2NUM * (-(_nbits) - (_emin))) >> LOG2DENOMSHIFT) + 3)
+
+#define TRUNCATE_DIGITS(_s0, _temp, _nd, _nd0, _nf, _nbits, _emin, _dplen) \
+{ \
+	int _maxdigits = TRUNCATEDIGITS((_nbits), (_emin)); \
+	if ((_nd) > _maxdigits && \
+	  ((_temp) = MALLOC(_maxdigits + (_dplen) + 2)) != NULL) { \
+		char *_tp = (_temp) + _maxdigits; \
+		if ((_nd0) >= _maxdigits) { \
+			memcpy((_temp), (_s0), _maxdigits); \
+			if ((_nd) > (_nd0)) *_tp++ = '1'; \
+			else { \
+			    const char *_q = (_s0) + _maxdigits; \
+			    int _n = (_nd0) - _maxdigits; \
+			    for(; _n > 0 && *_q == '0'; _n--, _q++) {} \
+			    *_tp++ = _n > 0 ? '1' : '0'; \
+			    } \
+			(_nf) = -((_nd0) - (_maxdigits + 1)); \
+			(_nd0) = _maxdigits + 1; \
+			} \
+		else if ((_nd0) == 0) { \
+			memcpy((_temp), (_s0), _maxdigits); \
+			*_tp++ = '1'; \
+			(_nf) -= ((_nd) - (_maxdigits + 1)); \
+			} \
+		else { \
+			memcpy((_temp), (_s0), _maxdigits + (_dplen)); \
+			_tp += (_dplen); \
+			*_tp++ = '1'; \
+			(_nf) = (_maxdigits + 1) - (_nd0); \
+			} \
+		*_tp = 0; \
+		(_nd) = _maxdigits + 1; \
+		(_s0) = (_temp); \
+		} \
+	}
+
 #endif /* GDTOAIMP_H_INCLUDED */