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
|
@ -1216,6 +1216,7 @@ make install
|
||||||
exec - iffe ${IFFEFLAGS} -v -c "${CC} ${mam_cc_FLAGS} ${KSH_RELFLAGS} ${KSH_SHOPTFLAGS} ${CCFLAGS} ${LDFLAGS}" ref ${mam_cc_L+-L.} ${mam_cc_L+-L${INSTALLROOT}/lib} -I${PACKAGE_ast_INCLUDE} -I${INSTALLROOT}/include ${mam_libdll} ${mam_libcmd} ${mam_libast} ${mam_libm} ${mam_libnsl} : run features/math.sh ${PACKAGEROOT}/src/cmd/ksh93/data/math.tab
|
exec - iffe ${IFFEFLAGS} -v -c "${CC} ${mam_cc_FLAGS} ${KSH_RELFLAGS} ${KSH_SHOPTFLAGS} ${CCFLAGS} ${LDFLAGS}" ref ${mam_cc_L+-L.} ${mam_cc_L+-L${INSTALLROOT}/lib} -I${PACKAGE_ast_INCLUDE} -I${INSTALLROOT}/include ${mam_libdll} ${mam_libcmd} ${mam_libast} ${mam_libm} ${mam_libnsl} : run features/math.sh ${PACKAGEROOT}/src/cmd/ksh93/data/math.tab
|
||||||
make ${PACKAGE_ast_INCLUDE}/ast_standards.h implicit
|
make ${PACKAGE_ast_INCLUDE}/ast_standards.h implicit
|
||||||
done ${PACKAGE_ast_INCLUDE}/ast_standards.h dontcare
|
done ${PACKAGE_ast_INCLUDE}/ast_standards.h dontcare
|
||||||
|
prev ${INSTALLROOT}/src/lib/libast/FEATURE/float implicit
|
||||||
done FEATURE/math generated
|
done FEATURE/math generated
|
||||||
prev include/streval.h implicit
|
prev include/streval.h implicit
|
||||||
prev FEATURE/options implicit
|
prev FEATURE/options implicit
|
||||||
|
|
|
@ -3128,6 +3128,7 @@ make install
|
||||||
prev include/tm.h implicit
|
prev include/tm.h implicit
|
||||||
prev include/error.h implicit
|
prev include/error.h implicit
|
||||||
prev include/ast.h implicit
|
prev include/ast.h implicit
|
||||||
|
prev FEATURE/float implicit
|
||||||
done comp/omitted.c
|
done comp/omitted.c
|
||||||
meta omitted.o %.c>%.o comp/omitted.c omitted
|
meta omitted.o %.c>%.o comp/omitted.c omitted
|
||||||
prev comp/omitted.c
|
prev comp/omitted.c
|
||||||
|
|
|
@ -15,6 +15,7 @@ __STDPP__directive pragma pp:hide utime utimes
|
||||||
#include <error.h>
|
#include <error.h>
|
||||||
#include <tm.h>
|
#include <tm.h>
|
||||||
|
|
||||||
|
#include "FEATURE/float"
|
||||||
#include "FEATURE/omitted"
|
#include "FEATURE/omitted"
|
||||||
|
|
||||||
#undef OMITTED
|
#undef OMITTED
|
||||||
|
@ -1145,6 +1146,36 @@ __EXPORT__ double (*_imp__strtod)(const char*, char**) = strtod;
|
||||||
|
|
||||||
#endif
|
#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
|
#ifndef OMITTED
|
||||||
|
|
||||||
NoN(omitted)
|
NoN(omitted)
|
||||||
|
|
|
@ -2,7 +2,7 @@ set prototyped
|
||||||
set nooptimize
|
set nooptimize
|
||||||
set stdio FEATURE/standards
|
set stdio FEATURE/standards
|
||||||
hdr float,limits,math,values
|
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{
|
lib fpclassify -lm note{ fpclassify present and works }end link{
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.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
|
}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/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
int main() { return pow(1.0, 1.0 / 0.0) != 1.0; }
|
int main() { return pow(1.0, 1.0 / 0.0) == 1.0; }
|
||||||
}end fail{
|
}end {
|
||||||
echo '#define powf(x,y) (((x)==1.0)?1.0:powf((x),(y)))'
|
#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)))'
|
#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)))'
|
#define powl(x,y) (((x)==1.0)?1.0:powl((x),(y)))
|
||||||
}end
|
}
|
||||||
|
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