This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

libm error handling


Different libm error handling approaches are selected by the
_LIB_VERSION global variable.  This defaults to _POSIX_ (selected by
CPPFLAGS-s_lib_version.c := -D_POSIX_MODE in math/Makefile, used to
compile sysdeps/ieee754/s_lib_version.c), may be set to _IEEE_ by
linking with -lieee (math/ieee-math.c) and otherwise may be set
explicitly by the user.  The possible values are: _IEEE_, _SVID_,
_XOPEN_, _POSIX_, _ISOC_, and the following notes describe the
differences between the versions.  Comments are welcome, particularly
on the proposed principles / changes at the end.  This analysis
ignores the special IA64 error handling
(ports/sysdeps/ia64/fpu/libm_error.c) on the basis that it's for IA64
maintainers to follow any changes in this area made elsewhere in
glibc.

What follows is specifically about real functions; complex functions
are not required by ISO C to set errno (regardless of the
math_errhandling value) and generally do not do so (because they use
the __ieee754_* versions of real functions internally).  Furthermore,
everything about matherr is limited to functions that were in the
SVID, or float and long double variants of those; newer functions do
not attempt to support this legacy error handling mechanism, only
exceptions and errno.

In general, the value _IEEE_ means "do not set errno, or call matherr;
do not use the __kernel_standard wrapper that does those things at
all".  The "do not set errno" part is not guaranteed, since some
functions directly set errno without checking _LIB_VERSION.  The "do
not use __kernel_standard" part *is* guaranteed, and so "do not call
matherr" is also guaranteed.

In general, _POSIX_ (the default) means that both exceptions and errno
are used, but matherr is not called.

The other values seem more poorly defined.  Do exceptions get raised
for them?  In some cases, yes, but in others not, depending on whether
the conditions for using the wrapper are based on the inputs to the
function, or on the result of the __ieee754_* version of the function.
Is matherr called?  Generally yes, even for _ISOC_ where it seems
inappropriate.  Is errno set?  The conditions in __kernel_standard
generally set it only for _POSIX_, or if matherr returns 0, but just
as _IEEE_ doesn't guarantee not setting errno, so the other values do
not guarantee it.

More specifically, _SVID_ and _XOPEN_ may both be interpreted as
meaning that matherr should be called (and errno not necessarily set
unless matherr returns 0), and _SVID_ as meaning that an error message
is printed to stderr if matherr returns zero.  In addition, _SVID_
means that return values are typically HUGE (the largest finite float)
instead of infinity or NaN.

The following cases have other special handling for particular
_LIB_VERSION values, beyond the general description above:

* atan2 (zero, zero) handles _SVID_ specially.

* Bessel function TLOSS errors are not reported for _IEEE_ or _POSIX_.

* lgamma does not set signgam for _ISOC_.

* scalb (removed in current POSIX, not in ISO C) uses a different
  implementation for _SVID_.

* There are various peculiarities of error handling in particular
  cases, conditioned on _SVID_ or _POSIX_, in __kernel_standard.


Now for proposed principles and changes:

* With the proposed removal of _SVID_SOURCE as a supported feature
  test macro, the _SVID_ and _XOPEN_ error handling modes should be
  considered legacy modes for existing binaries only.  Both these
  modes clearly predate ANSI C89 / ISO C90 (which specifies error
  handling via errno), which is generally the oldest API supported by
  glibc now.  Whether floating-point exceptions do get raised in
  particular cases in those modes should not be significant, as any
  code using them should not also try to use floating-point exceptions.

  Making matherr / _LIB_VERSION into compat symbols might be hard,
  however; I don't know if that works for symbols that the user's
  program defines itself, and you'd have the issue of new programs
  linked with -lieee (change -lieee to define a constructor that calls
  a new interface to change the error handling mode, if you don't
  obsolete use of -lieee as well?).

* The _ISOC_ mode should also be considered legacy.  It's not
  documented, and not a sensible approach for controlling signgam use;
  the present situation, where if a user defines a variable called
  signgam it gets modified by lgamma in a program built with -std=c99,
  is simply a bug, as signgam is in the user's namespace for C99/C11,
  and ISO C doesn't include any requirement to set _LIB_VERSION to
  _ISOC_.

  As far as I can tell, POSIX only reserves the identifier signgam
  with external linkage when math.h is included with _XOPEN_SOURCE
  defined appropriately to enable XSI extensions, not otherwise (there
  is a long list of symbols with external linkage that are always
  reserved, and it does not include signgam).  So I think the
  following should work for a fix: the lgamma symbol versions
  presently in use are made into compat symbol versions, for existing
  binaries where lgamma is expected to set signgam (except for
  _ISOC_).  The new version of the lgamma symbol does not set signgam,
  while a separate __lgamma_xsi function is defined that does set
  signgam, and is used when math.h is included with appropriate
  feature test macros defined.

  Otherwise, the most sensible handling of _ISOC_ is probably like
  _POSIX_ (meaning errno is set, TLOSS errors do not occur, and
  matherr is not called).

* As a corollary of the above, and given _ISOC_ treated like _POSIX_
  for TLOSS errors, bugs 6805 and 6806 (Bessel functions not raising
  underflow exception on TLOSS errors) could be closed as such errors
  would now only be considered to be relevant to legacy binaries not
  caring about floating-point exceptions.

* The most sensible way to control errno setting is not -lieee or
  _LIB_VERSION = _IEEE_, it's -fno-math-errno.  It would make sense
  for that to predefine __NO_MATH_ERRNO__ in GCC, and then to export
  the no-errno versions of functions under appropriate __*_noerrno (or
  similar) names - it's inevitably going to be a bit faster for
  programs to call the functions directly without needing runtime
  checks on _LIB_VERSION.

* Existing tests of _LIB_VERSION should where possible move to using
  appropriate macros relating to what is being logically tested
  (e.g. support for non-exception error handling); most cases in
  __kernel_standard have pretty standard code much more of which could
  go in a macro.  Such macros could also use __glibc_likely /
  __glibc_unlikely to reflect that _POSIX_ is by far the most likely
  _LIB_VERSION setting.

-- 
Joseph S. Myers
joseph@codesourcery.com


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]