Re: stack-trace: Use libasan as an alternative to libbacktrace

2024-07-18 Thread Bruno Haible
I did:
> 2024-07-17  Bruno Haible  
> 
>   stack-trace: Use libasan as an alternative to libbacktrace.
>   * m4/stack-trace.m4 (gl_STACK_TRACE_EARLY): As a second choice, use
>   libasan.

However, on NetBSD 10.0, every program that links with libasan exits
without even reaching main(). It merely prints
"This sanitizer is not compatible with enabled ASLR"
to standard error and exits with status 0 (yes, 0 !!!).

NetBSD is such a joke.

And yes, they knew about it more than one year before they released NetBSD 10.0
[1] and didn't do anything about it.

[1] https://mail-index.netbsd.org/pkgsrc-users/2022/12/17/msg036642.html


2024-07-18  Bruno Haible  

stack-trace: Don't use NetBSD's broken libasan.
* m4/stack-trace.m4 (gl_STACK_TRACE_EARLY): Test whether a program
linked with libasan even minimally works.

diff --git a/m4/stack-trace.m4 b/m4/stack-trace.m4
index e102484e0f..faf86eefe9 100644
--- a/m4/stack-trace.m4
+++ b/m4/stack-trace.m4
@@ -22,6 +22,7 @@ AC_DEFUN([gl_STACK_TRACE_EARLY]
   AC_MSG_RESULT([$enable_debug])
 
   AC_REQUIRE([gl_STDLIB_H_DEFAULTS])
+  AC_REQUIRE([AC_CANONICAL_HOST])
   if test $enable_debug = yes; then
 dnl The first choice is libbacktrace by Ian Lance Taylor.
 dnl Maintained at https://github.com/ianlancetaylor/libbacktrace,
@@ -54,50 +55,69 @@ AC_DEFUN([gl_STACK_TRACE_EARLY]
   AC_CACHE_CHECK([for libasan], [gl_cv_lib_asan], [
 gl_saved_LIBS="$LIBS"
 LIBS="$gl_saved_LIBS -lasan"
-AC_LINK_IFELSE(
+dnl We need AC_RUN_IFELSE here, not merely AC_LINK_IFELSE, because on
+dnl NetBSD libasan exists but every program that links to it 
immediately
+dnl prints "This sanitizer is not compatible with enabled ASLR" to
+dnl standard error and exits with code 0, without even invoking main().
+AC_RUN_IFELSE(
   [AC_LANG_PROGRAM(
- [[extern
+ [[#include 
+   extern
#ifdef __cplusplus
"C"
#endif
void __sanitizer_print_stack_trace (void);
  ]],
- [[__sanitizer_print_stack_trace ();
+ [[remove ("conftest.c");
+   __sanitizer_print_stack_trace ();
  ]])],
-  [gl_cv_lib_asan=yes],
-  [gl_cv_lib_asan=no])
+  [if test -f conftest.c; then
+ dnl main() was not reached. NetBSD!
+ gl_cv_lib_asan=no
+   else
+ gl_cv_lib_asan=yes
+   fi
+  ],
+  [gl_cv_lib_asan=no],
+  [case "$host_os" in
+ netbsd*) gl_cv_lib_asan="guessing no" ;;
+ *)   gl_cv_lib_asan="guessing yes" ;;
+   esac
+  ])
 LIBS="$gl_saved_LIBS"
   ])
-  if test $gl_cv_lib_asan = yes; then
-AC_DEFINE([HAVE_LIBASAN], [1],
-  [Define if you have the libasan library.])
-CAN_PRINT_STACK_TRACE=1
-LIBS="$LIBS -lasan"
-  else
-dnl The third choice is libexecinfo.
-dnl It does not produce source file names and line numbers, only 
addresses
-dnl (which are mostly useless due to ASLR) and _sometimes_ function 
names.
-AC_REQUIRE([AC_CANONICAL_HOST])
-case "$host_os" in
-  *-gnu* | gnu* | darwin* | freebsd* | dragonfly* | netbsd* | openbsd* 
| solaris*)
-dnl execinfo might be implemented on this platform.
-CAN_PRINT_STACK_TRACE=1
-dnl On *BSD system, link all programs with -lexecinfo. Cf. 
m4/execinfo.m4.
-case "$host_os" in
-  freebsd* | dragonfly* | netbsd* | openbsd*)
-LIBS="$LIBS -lexecinfo"
-;;
-esac
-dnl Link all programs in such a way that the stack trace includes 
the
-dnl function names. '-rdynamic' is equivalent to 
'-Wl,-export-dynamic'.
-case "$host_os" in
-  *-gnu* | gnu* | openbsd*)
-LDFLAGS="$LDFLAGS -rdynamic"
-;;
-esac
-;;
-esac
-  fi
+  case "$gl_cv_lib_asan" in
+*yes)
+  AC_DEFINE([HAVE_LIBASAN], [1],
+[Define if you have the libasan library.])
+  CAN_PRINT_STACK_TRACE=1
+  LIBS="$LIBS -lasan"
+  ;;
+*)
+  dnl The third choice is libexecinfo.
+  dnl It does not produce source file names and line numbers, only 
addresses
+  dnl (which are mostly useless due to ASLR) and _sometimes_ function 
names.
+  case "$host_os" in
+*-gnu* | gnu* | darwin* | freebsd* | dragonfly* | netbsd* | 
openbsd* | solaris*)
+  dnl execinfo might be implemented on this platform.
+  CAN_PRINT_STACK_TRACE=1
+  dnl On *BSD system, link all programs with -lexecinfo. Cf. 
m4/execinfo.m4.
+  case "$host_os" in
+freebsd* | dragonfly* | netbsd* | openbsd*)
+

stdlib: Don't define print_stack_trace unconditionally

2024-07-18 Thread Bruno Haible
Yesterday I renamed _gl_pre_abort() to print_stack_trace(). But the latter
is a symbol that could collide with some symbol defined by the application,
and should therefore not be defined by gnulib's  override
unconditionally. This patch fixes that.


2024-07-18  Bruno Haible  

stdlib: Don't define print_stack_trace unconditionally.
* modules/stack-trace (configure.ac): Invoke gl_MODULE_INDICATOR.
* lib/stdlib.in.h (print_stack_trace): Don't define if module
'stack-trace' is not present.
* tests/macros.h (print_stack_trace): Define as a fallback if module
'stack-trace' is not present.

