mirror of
				git://git.code.sf.net/p/cdesktopenv/code
				synced 2025-03-09 15:50:02 +00:00 
			
		
		
		
	Revise the pow(1,inf) IEEE feature test to defeat clever compilers (#184)
Compilers like GCC are capable of optimizing away calls like pow(1,inf), which caused the IEEE compliance feature test within libast to incorrectly succeed on platforms with non-IEEE behavior. This is arguably a bug within GCC, as floating point optimizations should never alter the behavior of code unless IEEE compliance is explicitly disabled via a flag like -ffast-math. Programs in which only some calls to pow are optimized away are liable to severely malfunction. Thanks to Martijn Dekker for pointing this issue out and the kind operators of polarhome.com for permitting me gratis use of their Unix systems. src/lib/libast/comp/omitted.c: - Add IEEE compliant functions that wrap powf, pow, and powl. src/lib/libast/features/float: - Look for powf, pow, and powl in the C library. - For compilers that do the right thing, like the native toolchains of Solaris and UnixWare, use lightweight macros to wrap the pow functions. - Use a volatile function pointer through which to access the C library's pow function in an attempt to defeat code optimization. - For these overzealous compilers, define pow to _ast_pow so that the same technique can be used within the above functions.
This commit is contained in:
		
							parent
							
								
									c2cb0eae19
								
							
						
					
					
						commit
						72968eaed6
					
				
					 4 changed files with 59 additions and 8 deletions
				
			
		| 
						 | 
				
			
			@ -3128,6 +3128,7 @@ make install
 | 
			
		|||
					prev include/tm.h implicit
 | 
			
		||||
					prev include/error.h implicit
 | 
			
		||||
					prev include/ast.h implicit
 | 
			
		||||
					prev FEATURE/float implicit
 | 
			
		||||
				done comp/omitted.c
 | 
			
		||||
				meta omitted.o %.c>%.o comp/omitted.c omitted
 | 
			
		||||
				prev comp/omitted.c
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,6 +15,7 @@ __STDPP__directive pragma pp:hide utime utimes
 | 
			
		|||
#include <error.h>
 | 
			
		||||
#include <tm.h>
 | 
			
		||||
 | 
			
		||||
#include "FEATURE/float"
 | 
			
		||||
#include "FEATURE/omitted"
 | 
			
		||||
 | 
			
		||||
#undef	OMITTED
 | 
			
		||||
| 
						 | 
				
			
			@ -1145,6 +1146,36 @@ __EXPORT__ double (*_imp__strtod)(const char*, char**) = strtod;
 | 
			
		|||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* Kludge to deal with GCC's overzealous optimizer breaking the pow functions.
 | 
			
		||||
 *
 | 
			
		||||
 * Removal of this will break IEEE floating point on the SVR4 platforms.
 | 
			
		||||
 */
 | 
			
		||||
#if _need_ast_pow_funs
 | 
			
		||||
# if _lib_powf
 | 
			
		||||
float (*volatile _ast_ppowf)(float,float) = &powf;
 | 
			
		||||
float _ast_powf(float x, float y)
 | 
			
		||||
{
 | 
			
		||||
	return x == 1.0F ? 1.0F : (*_ast_ppowf)(x,y);
 | 
			
		||||
}
 | 
			
		||||
# endif
 | 
			
		||||
 | 
			
		||||
# if _lib_pow
 | 
			
		||||
double (*volatile _ast_ppow)(double,double) = &pow;
 | 
			
		||||
double _ast_pow(double x, double y)
 | 
			
		||||
{
 | 
			
		||||
	return x == 1.0 ? 1.0 : (*_ast_ppow)(x,y);
 | 
			
		||||
}
 | 
			
		||||
# endif
 | 
			
		||||
 | 
			
		||||
# if _lib_powl
 | 
			
		||||
long double (*volatile _ast_ppowl)(long double,long double) = &powl;
 | 
			
		||||
long double _ast_powl(long double x, long double y)
 | 
			
		||||
{
 | 
			
		||||
	return x == 1.0L ? 1.0L : (*_ast_ppowl)(x,y);
 | 
			
		||||
}
 | 
			
		||||
# endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef OMITTED
 | 
			
		||||
 | 
			
		||||
NoN(omitted)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,7 +2,7 @@ set	prototyped
 | 
			
		|||
set	nooptimize
 | 
			
		||||
set	stdio FEATURE/standards
 | 
			
		||||
hdr	float,limits,math,values
 | 
			
		||||
lib,npt	frexp,frexpl,ldexp,ldexpl,finite,finitel,isinfl,isnanl,copysign,copysignl FEATURE/standards math.h -lm
 | 
			
		||||
lib,npt	frexp,frexpl,ldexp,ldexpl,finite,finitel,isinfl,isnanl,copysign,copysignl,powf,pow,powl FEATURE/standards math.h -lm
 | 
			
		||||
lib	fpclassify -lm note{ fpclassify present and works }end link{
 | 
			
		||||
		#include <sys/types.h>
 | 
			
		||||
		#include <sys/stat.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -1231,15 +1231,33 @@ tst	- -DSCAN=1 - -lm -DSTRTO=1 - -DMAC=1 - -DDIV=1 - -DEXP=1 - -DADD=1 - -DMPY=1
 | 
			
		|||
	}
 | 
			
		||||
}end
 | 
			
		||||
 | 
			
		||||
