1
0
Fork 0
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:
Lev Kujawski 2021-02-18 11:45:27 -07:00 committed by GitHub
parent c2cb0eae19
commit 72968eaed6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 59 additions and 8 deletions

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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