diff --git a/lib/stdlib.in.h b/lib/stdlib.in.h
index 3de9eba245..7c6daa58b8 100644
--- a/lib/stdlib.in.h
+++ b/lib/stdlib.in.h
@@ -1600,12 +1600,16 @@ _GL_WARN_ON_USE (setenv, "setenv is unportable - "
 # endif
 #endif
 
-#if @GNULIB_STACK_TRACE@ && @CAN_PRINT_STACK_TRACE@
+#if @GNULIB_STACK_TRACE@
+/* Prints a stack trace of the current thread to standard error,
+   if possible.  */
+# if @CAN_PRINT_STACK_TRACE@
 _GL_EXTERN_C void print_stack_trace (void);
-#else
-# if !GNULIB_defined_print_stack_trace
-#  define print_stack_trace() /* nothing */
-#  define GNULIB_defined_print_stack_trace 1
+# else
+#  if !GNULIB_defined_print_stack_trace
+#   define print_stack_trace() /* nothing */
+#   define GNULIB_defined_print_stack_trace 1
+#  endif
 # endif
 #endif
 
diff --git a/modules/stack-trace b/modules/stack-trace
index 122845d610..8dfb87908b 100644
--- a/modules/stack-trace
+++ b/modules/stack-trace
@@ -18,6 +18,7 @@ configure.ac:
 gl_STACK_TRACE
 gl_CONDITIONAL([GL_COND_OBJ_STACK_TRACE], [test $CAN_PRINT_STACK_TRACE = 1])
 gl_STDLIB_MODULE_INDICATOR([stack-trace])
+gl_MODULE_INDICATOR([stack-trace])
 
 Makefile.am:
 if GL_COND_OBJ_STACK_TRACE
diff --git a/tests/macros.h b/tests/macros.h
index 3121b21820..55163c65a3 100644
--- a/tests/macros.h
+++ b/tests/macros.h
@@ -45,6 +45,12 @@
 # define ASSERT_STREAM stderr
 #endif
 
+/* Define print_stack_trace() to a no-op, if the module 'stack-trace' is not
+   in use.  */
+#if !GNULIB_STACK_TRACE
+# define print_stack_trace() /* nothing */
+#endif
+
 /* Exit status of the test.
Initialized to EXIT_SUCCESS.
Set to EXIT_FAILURE when an ASSERT or ASSERT_NO_STDIO fails.  */






doc: Document the stack-trace and abort-debug modules

2024-07-18 Thread Bruno Haible
The stack-trace and abort-debug modules are now in a state where they
can be documented. Done as follows:


2024-07-18  Bruno Haible  

doc: Document the stack-trace and abort-debug modules.
* doc/stack-trace.texi: New file.
* doc/gnulib.texi (Particular Modules): Include it.

== doc/stack-trace.texi ==
@node Stack traces
@section Stack traces

@c Copyright (C) 2024 Free Software Foundation, Inc.

@c Permission is granted to copy, distribute and/or modify this document
@c under the terms of the GNU Free Documentation License, Version 1.3 or
@c any later version published by the Free Software Foundation; with no
@c Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.  A
@c copy of the license is at .

@c Written by Bruno Haible.

Printing a stack trace
was traditionally seen as a feature of the debugging environment
and thus only implemented in the debuggers (@command{gdb} etc.).
However, they are also useful in production code,
for use in two circumstances:
@itemize
@item
When a problem occurs on a user's machine,
when the user is merely a user, not a programmer.
@item
In unit tests that run in continuous-integration environments.
In such environments, the virtual machine is discarded
immediately after the tests have run.
It is not possible to run a debugger in such environments.
@end itemize
@noindent
And in fact, printing a stack trace is part of the basic runtime system
in programming languages such as
Java 
(@url{https://docs.oracle.com/javase/8/docs/api/java/lang/Throwable.html#printStackTrace--,
 printStackTrace method}),
Python (@url{https://docs.python.org/3/library/traceback.html, print_exception 
method}),
Go (@url{https://pkg.go.dev/runtime/debug#PrintStack, PrintStack function}),
and
ISO C++ 23 (@url{https://en.cppreference.com/w/cpp/utility/basic_stacktrace, 
std::stacktrace class}).

Gnulib provides a module @samp{stack-trace} with this feature:
@code{print_stack_trace ()}
prints a stack trace of the current thread to standard error.

For it to work best, three requirements need to be met:
@itemize
@item
The @url{https://github.com/ianlancetaylor/libbacktrace, libbacktrace library}
or GCC's sanitizer library @code{libasan} needs to be installed.
@item
The program needs to be compiled with debugging information (option @code{-g}).
@item
On macOS, where debugging information
is stored in a separate directory rather than in the compiled binary
(see @url{https://stackoverflow.com/questions/10044697/#12827463}),
the @code{dsymutil} program needs to be used when linking,
and the debugging information needs to be copied when the program is installed.
Cf. 
@url{https://github.com/ianlancetaylor/libbacktrace/issues/122#issuecomment-2122589147}.
@end itemize

When these requirements are not met, the function @code{print_stack_trace ()}
either prints a stack trace without source file names and line numbers,
or prints nothing at all.

Gnulib also provides a module @samp{abort-debug},
that overrides the @code{abort} function so that
it prints the stack trace of the current thread, before actually aborting.
Thus, @code{abort ()} remains the idiom of choice
for signaling a fatal situation that requires developer attention:
it is useful both in debugging environments and production code.






Re: doc: Document the stack-trace and abort-debug modules

2024-07-18 Thread Paul Eggert

On 2024-07-18 05:25, Bruno Haible wrote:

The stack-trace and abort-debug modules are now in a state where they
can be documented. Done as follows:


Thanks. Are these modules safe to use in signal handlers? I suspect that 
Emacs would need that, in order to use them. Either way, it should be 
documented.


Similarly, in POSIX an 'abort ()' call is async-signal-safe; is that 
still true if the abort-debug module is used? This should be documented.




Re: stack-trace: Use libasan as an alternative to libbacktrace

2024-07-18 Thread Paul Eggert

On 2024-07-18 04:21, Bruno Haible wrote:

on NetBSD 10.0, every program that links with libasan exits
without even reaching main(). It merely prints
"This sanitizer is not compatible with enabled ASLR"
to standard error and exits with status 0 (yes, 0 !!!).


If I understand things correctly a similar problem was also on FreeBSD 
with PIE and the bug wasn't fixed until November of last year:


https://github.com/llvm/llvm-project/commit/7440e4ed85aa992718d4b5ccd1c97724bc3bdd2c

It might also be worth looking into the other Die() calls in the latest 
sanitizer_linux.cpp:


https://github.com/llvm/llvm-project/blob/main/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp



[PATCH v1] xstrtol: 1 is not a valid base

2024-07-18 Thread Alejandro Colomar
If xstrtol() was being called with a base of 1, under some conditions it
would invoke Undefined Behavior.

Here's the code that would trigger UB:

char  *end;

xstrtol(str, &end, 1, ...);  // Let's ignore trailing args.

The reason why this triggers UB is that since the following line lets a
base of 1 go through:

assure (0 <= strtol_base && strtol_base <= 36);

then we arrive at this call:

tmp = __strtol (s, p, strtol_base);

which sets errno to EINVAL and returns 0 immediately, without updating
the 'p' pointer.  Then, the following line of code:

if (*p == s)

dereferences an uninitialized pointer.

This was found while searching for examples of why strtol(3) is a bad
API, and how it makes it so easy to misuse.

Fixes: 034a18049cbc (2014-12-20, "assure: new module")
Link: 

Cc: Paul Eggert 
Cc: Đoàn Trần Công Danh 
Cc: Eli Schwartz 
Cc: Sam James 
Cc: Serge Hallyn 
Cc: Iker Pedrosa 
Cc: "Andrew J. Hesford" 
Cc: Michael Vetter 
Cc: 
Signed-off-by: Alejandro Colomar 
---
Range-diff against v0:
-:  -- > 1:  49c4c25b0a xstrtol: 1 is not a valid base

 lib/xstrtol.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/xstrtol.c b/lib/xstrtol.c
index e4bce43681..575c16d45f 100644
--- a/lib/xstrtol.c
+++ b/lib/xstrtol.c
@@ -83,7 +83,7 @@ __xstrtol (const char *s, char **ptr, int strtol_base,
   __strtol_t tmp;
   strtol_error err = LONGINT_OK;
 
-  assure (0 <= strtol_base && strtol_base <= 36);
+  assure (0 == strtol_base || (2 <= strtol_base && strtol_base <= 36));
 
   p = (ptr ? ptr : &t_ptr);
 
-- 
2.45.2



signature.asc
Description: PGP signature


Re: [PATCH v1] xstrtol: 1 is not a valid base

2024-07-18 Thread Bruno Haible
Alejandro Colomar wrote:
> If xstrtol() was being called with a base of 1, under some conditions it
> would invoke Undefined Behavior.

Yes, sure. A numeric base of 1 makes no sense, mathematically.

Thanks for the patch; applied.

Note that I disagree with the statement from
https://github.com/void-linux/void-packages/issues/51261#issuecomment-2237055195
 :
> Yet he introduced that bug a decade ago

I wouldn't call it a bug. Gnulib does not document that passing a base of 1
to xstrtol is valid. It's known to everyone in the field that a base of 1
makes no sense. So, what you saw here was a slightly incomplete input
validation check.

Thanks for the improvement.

Bruno






Re: stack-trace: Use libasan as an alternative to libbacktrace

2024-07-18 Thread Bruno Haible
Paul Eggert wrote:
> If I understand things correctly a similar problem was also on FreeBSD 
> with PIE and the bug wasn't fixed until November of last year:
> 
> https://github.com/llvm/llvm-project/commit/7440e4ed85aa992718d4b5ccd1c97724bc3bdd2c

This issue does not affect the Gnulib 'stack-trace' module, because
we link only to GCC's sanitizer library, not to clang's sanitizer library.

But looking into the situation on FreeBSD, it appears that the 'stack-trace'
module could be enhanced with clang-specific approaches:

  (A) Use the fact that clang's internal libraries
  libclang_rt.{asan,msan,tsan,ubsan_standalone}.a
  define the symbol __sanitizer_print_stack_trace, like GCC's libasan does.

  This would mean that m4/stack-trace.m4 would add to $CC and $CXX the
  option '-fsanitize=return' [1]. This appears to be the cheapest way to
  include __sanitizer_print_stack_trace in the executable.

  However, there are several drawbacks:
* An autoconf macro should not modify the value of CC (or CFLAGS).
* Programs compiled this way link to 6 additional shared libraries:
libthr.so.3
librt.so.1
libm.so.5
libexecinfo.so.1
libgcc_s.so.1
libelf.so.2
* The behaviour becomes dependent on some environment variables.
* The approach does not work if $CC already contains the option
  '-fsanitize-minimal-runtime'.

  (B) Do what __sanitizer_print_stack_trace does, namely invoke the program
  'llvm-symbolizer' [2]. This program is installed by default in /usr/bin
  in FreeBSD ≥ 13.

  There are several drawbacks here as well:
* Gnulib would need extra code to get the addresses from libexecinfo,
  determine VMA boundaries (using /proc, I guess), then invoke
  llvm-symbolizer as a subprocess.
* The approach does not work if llvm-symbolizer is not found in $PATH.
* Extra command-line options are needed on macOS, due to .dSYM.

The existing first-choice approach (libbacktrace) is better than either of
(A) or (B). Therefore I see no reason for implementing (A) or (B).

Bruno

[1] 
https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html#stack-traces-and-report-symbolization
[2] https://llvm.org/docs/CommandGuide/llvm-symbolizer.html






Re: [PATCH v1] xstrtol: 1 is not a valid base

2024-07-18 Thread Alejandro Colomar
Hi Bruno,

On Thu, Jul 18, 2024 at 08:06:07PM GMT, Bruno Haible wrote:
> Alejandro Colomar wrote:
> > If xstrtol() was being called with a base of 1, under some conditions it
> > would invoke Undefined Behavior.
> 
> Yes, sure. A numeric base of 1 makes no sense, mathematically.
> 
> Thanks for the patch; applied.
> 
> Note that I disagree with the statement from
> https://github.com/void-linux/void-packages/issues/51261#issuecomment-2237055195
>  :
> > Yet he introduced that bug a decade ago
> 
> I wouldn't call it a bug. Gnulib does not document that passing a base of 1
> to xstrtol is valid.

While it's your api, borrowing the name of strtol(3) comes with implied
semantics.  I think it'd be common to assume that unless specifically
documented, you behave like POSIX's strtol(3), which produces defined
behavior for a base of 1.  If not a bug, it was at least misleading.

I don't claim that POSIX's choice was good; actually I think it makes
little sense, and ISO C's choice of leaving it undefined was probably
better.

BTW, does gnulib have documentation for xstrtol()?  I couldn't find it.
And for MALLOC()?  I'm interested in reading both.

> It's known to everyone in the field that a base of 1
> makes no sense. So, what you saw here was a slightly incomplete input
> validation check.
> 
> Thanks for the improvement.

You're welcome!

Have a lovely night!
Alex

> Bruno

-- 



signature.asc
Description: PGP signature


Re: stack-trace: Use libasan as an alternative to libbacktrace

2024-07-18 Thread Bruno Haible
Paul Eggert wrote:
> If I understand things correctly a similar problem was also on FreeBSD 
> with PIE and the bug wasn't fixed until November of last year:
> 
> https://github.com/llvm/llvm-project/commit/7440e4ed85aa992718d4b5ccd1c97724bc3bdd2c

Btw, I don't know why they do this. For the purpose of producing correct
stack traces, it would be a better approach to use the llvm-symbolizer
option '--adjust-vma', that was introduced for precisely this purpose. [1]

Bruno

[1] https://reviews.llvm.org/D57151






[PATCH v1] xstrtol: Remove dead code

2024-07-18 Thread Alejandro Colomar
strtol(3) has a limited set of possible states:

-  The base was invalid.
   -  return 0
   -  errno = EINVAL
   -  endp is not set
   We cover this case with the assure() call, before strtol(3).

-  No conversion was performed.
   -  return 0
   -  errno may be EINVAL, or may be unset.
   -  *endp == s
   We cover this case with the 'if (*p == s)' check.

-  Conversion performed with extra trailing characters.
   -  return any number
   -  errno is not set
   -  *endp != s
   -  **endp != '\0'
   We let this fall through.

-  String fully converted.
   -  return any number
   -  errno is not set
   -  *endp != s
   -  **endp == '\0'
   We let this fall through.

-  Overflow
   -  return LONG_MAX or LONG_MIN
   -  errno = ERANGE
   -  *endp != s
   We cover this with 'else if (errno != 0)'

The condition '*endp != s && errno != 0 && errno != ERANGE' is
unreachable.  The only errno possible if '*endp != s' is ERANGE.

Fixes: 790855e18a1d (2003-10-14, "Handle invalid suffixes and overflow 
independently, so that ...")
Cc: Paul Eggert 
Cc: Bruno Haible 
Cc: Đoàn Trần Công Danh 
Cc: Eli Schwartz 
Cc: Sam James 
Cc: Serge Hallyn 
Cc: Iker Pedrosa 
Cc: "Andrew J. Hesford" 
Cc: Michael Vetter 
Cc: 
Signed-off-by: Alejandro Colomar 
---
Range-diff against v0:
-:  -- > 1:  1af702673f xstrtol: Remove dead code

 lib/xstrtol.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/lib/xstrtol.c b/lib/xstrtol.c
index 575c16d45f..5d10ce041e 100644
--- a/lib/xstrtol.c
+++ b/lib/xstrtol.c
@@ -110,10 +110,8 @@ __xstrtol (const char *s, char **ptr, int strtol_base,
   else
 return LONGINT_INVALID;
 }
-  else if (errno != 0)
+  else if (errno == ERANGE)
 {
-  if (errno != ERANGE)
-return LONGINT_INVALID;
   err = LONGINT_OVERFLOW;
 }
 
-- 
2.45.2



signature.asc
Description: PGP signature


Re: doc: Document the stack-trace and abort-debug modules

2024-07-18 Thread Bruno Haible
Paul Eggert wrote:
> > The stack-trace and abort-debug modules are now in a state where they
> > can be documented. Done as follows:
> 
> Thanks. Are these modules safe to use in signal handlers?

No, they aren't.

Find attached the log of 'ltrace gltestst/test-stack-trace'. While
libbacktrace carefully avoids malloc(), it calls fprintf or __fprintf_chk,
which is not async-signal-safe.

Also, in a signal handler, the stack trace is truncated: it starts at
the point where the kernel invoked the signal handler.

> I suspect that 
> Emacs would need that, in order to use them. Either way, it should be 
> documented.

Most code in Gnulib is not async-signal-safe. We can't document all that.

Multithread-safety restrictions is something we should document, though.
Multithreading has been the preferred approach over async signal handlers,
that are notoriously terrible to get right, for the last 20 years.

> Similarly, in POSIX an 'abort ()' call is async-signal-safe; is that 
> still true if the abort-debug module is used? This should be documented.

Good point. Done as follows:


2024-07-18  Bruno Haible  

abort-debug: Document better.
Suggested by Paul Eggert in
.
* lib/stdlib.in.h (abort): Add comment.
* doc/stack-trace.texi: Document what to do in signal handlers.

diff --git a/doc/stack-trace.texi b/doc/stack-trace.texi
index e7fc453d88..1b266c0cbd 100644
--- a/doc/stack-trace.texi
+++ b/doc/stack-trace.texi
@@ -65,3 +65,9 @@
 Thus, @code{abort ()} remains the idiom of choice
 for signaling a fatal situation that requires developer attention:
 it is useful both in debugging environments and production code.
+
+Note:
+While the original @code{abort} function is safe to call in signal handlers,
+the overridden @code{abort} function is not.
+In signal handlers, you will need to call the original @code{abort} function,
+by doing @code{#undef abort} first.
diff --git a/lib/stdlib.in.h b/lib/stdlib.in.h
index 7c6daa58b8..d86b3ad53c 100644
--- a/lib/stdlib.in.h
+++ b/lib/stdlib.in.h
@@ -241,6 +241,9 @@ _GL_WARN_ON_USE (_Exit, "_Exit is unportable - "
 
 
 #if @GNULIB_ABORT_DEBUG@
+/* Terminates the current process with signal SIGABRT.
+   Note: While the original abort() function is safe to call in signal 
handlers,
+   the overridden abort() function is not.  */
 # if @REPLACE_ABORT@
 #  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
 #   undef abort


ltrace.log.gz
Description: application/gzip


abort-debug: Don't assume that signal SIGABRT is unmasked and unhandled

2024-07-18 Thread Bruno Haible
Reading the man page of abort(), I see that it deals with situations
where SIGABRT is masked (via sigprocmask) or has a handler installed.
The override needs to have the same behaviour.


2024-07-18  Bruno Haible  

abort-debug: Don't assume that signal SIGABRT is unmasked and unhandled.
* lib/abort-debug.c (rpl_abort): At the end, call the original abort
function.

diff --git a/lib/abort-debug.c b/lib/abort-debug.c
index 2457ef07c2..cb78c44dc0 100644
--- a/lib/abort-debug.c
+++ b/lib/abort-debug.c
@@ -26,13 +26,14 @@
 /*   rpl_abort ();
is equivalent to
  print_stack_trace ();
- original abort (); // i.e. raise (SIGABRT);
+ original abort (); // essentially raise (SIGABRT);
  */
 void
 rpl_abort (void)
+#undef abort
 {
 #if HAVE_LIBBACKTRACE || HAVE_LIBASAN || HAVE_EXECINFO_H
   print_stack_trace_to (stderr);
 #endif
-  raise (SIGABRT);
+  abort ();
 }






Re: [PATCH v1] xstrtol: Remove dead code

2024-07-18 Thread Bruno Haible
Hi Alejandro,

> strtol(3) has a limited set of possible states:
> ...
> The condition '*endp != s && errno != 0 && errno != ERANGE' is
> unreachable.  The only errno possible if '*endp != s' is ERANGE.

Such a statement can be true if you look at the standards (ISO C, POSIX).

However, there's a difference between what the standards say and what the
systems actually do. The Gnulib documentation contains thousands of examples
of such differences.

Gnulib therefore (almost) never assumes that there are no possible errno
values besides the ones listed in the standards.
  - Some systems return "wrong" errno values. Example: [1]
  - Some systems fail with ENOMEM when memory is tight. Who says that
an implementation of strtol() cannot use malloc() ? Some implementations
of strtod() do use malloc().

So, what you call "dead code", I call "defensive programming". I would not
like to apply this patch.

Bruno

[1] https://www.gnu.org/software/gnulib/manual/html_node/getlogin_005fr.html






Re: [PATCH v1] xstrtol: Remove dead code

2024-07-18 Thread Alejandro Colomar
On Thu, Jul 18, 2024 at 11:09:40PM GMT, Bruno Haible wrote:
> Hi Alejandro,

Hi Bruno,

> > strtol(3) has a limited set of possible states:
> > ...
> > The condition '*endp != s && errno != 0 && errno != ERANGE' is
> > unreachable.  The only errno possible if '*endp != s' is ERANGE.
> 
> Such a statement can be true if you look at the standards (ISO C, POSIX).
> 
> However, there's a difference between what the standards say and what the
> systems actually do. The Gnulib documentation contains thousands of examples
> of such differences.
> 
> Gnulib therefore (almost) never assumes that there are no possible errno
> values besides the ones listed in the standards.
>   - Some systems return "wrong" errno values. Example: [1]
>   - Some systems fail with ENOMEM when memory is tight. Who says that
> an implementation of strtol() cannot use malloc() ? Some implementations
> of strtod() do use malloc().
> 
> So, what you call "dead code", I call "defensive programming". I would not
> like to apply this patch.

Makes sense.  I think we should document that possibility in the manual
page.  Maybe say that other errno values are possible in some systems?
Otherwise, it's already a hell of a function to take care of, and most
uses don't handle that possibility at the moment.  (Yet more reasons to
use a wrapper that returns -1 & sets errno on error, as the rest of
libc.)

Would you send a patch?  (I'd write it myself, but you probably can
provide more info in the commit message.)

Have a lovely night!
Alex

> 
> Bruno
> 
> [1] https://www.gnu.org/software/gnulib/manual/html_node/getlogin_005fr.html
> 
> 
> 

-- 



signature.asc
Description: PGP signature


Re: [PATCH v1] xstrtol: Remove dead code

2024-07-18 Thread Alejandro Colomar
[CC -= Andrew, per explicit request]

On Thu, Jul 18, 2024 at 11:25:11PM GMT, Alejandro Colomar wrote:
> On Thu, Jul 18, 2024 at 11:09:40PM GMT, Bruno Haible wrote:
> > Hi Alejandro,

Hi Bruno,

> > > strtol(3) has a limited set of possible states:
> > > ...
> > > The condition '*endp != s && errno != 0 && errno != ERANGE' is
> > > unreachable.  The only errno possible if '*endp != s' is ERANGE.
> > 
> > Such a statement can be true if you look at the standards (ISO C, POSIX).
> > 
> > However, there's a difference between what the standards say and what the
> > systems actually do. The Gnulib documentation contains thousands of examples
> > of such differences.
> > 
> > Gnulib therefore (almost) never assumes that there are no possible errno
> > values besides the ones listed in the standards.
> >   - Some systems return "wrong" errno values. Example: [1]
> >   - Some systems fail with ENOMEM when memory is tight. Who says that
> > an implementation of strtol() cannot use malloc() ? Some implementations
> > of strtod() do use malloc().
> > 
> > So, what you call "dead code", I call "defensive programming". I would not
> > like to apply this patch.

On the other hand, I'm not sure that defensive programming is valid in
this case.  I already discussed this topic with Serge (but we didn't
have in mind any specific implementation) some time ago, and,

We'd need to know the precise specification of that system that can set
errno = ENOMEM.

Is *endp guaranteed to be set?  Or may it be unset (as happens with
EINVAL)?

If it is allowed to keep *endp unset, then the first `if (*p == s)`
would already be UB.  And for truly being defensive, we'd need to assume
that it may leave *endp unset.  Thus we cannot read that until we know
that no errno has been set.  But then comes the problem that some
systems set EINVAL on what strtoi(3) calls ECANCELED.  To work with all
of those systems, we'd probably need to pass a dummy NULL to make sure
we can inspect *endp regardless of strtol(3) having set it or not:

intmax_t
strtoi(char *s, char **restrict endp, int base,
intmax_t min, intmax_t max, int *restrict status)
{
interrno_saved, st;
char   *e;
char   **ep;
intmax_t   n;

e = NULL;
ep = &e;

if (status == NULL)
status = &st;

if (base != 0 && (base < 2 || base > 36)) {
*status = EINVAL;
return MAX(min, MIN(max, 0));
}

errno_saved = errno;
errno = 0;

n = strtoimax(s, ep, base);

if (errno == ERANGE || n < min || n > max)
*status = ERANGE;
else if (e == s && (errno == 0 || errno == EINVAL))
*status = ECANCELED;
else if (errno != 0)
*status = errno;
else if (*e != '\0')
*status = ENOTSUP;
else
*status = 0;

errno = errno_saved;

if (endp != NULL)
*endp = e;

return MAX(min, MIN(max, n));
}

Does this make sense?

Have a lovely night!
Alex

> 
> Makes sense.  I think we should document that possibility in the manual
> page.  Maybe say that other errno values are possible in some systems?
> Otherwise, it's already a hell of a function to take care of, and most
> uses don't handle that possibility at the moment.  (Yet more reasons to
> use a wrapper that returns -1 & sets errno on error, as the rest of
> libc.)
> 
> Would you send a patch?  (I'd write it myself, but you probably can
> provide more info in the commit message.)
> 
> Have a lovely night!
> Alex
> 
> > 
> > Bruno
> > 
> > [1] https://www.gnu.org/software/gnulib/manual/html_node/getlogin_005fr.html
> > 
> > 
> > 
> 
> -- 
> 



-- 



signature.asc
Description: PGP signature


Re: [PATCH v1] xstrtol: Remove dead code

2024-07-18 Thread Bruno Haible
Alejandro Colomar wrote:
> >   - Some systems return "wrong" errno values. Example: [1]
> >   - Some systems fail with ENOMEM when memory is tight. Who says that
> > an implementation of strtol() cannot use malloc() ? Some implementations
> > of strtod() do use malloc().
> > 
> > So, what you call "dead code", I call "defensive programming". I would not
> > like to apply this patch.
> 
> Makes sense.  I think we should document that possibility in the manual
> page.

Well, I wouldn't want to document just _theoretical_ platforms. The set of
manual pages has a certain scope, regarding platform, probably Linux
(and Hurd, maybe?). It's the behaviour on these platforms which should
be documented, nothing more, nothing less.

Defensive programming means to imagine other behaviours that could
possibly occur. It is subjective; some programmers want to be more cautious
than others.

> Maybe say that other errno values are possible in some systems?

Other errno values are always possible, as far as I understand POSIX.

section 1.2 ERRORS.

It would be overkill to state this in hundreds of manual pages, IMO.

Bruno






Re: [PATCH v1] xstrtol: Remove dead code

2024-07-18 Thread Alejandro Colomar
Hi Bruno,

On Fri, Jul 19, 2024 at 12:34:39AM GMT, Bruno Haible wrote:
> Alejandro Colomar wrote:
> > >   - Some systems return "wrong" errno values. Example: [1]
> > >   - Some systems fail with ENOMEM when memory is tight. Who says that
> > > an implementation of strtol() cannot use malloc() ? Some 
> > > implementations
> > > of strtod() do use malloc().
> > > 
> > > So, what you call "dead code", I call "defensive programming". I would not
> > > like to apply this patch.
> > 
> > Makes sense.  I think we should document that possibility in the manual
> > page.
> 
> Well, I wouldn't want to document just _theoretical_ platforms.

While it may be theoretical for strtol(3), you said it was real for
strtod(3), and strtod(3) defers to strtol(3) for the example program.

We should provide a portable example of use of strtod(3), and rather
than writing another example for strtod(3), maybe we could improve the
strtol(3) one for theoretical implementations.


> The set of
> manual pages has a certain scope, regarding platform, probably Linux
> (and Hurd, maybe?). It's the behaviour on these platforms which should
> be documented, nothing more, nothing less.

Not really.  We do document portability to other Unix systems.  Mainly
the BSDs, but in some important cases we document others.

> 
> Defensive programming means to imagine other behaviours that could
> possibly occur. It is subjective; some programmers want to be more cautious
> than others.
> 
> > Maybe say that other errno values are possible in some systems?
> 
> Other errno values are always possible, as far as I understand POSIX.
> 
> section 1.2 ERRORS.

True.

> It would be overkill to state this in hundreds of manual pages, IMO.

strtol(3) is special-enough regarding errors, that it might make sense.
Even if we don't mention it in ERRORS, it would make sense to fix the
example program to make it portable.

> 
> Bruno

Have a lovely night!
Alex

-- 



signature.asc
Description: PGP signature


Re: [PATCH v1] xstrtol: Remove dead code

2024-07-18 Thread Alejandro Colomar
On Fri, Jul 19, 2024 at 12:14:19AM GMT, Alejandro Colomar wrote:
> [CC -= Andrew, per explicit request]
> 
> On Thu, Jul 18, 2024 at 11:25:11PM GMT, Alejandro Colomar wrote:
> > On Thu, Jul 18, 2024 at 11:09:40PM GMT, Bruno Haible wrote:
> > > Hi Alejandro,
> 
> Hi Bruno,
> 
> > > > strtol(3) has a limited set of possible states:
> > > > ...
> > > > The condition '*endp != s && errno != 0 && errno != ERANGE' is
> > > > unreachable.  The only errno possible if '*endp != s' is ERANGE.
> > > 
> > > Such a statement can be true if you look at the standards (ISO C, POSIX).
> > > 
> > > However, there's a difference between what the standards say and what the
> > > systems actually do. The Gnulib documentation contains thousands of 
> > > examples
> > > of such differences.
> > > 
> > > Gnulib therefore (almost) never assumes that there are no possible errno
> > > values besides the ones listed in the standards.
> > >   - Some systems return "wrong" errno values. Example: [1]
> > >   - Some systems fail with ENOMEM when memory is tight. Who says that
> > > an implementation of strtol() cannot use malloc() ? Some 
> > > implementations
> > > of strtod() do use malloc().
> > > 
> > > So, what you call "dead code", I call "defensive programming". I would not
> > > like to apply this patch.
> 
> On the other hand, I'm not sure that defensive programming is valid in
> this case.  I already discussed this topic with Serge (but we didn't
> have in mind any specific implementation) some time ago, and,
> 
> We'd need to know the precise specification of that system that can set
> errno = ENOMEM.
> 
> Is *endp guaranteed to be set?  Or may it be unset (as happens with
> EINVAL)?
> 
> If it is allowed to keep *endp unset, then the first `if (*p == s)`
> would already be UB.  And for truly being defensive, we'd need to assume
> that it may leave *endp unset.  Thus we cannot read that until we know
> that no errno has been set.  But then comes the problem that some
> systems set EINVAL on what strtoi(3) calls ECANCELED.  To work with all
> of those systems, we'd probably need to pass a dummy NULL to make sure
> we can inspect *endp regardless of strtol(3) having set it or not:
> 
> intmax_t
> strtoi(char *s, char **restrict endp, int base,
> intmax_t min, intmax_t max, int *restrict status)
> {
>   interrno_saved, st;
>   char   *e;
>   char   **ep;
>   intmax_t   n;
> 
>   e = NULL;
>   ep = &e;
> 
>   if (status == NULL)
>   status = &st;
> 
>   if (base != 0 && (base < 2 || base > 36)) {
>   *status = EINVAL;
>   return MAX(min, MIN(max, 0));
>   }
> 
>   errno_saved = errno;
>   errno = 0;
> 
>   n = strtoimax(s, ep, base);
> 
>   if (errno == ERANGE || n < min || n > max)
>   *status = ERANGE;
>   else if (e == s && (errno == 0 || errno == EINVAL))
>   *status = ECANCELED;
>   else if (errno != 0)
>   *status = errno;
>   else if (*e != '\0')
>   *status = ENOTSUP;
>   else
>   *status = 0;

Hmm, bug there.  I should have written:

if (errno == ERANGE)
*status = ERANGE;
else if (e == s && (errno == 0 || errno == EINVAL))
*status = ECANCELED;
else if (errno != 0)
*status = errno;
else if (n < min || n > max)
*status = ERANGE;
else if (*e != '\0')
*status = ENOTSUP;
else
*status = 0;

> 
>   errno = errno_saved;
> 
>   if (endp != NULL)
>   *endp = e;
> 
>   return MAX(min, MIN(max, n));
> }
> 
> Does this make sense?
> 
> Have a lovely night!
> Alex
> 
> > 
> > Makes sense.  I think we should document that possibility in the manual
> > page.  Maybe say that other errno values are possible in some systems?
> > Otherwise, it's already a hell of a function to take care of, and most
> > uses don't handle that possibility at the moment.  (Yet more reasons to
> > use a wrapper that returns -1 & sets errno on error, as the rest of
> > libc.)
> > 
> > Would you send a patch?  (I'd write it myself, but you probably can
> > provide more info in the commit message.)
> > 
> > Have a lovely night!
> > Alex
> > 
> > > 
> > > Bruno
> > > 
> > > [1] 
> > > https://www.gnu.org/software/gnulib/manual/html_node/getlogin_005fr.html
> > > 
> > > 
> > > 
> > 
> > -- 
> > 
> 
> 
> 
> -- 
> 



-- 



signature.asc
Description: PGP signature


Re: [PATCH v1] xstrtol: Remove dead code

2024-07-18 Thread Andrew J. Hesford
Stop tagging me in your submissions. I have no involvement in any of this 
activity.
-- 
Andrew J. Hesford
a...@sideband.org
[Mobile communication]

> On Jul 18, 2024, at 5:25 PM, Alejandro Colomar  wrote:
> 
> On Thu, Jul 18, 2024 at 11:09:40PM GMT, Bruno Haible wrote:
>> Hi Alejandro,
> 
> Hi Bruno,
> 
>>> strtol(3) has a limited set of possible states:
>>> ...
>>> The condition '*endp != s && errno != 0 && errno != ERANGE' is
>>> unreachable.  The only errno possible if '*endp != s' is ERANGE.
>> 
>> Such a statement can be true if you look at the standards (ISO C, POSIX).
>> 
>> However, there's a difference between what the standards say and what the
>> systems actually do. The Gnulib documentation contains thousands of examples
>> of such differences.
>> 
>> Gnulib therefore (almost) never assumes that there are no possible errno
>> values besides the ones listed in the standards.
>>  - Some systems return "wrong" errno values. Example: [1]
>>  - Some systems fail with ENOMEM when memory is tight. Who says that
>>an implementation of strtol() cannot use malloc() ? Some implementations
>>of strtod() do use malloc().
>> 
>> So, what you call "dead code", I call "defensive programming". I would not
>> like to apply this patch.
> 
> Makes sense.  I think we should document that possibility in the manual
> page.  Maybe say that other errno values are possible in some systems?
> Otherwise, it's already a hell of a function to take care of, and most
> uses don't handle that possibility at the moment.  (Yet more reasons to
> use a wrapper that returns -1 & sets errno on error, as the rest of
> libc.)
> 
> Would you send a patch?  (I'd write it myself, but you probably can
> provide more info in the commit message.)
> 
> Have a lovely night!
> Alex
> 
>> 
>> Bruno
>> 
>> [1] https://www.gnu.org/software/gnulib/manual/html_node/getlogin_005fr.html
>> 
>> 
>> 
> 
> --
> 
> 




Re: [PATCH v1] xstrtol: 1 is not a valid base

2024-07-18 Thread Paul Eggert

On 2024-07-18 12:53, Alejandro Colomar wrote:

I think it'd be common to assume that unless specifically
documented, you behave like POSIX's strtol(3), which produces defined
behavior for a base of 1.


Fair enough. I installed the attached Gnulib patch which addresses that 
point, along with the other points you raised about xstrtol that I 
understood. Since the system strtol can support base 1 as an extension, 
xstrtol now does whatever the system does so there's no need for the 
'assume'. (Not that any Gnulib-using programs care) (Oh, and by the 
way, I don't think I put that 'assume'/'assert'/whatever code in there 
decades ago as I'm not a fan of that sort of thing)


PS. Sorry about missing a space in the ChangeLog entry - I fixed that in 
a followup patch.From 64ddc975e72cb55d2b2d755c25603bd70312aa5e Mon Sep 17 00:00:00 2001
From: Paul Eggert 
Date: Thu, 18 Jul 2024 17:28:36 -0700
Subject: [PATCH] xstrtol: document and stray less from strtol
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

This patch alters xstrtol behavior slightly, in areas are not
likely to affect any real callers, by making xstrtol behave more
like the system strtol.  In particular, it lets xstrtol support
bases other than those required by POSIX, if the underlying
implementation does; this removes the need for an ‘assert’.
It also uses ‘restrict’ like the underlying strtol does.
The patch also documents xstrtol in xstrtol.h.
Problems reported by AlejandroColomar in:
https://lists.gnu.org/r/bug-gnulib/2024-07/msg00159.html
* lib/xstrtol.c: Do not include stdio.h or assure.h.
(__xstrtol): Use same parameter names as POSIX, to make it
easier for outsiders to follow.  Assume C99 decls after statement.
Do not require the base to be 0, or 2-36, as the underlying
implementation is allowed to support other bases.
Do not assume isspace preserves errno.
* lib/xstrtol.h (_DECLARE_XSTRTOL): Declare pointers to be
‘restrict’, for compatibility with C.
* m4/xstrtol.m4 (gl_XSTRTOL): Require AC_C_RESTRICT.
* modules/xstrtol (Depends-on): Remove ‘assure’.
---
 ChangeLog   | 23 +++
 lib/xstrtol.c   | 59 +++--
 lib/xstrtol.h   | 17 +-
 m4/xstrtol.m4   |  3 ++-
 modules/xstrtol |  1 -
 5 files changed, 64 insertions(+), 39 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 833ecd6d80..1728846392 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,26 @@
+2024-07-18  Paul Eggert  
+
+	xstrtol: document and stray less from strtol
+	This patch alters xstrtol behavior slightly, in areas are not
+	likely to affect any real callers, by making xstrtol behave more
+	like the system strtol.  In particular, it lets xstrtol support
+	bases other than those required by POSIX, if the underlying
+	implementation does; this removes the need for an ‘assert’.
+	It also uses ‘restrict’ like the underlying strtol does.
+	The patch also documents xstrtol in xstrtol.h.
+	Problems reported by AlejandroColomar in:
+	https://lists.gnu.org/r/bug-gnulib/2024-07/msg00159.html
+	* lib/xstrtol.c: Do not include stdio.h or assure.h.
+	(__xstrtol): Use same parameter names as POSIX, to make it
+	easier for outsiders to follow.  Assume C99 decls after statement.
+	Do not require the base to be 0, or 2-36, as the underlying
+	implementation is allowed to support other bases.
+	Do not assume isspace preserves errno.
+	* lib/xstrtol.h (_DECLARE_XSTRTOL): Declare pointers to be
+	‘restrict’, for compatibility with C.
+	* m4/xstrtol.m4 (gl_XSTRTOL): Require AC_C_RESTRICT.
+	* modules/xstrtol (Depends-on): Remove ‘assure’.
+
 2024-07-18  Bruno Haible  
 
 	abort-debug: Don't assume that signal SIGABRT is unmasked and unhandled.
diff --git a/lib/xstrtol.c b/lib/xstrtol.c
index 575c16d45f..c3145171f3 100644
--- a/lib/xstrtol.c
+++ b/lib/xstrtol.c
@@ -30,10 +30,6 @@
 
 #include "xstrtol.h"
 
-/* Some pre-ANSI implementations (e.g. SunOS 4)
-   need stderr defined if assertion checking is enabled.  */
-#include 
-
 #include 
 #include 
 #include 
@@ -45,7 +41,6 @@
 # include 
 #endif
 
-#include "assure.h"
 #include "intprops.h"
 
 static strtol_error
@@ -72,26 +67,17 @@ bkm_scale_by_power (__strtol_t *x, int base, int power)
   return err;
 }
 
-/* FIXME: comment.  */
-
 strtol_error
-__xstrtol (const char *s, char **ptr, int strtol_base,
-   __strtol_t *val, const char *valid_suffixes)
+__xstrtol (char const *nptr, char **endptr, int base,
+   __strtol_t *val, char const *valid_suffixes)
 {
   char *t_ptr;
-  char **p;
-  __strtol_t tmp;
-  strtol_error err = LONGINT_OK;
-
-  assure (0 == strtol_base || (2 <= strtol_base && strtol_base <= 36));
-
-  p = (ptr ? ptr : &t_ptr);
-
-  errno = 0;
+  char **p = endptr ? endptr : &t_ptr;
+  *p = (char *) nptr;
 
   if (! TYPE_SIGNED (__strtol_t))
 {
-  const char *q = s;
+  char const *q = nptr;
   unsigned char ch = *q;
   while (isspace (ch))
 ch = *++q;
@@ -99,16 +85,17 @@

xstrtod, xstrtold: Add documentation

2024-07-18 Thread Bruno Haible
Inspired by the discussion around xstrtol, I looked at xstrtod.

I plan to commit this documentation, when savannah allows. And to look
at the two FIXMEs regarding platform-dependent behaviour...


2024-07-18  Bruno Haible  

xstrtod, xstrtold: Add documentation.
* lib/xstrtod.h (xstrtod, xstrtold): Add comments.
* lib/xstrtod.c (XSTRTOD): Add two FIXMEs.

diff --git a/lib/xstrtod.c b/lib/xstrtod.c
index 55b4bb4a8f..f99c943805 100644
--- a/lib/xstrtod.c
+++ b/lib/xstrtod.c
@@ -59,6 +59,8 @@ XSTRTOD (char const *str, char const **ptr, DOUBLE *result,
   /* Allow underflow (in which case CONVERT returns zero),
  but flag overflow as an error.  The user can decide
  to use the limits in RESULT upon ERANGE.  */
+  /* FIXME: Upon underflow, CONVERT may return non-zero.  */
+  /* FIXME: errno is unchanged if (math_errhandling & MATH_ERRNO) == 0.  */
   if (val != 0 && errno == ERANGE)
 ok = false;
 }
diff --git a/lib/xstrtod.h b/lib/xstrtod.h
index 9ae4be13da..a1d2ce06f7 100644
--- a/lib/xstrtod.h
+++ b/lib/xstrtod.h
@@ -26,8 +26,37 @@ extern "C" {
 #endif
 
 
+/* Converts the initial portion of the string starting at STR (if PTR != NULL)
+   or the entire string starting at STR (if PTR == NULL) to a number of type
+   'double'.
+   CONVERT should be a conversion function with the same calling conventions
+   as strtod, such as strtod or c_strtod.
+   If successful, it returns true, with *RESULT set to the result.
+   If it fails, it returns false, with *RESULT set to
+ - 0.0 upon conversion error,
+ - ±HUGE_VAL (i.e. ±Infinity) upon overflow,
+ - a value near zero upon underflow (only in implementations which consider
+   underflow to be an error),
+   and _maybe_ errno set as well.
+   In both cases, if PTR != NULL, *PTR is set to point to the character after
+   the parsed number.  */
 bool xstrtod (const char *str, const char **ptr, double *result,
   double (*convert) (char const *, char **));
+
+/* Converts the initial portion of the string starting at STR (if PTR != NULL)
+   or the entire string starting at STR (if PTR == NULL) to a number of type
+   'long double'.
+   CONVERT should be a conversion function with the same calling conventions
+   as strtold, such as strtold or c_strtold.
+   If successful, it returns true, with *RESULT set to the result.
+   If it fails, it returns false, with *RESULT set to
+ - 0.0L upon conversion error,
+ - ±HUGE_VALL (i.e. ±Infinity) upon overflow,
+ - a value near zero upon underflow (only in implementations which consider
+   underflow to be an error),
+   and _maybe_ errno set as well.
+   In both cases, if PTR != NULL, *PTR is set to point to the character after
+   the parsed number.  */
 bool xstrtold (const char *str, const char **ptr, long double *result,
long double (*convert) (char const *, char **));