tst	ast_pow_ieee -lm note{ pow(1,inf) is IEEE compliant }end execute{
 | 
			
		||||
if	need_ast_pow_macros -lm note{ are IEEE pow macro replacements needed }end execute{
 | 
			
		||||
	#include <sys/types.h>
 | 
			
		||||
	#include <sys/stat.h>
 | 
			
		||||
	#include <stdlib.h>
 | 
			
		||||
	#include <unistd.h>
 | 
			
		||||
	#include <math.h>
 | 
			
		||||
	int main() { return pow(1.0, 1.0 / 0.0) != 1.0; }
 | 
			
		||||
}end fail{
 | 
			
		||||
	echo '#define powf(x,y)	(((x)==1.0)?1.0:powf((x),(y)))'
 | 
			
		||||
	echo '#define pow(x,y)	(((x)==1.0)?1.0:pow((x),(y)))'
 | 
			
		||||
	echo '#define powl(x,y)	(((x)==1.0)?1.0:powl((x),(y)))'
 | 
			
		||||
}end
 | 
			
		||||
	int main() { return pow(1.0, 1.0 / 0.0) == 1.0; }
 | 
			
		||||
}end {
 | 
			
		||||
	#define powf(x,y)	(((x)==1.0)?1.0:powf((x),(y)))
 | 
			
		||||
	#define pow(x,y)	(((x)==1.0)?1.0:pow((x),(y)))
 | 
			
		||||
	#define powl(x,y)	(((x)==1.0)?1.0:powl((x),(y)))
 | 
			
		||||
}
 | 
			
		||||
elif	tst need_ast_pow_funs -lm note{ are IEEE pow function replacements needed }end execute{
 | 
			
		||||
	#include <sys/types.h>
 | 
			
		||||
	#include <sys/stat.h>
 | 
			
		||||
	#include <stdlib.h>
 | 
			
		||||
	#include <unistd.h>
 | 
			
		||||
	#include <math.h>
 | 
			
		||||
	/* This bit of obfuscation defeats GCC's code optimizer. */
 | 
			
		||||
	double (*volatile _ast_ppow)(double,double);
 | 
			
		||||
	int main () { _ast_ppow = &pow; return (*_ast_ppow)(1.0, 1.0 / 0.0) == 1.0; }
 | 
			
		||||
}end {
 | 
			
		||||
	float			_ast_powf(float x, float y);
 | 
			
		||||
	double			_ast_pow(double x, double y);
 | 
			
		||||
	long double		_ast_powl(long double x, long double y);
 | 
			
		||||
	#define powf(x,y)	(_ast_powf((x),(y)))
 | 
			
		||||
	#define pow(x,y)	(_ast_pow((x),(y)))
 | 
			
		||||
	#define powl(x,y)	(_ast_powl((x),(y)))
 | 
			
		||||
}
 | 
			
		||||
endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue