Re: Bash printf should diagnose integer overflow

2024-03-21 Thread Paul Eggert

On 2024-03-21 13:31, Chet Ramey wrote:


Interesting. I can't reproduce this. Using the commit to which your patches
apply, without applying any of them, on a fresh Virtualbox Fedora 39
install, I get consistent `make tests' output every time.


I just now tried the latest devel commit 
(b1e7f68032bd90dec1a2968a616b32a469929c78) on Fedora 39 running on bare 
hardware (AMD Phenom II X4 910e), with Fedora patches up through today 
and with 873 locales installed (output of "locale -a | wc"). Often "make 
check" output was the same, but sometimes it differed. Here's the first 
difference (after this I stopped checking):



$ diff -u :check[34].log
--- :check3.log 2024-03-21 14:09:48.069094929 -0700
+++ :check4.log 2024-03-21 22:39:51.391869014 -0700
@@ -327,6 +327,10 @@
 warning: UNIX versions number signals and schedule processes differently.
 warning: If output differing only in line numbers is produced, please
 warning: do not consider this a test failure.
+111c111
+< ./trap8.sub: DEBUG warning: run_pending_traps: recursive invocation while 
running trap for signal 17
+---
+> CHLD
 run-type
 run-varenv
 warning: some of these tests will fail if arrays have not


I recall other differences in past runs.



Output that differs in error message language isn't a failure.


Yes, and I assumed that since output like the above didn't affect the 
exit status of "make check", it wasn't that important.





Re: Bash printf should diagnose integer overflow

2024-03-19 Thread Paul Eggert

On 3/18/24 12:41, Chet Ramey wrote:

I'm not sure what you're using, but that was not my experience on
macOS.


I am using Fedora 39 (the current version) on x86-64. That could explain 
our differing experiences.


I see several diagnostics (mostly diff output) with "make check" on 
Fedora 39. The diagnostics can vary from run to run, i.e., they aren't 
necessarily reproducible. I assumed these were OK because I got 'em 
before any patches. From my point of view the diff output was sort of 
random, so I eyeballed it and guessed which outputs mattered and which 
didn't. Apparently I guessed incorrectly with fw.


At some point I suppose it'd be nice if 'make check' succeeded (exit 
status 0) or failed (nonzero exit status) so that it is easy for 
non-experts to tell which diagnostics matter; that's what many other 
packages do. For now I'd rather focus on the integer overflow issues in 
Bash, while they're fresh in my mind.




First, the patched version doesn't build on macOS because your patches
don't include . Once you get past that, printf goes into an
infinite loop on

printf -v s "%b" ""

in printstr because `fw' is used unititialized (and randomly set to some
ridiculously large value). That and the old test's incorrect expectation
that a field width of 9223372036854775825 would always overflow to -1 (a
left-adjusted field width of 1) instead of being flagged as overflow are
the UB I was talking about.


Yes, I see now. I didn't get that behavior on Fedora, perhaps because 
the junk in fw was benign there.


Perhaps at some point we could enable more of GCC's static checking to 
catch silly mistakes like that. Again, a task for another time.




It should be mostly there in the changes I pushed today, once I made it
through the above.


Thanks, I checked the devel branch against what I submitted, found a few 
errors, and while reviewing all this found and fixed a few other 
integer-overflow issues in Bash. Proposed patches attached, in "git 
format-patch" format so you can use "git am" on them. If there's some 
reason a patch shouldn't be applied please let me know so that I can 
stop worrying about that subissue.From ccf906084c3aaf7cd75f0ee1e035986af7d58a82 Mon Sep 17 00:00:00 2001
From: Paul Eggert 
Date: Mon, 18 Mar 2024 13:44:27 -0700
Subject: [PATCH 01/10] Improve use of HAVE_C_BOOL
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* bashansi.h: If HAVE_C_BOOL, bool works as per C23, so
we needn’t include  or define any workarounds.
In pre-C99 compilers arrange for ‘false’ and ‘true’ as well;
although Bash doesn't use either symbol it's safer to
be compatible in case some system .h file unwisely uses it.
---
 bashansi.h | 12 +++-
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/bashansi.h b/bashansi.h
index 4feaadfb..0bac61b4 100644
--- a/bashansi.h
+++ b/bashansi.h
@@ -35,13 +35,15 @@
 #  include "ansi_stdlib.h"
 #endif /* !HAVE_STDLIB_H */
 
-/* Prefer stdbool.h if we have it, maybe have to rethink this later */
-#if defined (HAVE_STDBOOL_H)
-#  include 
-#else
-#  ifndef HAVE_C_BOOL
+/* If bool is not builtin, prefer stdbool.h if we have it. */
+#ifndef HAVE_C_BOOL
+#  ifdef HAVE_STDBOOL_H
+#include 
+#  else
 #undef bool
 typedef unsigned char bool;
+#define false 0
+#define true 1
 #  endif
 #endif
 
-- 
2.44.0

From aeb21592ed88cac5072bcd41b2c478766d6e1dee Mon Sep 17 00:00:00 2001
From: Paul Eggert 
Date: Mon, 18 Mar 2024 13:54:29 -0700
Subject: [PATCH 02/10] Minor mkseq clarification/tuning
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* braces.c (mkseq): All branches of an if end in ‘result[i++] =
t;’, so hoist that out of the ‘if’.
---
 braces.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/braces.c b/braces.c
index 444807a7..194000c2 100644
--- a/braces.c
+++ b/braces.c
@@ -399,7 +399,7 @@ mkseq (intmax_t start, intmax_t end, intmax_t incr, int type, size_t width)
   QUIT;
 #endif
   if (type == ST_INT)
-	result[i++] = t = itos (n);
+	t = itos (n);
   else if (type == ST_ZINT)
 	{
 	  size_t tlen;
@@ -419,7 +419,6 @@ mkseq (intmax_t start, intmax_t end, intmax_t incr, int type, size_t width)
 		  memset (t + (n < 0), '0', width - tlen);
 		}
 	}
-	  result[i++] = t;
 	}
   else
 	{
@@ -428,9 +427,10 @@ mkseq (intmax_t start, intmax_t end, intmax_t incr, int type, size_t width)
 	  t[0] = n;
 	  t[1] = '\0';
 	}
-	  result[i++] = t;
 	}
 
+  result[i++] = t;
+
   /* We failed to allocate memory for this number, so we bail. */
   if (t == 0)
 	{
-- 
2.44.0

From 3c124056fbd07b31b259ec0fd87781d9a3ed4eed Mon Sep 17 00:00:00 2001
From: Paul Eggert 
Date: Mon, 18 Mar 2024 13:57:36 -0700
Subject: [PATCH 03/10] 

Re: Bash printf should diagnose integer overflow

2024-03-18 Thread Paul Eggert

On 3/18/24 07:40, Chet Ramey wrote:

Thanks for the patches. They introduce a number of regressions, some due
to the different overflow handling; several not. I urge everyone who
submits non-trivial patches to run the test suite (`make tests') on their
patched versions before sending them in.


I ran "make check" (equivalent to "make tests") and it looked to me like 
all the tests passed. The test output chattered a lot, and contained a 
lot of 'diff output', but then it did the same thing without the 
proposed patches and as far as I could tell nothing was unusual about 
the chatter. And since "make tests" exited with zero status, the tests 
appeared successful to me. Is there some documentation for how to 
interpret "make tests" output?


One thing that caused trouble for me is that I could not use the 
following shell command on my terminal:


  $ make tests >:tests.log 2>&1 < /dev/null &

because the tests would at some point stop in the background. Apparently 
some of the tests require access to the controlling terminal, which is a 
problem if you're trying to run them in the background. (Perhaps that 
explains why the tests succeeded for me but failed for you.)


I see that you're part way towards improving integer overflow checking, 
as you've added stdckdint.in.h to the devel branch but are not using 
stdckint.h yet. If there's any further way I can help to get integer 
overflow checking to work as well as my proposed patches tried to do, 
please let me know.




Re: Bash printf should diagnose integer overflow

2024-03-13 Thread Paul Eggert

On 3/13/24 11:13, Chet Ramey wrote:


Thanks for the report. The most appropriate fix for this particular issue
is to display an error message if printf returns < 0, instead of
suppressing it unless the -v option has been set.


Oh, good point. This simplifies things a bit, though Bash still needs to 
do its own overflow checking for cases like "printf '%2147483648q' ''" 
and "printf '%*s' 2147483648 ''" when the Bash code itself is parsing 
the integer, rather than relying on printf(3) to do it.


Revised patchset attached. The first patch uses the fix you suggested; 
the remaining patches are similar to what I sent earlier, except the 
last one is simplified since it doesn't need to worry about inline width 
and precision when printf will do the checking. These patches are 
relative to Bash devel commit bf944fe91ffa97743ad86f6db6f3b84c78207a78 
dated today at 09:33:32 -0400.


From 4ca64cfc3de1d9cf75490b85891e88fbf0405538 Mon Sep 17 00:00:00 2001
From: Paul Eggert 
Date: Wed, 13 Mar 2024 17:00:17 -0700
Subject: [PATCH 1/5] printf now diagnoses underlying printf failure

* builtins/printf.def (printf_builtin):
Report an error if printf returns -1, even when
-v is not used, so that a shell command like
"printf '%1s' ''"
does not fail silently.
---
 builtins/printf.def | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/builtins/printf.def b/builtins/printf.def
index 49757f5c..b1140dc4 100644
--- a/builtins/printf.def
+++ b/builtins/printf.def
@@ -178,8 +178,7 @@ extern int errno;
 if (nw < 0 || (vflag == 0 && ferror (stdout))) \
   { \
 	QUIT; \
-	if (vflag) \
-	  builtin_error ("%s", strerror (errno)); \
+	builtin_error ("%s", strerror (errno)); \
 	PRETURN (EXECUTION_FAILURE); \
   } \
 tw += nw; \
-- 
2.44.0

From 21a3752666536f390f9d5d8378171a4323745adc Mon Sep 17 00:00:00 2001
From: Paul Eggert 
Date: Fri, 8 Mar 2024 21:58:46 -0800
Subject: [PATCH 2/5] maint: add support for C23-style stdckdint.h
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

This is so that Bash can do proper checking for internal
integer overflow.  This change doesn't change Bash proper;
it only adds the minimum changes needed so that
C23-style "#include " will work portably
to older systems.
* Makefile.in (CREATED_CONFIGURE): Add stdckdint.h.
* configure.ac: Check for stdckdint.h.  If it works, remove
any stdckdint.h left over from a previous ‘configure’;
otherwise, create one.
* .gitignore: Add stdckdint.h.
* include/stdckdint.in.h, include/intprops-internal.h:
New files, copied verbatim from Gnulib.
---
 .gitignore  |   1 +
 Makefile.in |   1 +
 configure.ac|   7 +
 include/intprops-internal.h | 397 
 include/stdckdint.in.h  |  35 
 5 files changed, 441 insertions(+)
 create mode 100644 include/intprops-internal.h
 create mode 100644 include/stdckdint.in.h

diff --git a/.gitignore b/.gitignore
index 2c10177c..15b219d3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -70,6 +70,7 @@ support/bashbug.sh
 lsignames.h
 pathnames.h
 signames.h
+stdckdint.h
 version.h
 syntax.c
 stamp-h
diff --git a/Makefile.in b/Makefile.in
index 41443c6d..2b4b713c 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -584,6 +584,7 @@ CREATED_SUPPORT = signames.h recho$(EXEEXT) zecho$(EXEEXT) printenv$(EXEEXT) \
 		  mksyntax${EXEEXT} syntax.c $(VERSPROG) $(VERSOBJ) \
 		  buildversion.o mksignames.o signames.o buildsignames.o
 CREATED_CONFIGURE = config.h config.cache config.status config.log \
+		stdckdint.h \
 		stamp-h po/POTFILES config.status.lineno
 CREATED_MAKEFILES = Makefile builtins/Makefile doc/Makefile \
 		lib/readline/Makefile lib/glob/Makefile \
diff --git a/configure.ac b/configure.ac
index d4ca74e5..7befb6c2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -787,6 +787,7 @@ BASH_HEADER_INTTYPES
 
 AC_CHECK_HEADERS(unistd.h stdlib.h varargs.h limits.h string.h \
 		 memory.h locale.h termcap.h termio.h termios.h dlfcn.h \
+		 stdckdint.h \
 		 stdbool.h stddef.h stdint.h netdb.h pwd.h grp.h strings.h \
 		 regex.h syslog.h ulimit.h)
 AC_CHECK_HEADERS(sys/pte.h sys/stream.h sys/select.h sys/file.h sys/ioctl.h \
@@ -1352,4 +1353,10 @@ AC_CONFIG_FILES([Makefile builtins/Makefile lib/readline/Makefile \
 dnl Makefile uses this timestamp file to record whether config.h is up to date.
 AC_CONFIG_COMMANDS([stamp-h], [echo timestamp > stamp-h])
 
+if test "$ac_cv_header_stdckdint_h" = yes; then
+  rm -f stdckdint.h
+else
+  echo '#include ' >stdckdint.h
+fi
+
 AC_OUTPUT
diff --git a/include/intprops-internal.h b/include/intprops-internal.h
new file mode 100644
index ..c8a87d2b
--- /dev/null
+++ b/include/intprops-internal.h
@@ -0,0 +1,397 @@
+/* intprops-internal.h -- propert

Bash printf should diagnose integer overflow

2024-03-12 Thread Paul Eggert

Configuration Information:
Machine: x86_64
OS: linux-gnu
Compiler: gcc
Compilation CFLAGS: -g -O2
uname output: Linux penguin.cs.ucla.edu 6.7.7-200.fc39.x86_64 #1 SMP 
PREEMPT_DYNAMIC Fri Mar  1 16:53:59 UTC 2024 x86_64 GNU/Linux

Machine Type: x86_64-redhat-linux-gnu

Bash Version: 5.3
Patch Level: 26
Release Status: devel

Description:
Commands like "printf '%1s' ''"
silently ignore width and precision.  They should report the
integer overflow before continuing with a lesser width or
precision.  (I ran into this bug while using Bash to output
very long strings of spaces for some test cases.)

Repeat-By:
printf '%1s' ''

It prints nothing.  It should print a diagnostic if it
cannot do the requested operation.

Fix:
Bash should use C23  to check for integer
overflow.  Gnulib supplies a replacement stdckdint.h that works
on pre-C23 platforms; it's been extensively tested in other GNU
apps and doesn't require much setup.

The attached patches first add  to Bash, then
replace Bash's by-hand overflow checking (which I think I
contributed a while ago, if memory serves) with uses of the
standard C23 macros, and finally fixes printf.  Although there
are several other integer overflow bugs in Bash I thought
I'd send these fixes in now.

These patches use the Gnulib files intprops-internal.h and
stdckdint.in.h unmodified.  I thought this would be better
than trying to simplify them to cover just Bash's needs, as
it will make it easier to sync with Gnulib later. However,
for simplicity these patches do not use all the Gnulib machinery
for .

These patches can be applied to Bash's devel branch (commit
54f3ed2278025081f897b9bd958fcf099fd5be18 dated Mon Mar 4
14:59:33 2024 -0500) by using the command "git am".From 1f961bac5445929dc86ca8814b94548b16034337 Mon Sep 17 00:00:00 2001
From: Paul Eggert 
Date: Fri, 8 Mar 2024 21:58:46 -0800
Subject: [PATCH 1/4] maint: add support for C23-style stdckdint.h
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

This is so that Bash can do proper checking for internal
integer overflow.  This change doesn't change Bash proper;
it only adds the minimum changes needed so that
C23-style "#include " will work portably
to older systems.
* Makefile.in (CREATED_CONFIGURE): Add stdckdint.h.
* configure.ac: Check for stdckdint.h.  If it works, remove
any stdckdint.h left over from a previous ‘configure’;
otherwise, create one.
* .gitignore: Add stdckdint.h.
* include/stdckdint.in.h, include/intprops-internal.h:
New files, copied verbatim from Gnulib.
---
 .gitignore  |   1 +
 Makefile.in |   1 +
 configure.ac|   7 +
 include/intprops-internal.h | 397 
 include/stdckdint.in.h  |  35 
 5 files changed, 441 insertions(+)
 create mode 100644 include/intprops-internal.h
 create mode 100644 include/stdckdint.in.h

diff --git a/.gitignore b/.gitignore
index 2c10177c..15b219d3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -70,6 +70,7 @@ support/bashbug.sh
 lsignames.h
 pathnames.h
 signames.h
+stdckdint.h
 version.h
 syntax.c
 stamp-h
diff --git a/Makefile.in b/Makefile.in
index 41443c6d..2b4b713c 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -584,6 +584,7 @@ CREATED_SUPPORT = signames.h recho$(EXEEXT) zecho$(EXEEXT) printenv$(EXEEXT) \
 		  mksyntax${EXEEXT} syntax.c $(VERSPROG) $(VERSOBJ) \
 		  buildversion.o mksignames.o signames.o buildsignames.o
 CREATED_CONFIGURE = config.h config.cache config.status config.log \
+		stdckdint.h \
 		stamp-h po/POTFILES config.status.lineno
 CREATED_MAKEFILES = Makefile builtins/Makefile doc/Makefile \
 		lib/readline/Makefile lib/glob/Makefile \
diff --git a/configure.ac b/configure.ac
index d4ca74e5..7befb6c2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -787,6 +787,7 @@ BASH_HEADER_INTTYPES
 
 AC_CHECK_HEADERS(unistd.h stdlib.h varargs.h limits.h string.h \
 		 memory.h locale.h termcap.h termio.h termios.h dlfcn.h \
+		 stdckdint.h \
 		 stdbool.h stddef.h stdint.h netdb.h pwd.h grp.h strings.h \
 		 regex.h syslog.h ulimit.h)
 AC_CHECK_HEADERS(sys/pte.h sys/stream.h sys/select.h sys/file.h sys/ioctl.h \
@@ -1352,4 +1353,10 @@ AC_CONFIG_FILES([Makefile builtins/Makefile lib/readline/Makefile \
 dnl Makefile uses this timestamp file to record whether config.h is up to date.
 AC_CONFIG_COMMANDS([stamp-h], [echo timestamp > stamp-h])
 
+if test "$ac_cv_header_stdckdint_h" = yes; then
+  rm -f stdckdint.h
+else
+  echo '#include ' >stdckdint.h
+fi
+
 AC_OUTPUT
diff --git a/include/intprops-internal.h b/inclu

Re: test -lt inconsistent about white space

2023-10-30 Thread Paul Eggert

On 2023-10-30 08:09, Chet Ramey wrote:

The fact that this whitespace issue hasn't been reported since then shows
how obscure it is.


Yes, I noticed it only because coreutils 'test' was incompatible with 
Bash. (It was also incompatible with everybody else!)


I recently changed bleeding-edge coreutils 'test' to be compatible with 
the proposed change to Bash (and to ksh and to Dash), here:


https://git.savannah.gnu.org/cgit/coreutils.git/commit/?id=2709bea0f440507ac009e6e7ded453bb792d6842



Re: test -lt inconsistent about white space

2023-10-29 Thread Paul Eggert

On 2023-10-29 03:18, Oğuz wrote:
I think the intented behavior was skipping both leading and trailing 
horizontal whitespace, which makes sense as a QOL feature, and switching 
over to strtoimax changed this.


If that's the intent, which is self-consistent but which disagrees with 
all other shells we know about, then a patch differing from what I 
submitted should be applied. The patch I sent makes Bash self-consistent 
in a different way, one that is compatible with ksh and Dash. Although I 
would vote for the latter on compatibility grounds, the former is at 
least self-consistent.




https://git.savannah.gnu.org/cgit/bash.git/tree/test.c?id=726f63884db0132f01745f1fb4465e6621088ccf#n354


That old code is obviously wrong as it has undefined behavior on integer 
overflow. So we shouldn't simply revert to it, of course.




Re: test -lt inconsistent about white space

2023-10-28 Thread Paul Eggert

On 2023-10-28 18:41, Oğuz wrote:

Why? The same commands fail on bosh, yash, and zsh too.


I don't know what bosh is. zsh and yash prohibit trailing spaces in 
integers, but allow leading spaces:


  % test ' 3' -lt ' 4'
  % test ' 3 ' -lt ' 4 '
  test: integer expression expected:  3

Presumably this is because they use strtol or equivalent, and accept 
exactly the strings that strtol accepts. Although that's an allowed 
behavior, it's not the behavior that Bash and ksh and Dash use; they 
both allow the second example listed above.


My understanding is that Bash was intended to allow both leading and 
trailing whitespace. This is compatible with ksh and with Dash. If 
that's the intent, Bash should be consistent about it, just as ksh and 
Dash are. There seems little point to allowing one nonempty set of 
whitespace characters before the integer, and a different nonempty set 
of whitespace characters afterwards.


For what it's worth, 7th Edition Unix sh allows any characters after the 
integer. (There doesn't even have to be an integer!)


PS. As I understand it, POSIX allows all the behaviors described above, 
so this is not a POSIX conformance issue.




test -lt inconsistent about white space

2023-10-28 Thread Paul Eggert

Consider the following shell script 'doit':

sp=' '
nl='
'
test "${sp}1${sp}" -lt "${sp}2${sp}"
test "${nl}3${sp}" -lt "${nl}4${sp}"
test "${sp}5${nl}" -lt "${sp}6${nl}"
test "${nl}7${nl}" -lt "${nl}8${nl}"

Running the command "bash doit" outputs:

doit: line 6: test:  5
: integer expression expected
doit: line 7: test:
7
: integer expression expected

The problem occurs because strtoimax accepts all forms of leading 
whitespace, whereas Bash accepts only space and tab after the integer. 
This is inconsistent: Bash should treat trailing whitespace the same way 
it treats leading whitespace, and should accept all of doit's 'test' 
commands, as Dash does.


Proposed patch attached.From bb2403a3ae6a39631777a7deea3d7f8128fff764 Mon Sep 17 00:00:00 2001
From: Paul Eggert 
Date: Sat, 28 Oct 2023 12:05:14 -0700
Subject: [PATCH] fix inconsistency when parsing integers

* general.c (legal_number): Treat trailing whitespace
like leading whitespace.
---
 general.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/general.c b/general.c
index da59f9c0..3e63f9f7 100644
--- a/general.c
+++ b/general.c
@@ -256,7 +256,7 @@ legal_number (const char *string, intmax_t *result)
 return 0;	/* errno is set on overflow or underflow */
 
   /* Skip any trailing whitespace, since strtoimax does not. */
-  while (whitespace (*ep))
+  while (isspace ((unsigned char) *ep))
 ep++;
 
   /* If *string is not '\0' but *ep is '\0' on return, the entire string
-- 
2.41.0



Re: bug#65659: RFC: changing printf(1) behavior on %b

2023-08-31 Thread Paul Eggert

On 2023-08-31 08:35, Eric Blake wrote:

Typing-wise, %#s as a synonym for %b is
probably going to be easier (less shell escaping needed).  Is there
any interest in a patch to coreutils or bash that would add such a
synonym, to make it easier to leave that functionality in place for
POSIX Issue 9 even when %b is repurposed to align with C2x?


Sounds good to me for coreutils.



Re: [PATCH 3/4] Port unwind protection to C23

2023-03-27 Thread Paul Eggert

On 2023-03-26 21:17, Martin D Kealey wrote:

While C has never guaranteed that pointers all have the same size &
alignment, POSIX does provide this guarantee, although indirectly (it has
to be true for dlsym() to work, for example).


My commit message was a bit misleading, as the problem is not limited to 
platforms where pointers can differ in size or representation. The 
problem can also occur on platforms where calling conventions differ 
depending on type even if the two types have the same representation, 
and this can (and has) occurred on platforms with linear address spaces.


The patch fixes an actual (albeit unlikely) bug on GNU/Linux x86-64, due 
to a variant of that sort of thing.



I'm all for tidying up the code so that it can compile
cleanly and run reliably.


Yes, it's a win overall.

The patch is not enough to make Bash entirely C23-safe, alas; more work 
needs to be done in this area. Unfortunately it's a bit of a pain due to 
the K&R cruft still present (which can fight with C23).




Re: Bash not portable to C23

2023-03-26 Thread Paul Eggert

On 2023-03-24 12:04, Chet Ramey wrote:
However, Bash's devel branch still has old-style function definitions 
and therefore won't compile with a strict C23 compiler. For example, 
get_variable_value in variables.c is old-style. I assume there would 
be interest in fixing remaining areas where Bash won't port to C23?


Please report those as you find them.


I reported many of the ones I found to bug-bash just now. Many more such 
issues remain, unfortunately.


In looking into this I had some trouble reading the code - perhaps you 
could let me know if there's a roadmap for newbies? Or if there isn't 
one perhaps we could write one. That might help attract other people to 
make further improvements.


Here's a brief summary of my guesses at the situation; please correct me 
if I'm wrong. Perhaps this could serve as a basis for a roadmap.


* Ignore everything under the CWRU directory, because it does not 
contribute anything to any builds. Similarly for lib/posixheaders.old 
and support/config.*.*. (What other code should I ignore, and what's the 
motivation for keeping the unused code in the repository?)


* Ignore files like 'configure' and 'doc/bash.pdf' that are 
automatically generated. (Is there a list of which files these are? It's 
not clear to me.)


* Ignore lib/glob, lib/intl, lib/malloc, and lib/termcap as these are 
all taken from other projects and fixes should be sent there. (The other 
lib/* directories belong to Bash, though.)


* Ignore most of the files in m4/* as they're taken from Gnulib. (Which 
files?)


* Ignore the po/* files as they're all automatically generated and/or 
synced from the Translation Project somehow.


* Ignore support/config.guess and support/config.sub as it's taken from 
the GNU config upstream. Likewise for support/config.rpath, taken from 
GNU Libtool.



PS. What are the procedures for syncing from upstream? Is it all done by 
hand? In other projects we automate this as much as possible - would a 
patch to do that be welcome?




[PATCH 1/4] Port more functions etc. to C23

2023-03-26 Thread Paul Eggert
Port more function definitions and declarations to C23.
This includes adding a return type when it defaulted to int.
Add some casts to and from GENERIC_LIST * that are needed
now that the list functions are prototyped.

This does not finish the job, as some trickier functions
still won't work with C23.  However, one step at a time.
---
 aclocal.m4| 20 
 array.c   |  3 ++
 array2.c  |  5 ++-
 braces.c  |  4 +--
 builtins/common.c |  2 +-
 builtins/getopts.def  | 16 +++--
 builtins/mkbuiltins.c |  2 +-
 builtins/psize-posix.c|  1 +
 examples/loadables/bsdos.glue.c   | 31 ++
 examples/loadables/finfo.c| 54 ++-
 examples/loadables/getconf.c  |  3 +-
 examples/loadables/id.c   |  4 +--
 examples/loadables/pathchk.c  |  3 +-
 examples/loadables/pushd.def  | 42 +---
 examples/loadables/tee.c  |  2 +-
 examples/loadables/tty.c  |  2 +-
 execute_cmd.c |  2 +-
 expr.c| 12 +--
 externs.h | 10 +++---
 include/memalloc.h| 14 +++-
 input.c   |  1 +
 lib/glob/glob.c   |  5 ++-
 lib/glob/gm_loop.c| 11 ++-
 lib/glob/ndir.h   |  9 +++---
 lib/glob/strmatch.c   |  5 ++-
 lib/malloc/memtest.c  |  1 +
 lib/readline/bind.c   |  4 +--
 lib/readline/doc/hstech.texi  |  5 ++-
 lib/readline/doc/rltech.texi  | 18 ---
 lib/readline/examples/fileman.c   | 14 +++-
 lib/readline/examples/histexamp.c |  4 +--
 lib/readline/examples/rl.c|  4 +--
 lib/readline/examples/rlcat.c | 10 ++
 lib/readline/rltty.c  |  3 +-
 lib/readline/text.c   |  3 +-
 lib/sh/getcwd.c   |  5 ++-
 lib/sh/snprintf.c |  1 +
 lib/sh/strftime.c |  4 +--
 lib/sh/stringlist.c   |  2 +-
 lib/sh/stringvec.c|  2 +-
 lib/termcap/termcap.c |  5 ++-
 lib/termcap/tparam.c  |  5 ++-
 lib/tilde/shell.c |  2 +-
 lib/tilde/tilde.c |  3 +-
 pcomplete.c   |  2 +-
 shell.c   |  2 +-
 subst.c   |  7 ++--
 support/bashversion.c |  4 +--
 support/endian.c  |  5 ++-
 support/memtest.c |  1 +
 support/mksignames.c  |  7 ++--
 support/printenv.c|  4 +--
 support/recho.c   |  9 ++
 support/rlvers.sh |  1 +
 support/version2.c|  3 +-
 support/xcase.c   |  4 +--
 support/zecho.c   |  4 +--
 tests/misc/regress/getdate.y  |  7 ++--
 variables.c   |  3 +-
 version.c |  3 +-
 60 files changed, 164 insertions(+), 260 deletions(-)

diff --git a/aclocal.m4 b/aclocal.m4
index 37546c6c..e6e18737 100644
--- a/aclocal.m4
+++ b/aclocal.m4
@@ -432,6 +432,7 @@ AC_CACHE_VAL(bash_cv_sizeof_rlim_cur,
 #endif
 #include 
 #include 
+int
 main()
 {
 struct rlimit r;
@@ -457,6 +458,7 @@ AC_CACHE_VAL(bash_cv_sizeof_quad_t,
 #include 
 #endif
 
+int
 main()
 {
 #if HAVE_QUAD_T
@@ -841,9 +843,7 @@ AC_CACHE_VAL(bash_cv_func_strcoll_broken,
 #include 
 
 int
-main(c, v)
-int c;
-char*v[];
+main (int c, char **v)
 {
 int r1, r2;
 char*deflocale, *defcoll;
@@ -1345,15 +1345,13 @@ AC_CACHE_VAL(bash_cv_must_reinstall_sighandlers,
 #endif
 #include 
 
-typedef void sigfunc();
+typedef void sigfunc (int);
 
 volatile int nsigint;
 
 #ifdef HAVE_POSIX_SIGNALS
 sigfunc *
-set_signal_handler(sig, handler)
- int sig;
- sigfunc *handler;
+set_signal_handler (int sig, sigfunc *handler)
 {
   struct sigaction act, oact;
   act.sa_handler = handler;
@@ -1836,9 +1834,7 @@ bash_cv_wcwidth_broken,
 #include 
 
 int
-main(c, v)
-int c;
-char**v;
+main (int c, char **v)
 {
 int w;
 
@@ -2156,9 +2152,7 @@ AC_CACHE_VAL(bash_cv_wexitstatus_offset,
 #include 
 
 int
-main(c, v)
- int c;
- char **v;
+main (int c, char **v)
 {
   pid_t pid, p;
   int s, i, n;
diff --git a/array.c b/array.c
index 61894e0b..6f8926eb 100644
--- a/array.c
+++ b/array.c
@@ -1119,6 +1119,7 @@ quote_string(char *s)
return savestring(s);
 }
 
+int
 print_element(ARRAY_ELEMENT *ae)
 {
charlbuf[INT_STRLEN_BOUND (intmax_t) + 1];
@@ -1128,12 +1129,14 @@ print_element(ARRAY_ELEMENT *ae)
element_value(ae));
 }
 
+int
 print_array(ARRAY *a)
 {
printf("\n");
array_walk(a, print_element, (void *)NULL);
 }
 
+int
 main(int c, char **v)
 {
ARRAY   *a, *new_a, *copy_of_a;
diff --git a/array2.c b/array2.c
index 2988f3b1..3b6a62

[PATCH 2/4] Remove no-longer-used K&R cruft

2023-03-26 Thread Paul Eggert
Since we now assume C89 function prototypes anyway,
remove no-longer-used cruft that is used only for
ports to compilers requiring K&R style.
---
 aclocal.m4 | 35 +
 builtins/common.c  | 23 ++
 builtins/mkbuiltins.c  |  4 ---
 builtins/printf.def| 10 ++
 config-bot.h   | 11 ---
 configure.ac   |  3 +-
 error.c| 29 --
 examples/loadables/finfo.c | 30 --
 general.h  |  4 ---
 include/memalloc.h |  4 ---
 include/stdc.h | 18 ---
 jobs.h |  2 +-
 lib/doc-support/getopt.h   | 20 
 lib/readline/bind.c| 21 -
 lib/readline/complete.c|  4 ---
 lib/readline/display.c | 57 --
 lib/readline/examples/rl.c |  5 ---
 lib/readline/funmap.c  |  4 ---
 lib/readline/histlib.h |  3 --
 lib/readline/parens.c  |  4 ---
 lib/readline/readline.h|  4 ---
 lib/readline/rldefs.h  | 12 +---
 lib/readline/rlprivate.h   |  6 
 lib/readline/rlstdc.h  | 20 
 lib/readline/util.c| 63 --
 lib/sh/dprintf.c   |  9 ++
 lib/sh/fdprintf.c  | 16 ++
 lib/sh/snprintf.c  | 11 ++-
 lib/sh/strindex.c  |  4 +--
 lib/sh/xstrchr.c   |  6 
 lib/termcap/termcap.h  | 24 ---
 m4/iconv.m4|  4 ---
 pcomplete.c|  9 ++
 print_cmd.c| 25 ++-
 34 files changed, 41 insertions(+), 463 deletions(-)

diff --git a/aclocal.m4 b/aclocal.m4
index e6e18737..b8f67e75 100644
--- a/aclocal.m4
+++ b/aclocal.m4
@@ -69,11 +69,7 @@ AC_DEFUN(BASH_DECL_PRINTF,
 AC_CACHE_VAL(bash_cv_printf_declared,
 [AC_RUN_IFELSE([AC_LANG_SOURCE([[
 #include 
-#ifdef __STDC__
 typedef int (*_bashfunc)(const char *, ...);
-#else
-typedef int (*_bashfunc)();
-#endif
 #include 
 int
 main()
@@ -566,12 +562,7 @@ AC_CACHE_VAL(bash_cv_getenv_redef,
 #  endif
 #endif
 char *
-getenv (name)
-#if defined (__linux__) || defined (__bsdi__) || defined (convex)
- const char *name;
-#else
- char const *name;
-#endif /* !__linux__ && !__bsdi__ && !convex */
+getenv (const char *name)
 {
 return "42";
 }
@@ -601,7 +592,6 @@ fi
 # We should check for putenv before calling this
 AC_DEFUN(BASH_FUNC_STD_PUTENV,
 [
-AC_REQUIRE([AC_C_PROTOTYPES])
 AC_CACHE_CHECK([for standard-conformant putenv declaration], 
bash_cv_std_putenv,
 [AC_LINK_IFELSE([AC_LANG_PROGRAM([[
 #if HAVE_STDLIB_H
@@ -615,11 +605,7 @@ AC_CACHE_CHECK([for standard-conformant putenv 
declaration], bash_cv_std_putenv,
 #define const
 #  endif
 #endif
-#ifdef PROTOTYPES
 extern int putenv (char *);
-#else
-extern int putenv ();
-#endif
 ]], [[return (putenv == 0);]] )],
 [bash_cv_std_putenv=yes], [bash_cv_std_putenv=no]
 )])
@@ -631,7 +617,6 @@ fi
 # We should check for unsetenv before calling this
 AC_DEFUN(BASH_FUNC_STD_UNSETENV,
 [
-AC_REQUIRE([AC_C_PROTOTYPES])
 AC_CACHE_CHECK([for standard-conformant unsetenv declaration], 
bash_cv_std_unsetenv,
 [AC_LINK_IFELSE([AC_LANG_PROGRAM([[
 #if HAVE_STDLIB_H
@@ -645,11 +630,7 @@ AC_CACHE_CHECK([for standard-conformant unsetenv 
declaration], bash_cv_std_unset
 #define const
 #  endif
 #endif
-#ifdef PROTOTYPES
 extern int unsetenv (const char *);
-#else
-extern int unsetenv ();
-#endif
 ]], [[return (unsetenv == 0);]] )],
 [bash_cv_std_unsetenv=yes], [bash_cv_std_unsetenv=no]
 )])
@@ -2091,31 +2072,17 @@ AC_DEFUN([BASH_FUNC_VSNPRINTF],
   if test X$ac_cv_func_vsnprintf = Xyes; then
 AC_CACHE_CHECK([for standard-conformant vsnprintf], 
[bash_cv_func_vsnprintf],
   [AC_RUN_IFELSE([AC_LANG_SOURCE([[
-#if HAVE_STDARG_H
 #include 
-#else
-#include 
-#endif
 #include 
 #include 
 
 static int
-#if HAVE_STDARG_H
 foo(const char *fmt, ...)
-#else
-foo(format, va_alist)
- const char *format;
- va_dcl
-#endif
 {
   va_list args;
   int n;
 
-#if HAVE_STDARG_H
   va_start(args, fmt);
-#else
-  va_start(args);
-#endif
   n = vsnprintf(0, 0, fmt, args);
   va_end (args);
   return n;
diff --git a/builtins/common.c b/builtins/common.c
index 2679fae3..79e61887 100644
--- a/builtins/common.c
+++ b/builtins/common.c
@@ -34,12 +34,7 @@
 #include 
 
 #include 
-
-#if defined (PREFER_STDARG)
-#  include 
-#else
-#  include 
-#endif
+#include 
 
 #include "../bashansi.h"
 #include "../bashintl.h"
@@ -100,19 +95,13 @@ builtin_error_prolog (void)
 }
 
 void
-#if defined (PREFER_STDARG)
 builtin_error (const char *format, ...)
-#else
-builtin_error (format, va_alist)
- const char *format;
- va_dcl
-#endif
 {
   va_list args;
 
   builtin_error_prolog ();
 
-  SH_VA_START (args, format);
+  va_start (args, format);
 
   vfprintf (stderr, format, args);
   va_end (args);
@@ -120,20 +109,14 @@ builtin_error (format, va_alist)
 }
 
 void
-#if defined (PREFER_STDARG)
 builtin_warning (const 

[PATCH 4/4] Assume __STDC__ if it merely assumes C89 or later

2023-03-26 Thread Paul Eggert
There's no longer any point to worrying about K&R compilers
as the code won't work with them anyway.  Simplify the code
by omitting __STDC__ tests when that merely is checking for
C89 or later, as we assume C89 prototypes now.
---
 aclocal.m4| 15 ---
 builtins/enable.def   |  4 
 builtins/gen-helpfiles.c  |  4 
 builtins/help.def |  9 +
 builtins/printf.def   |  5 -
 general.h |  9 -
 hashlib.h | 14 +-
 include/ansi_stdlib.h |  8 +---
 include/ocache.h  |  8 +---
 include/stdc.h| 12 
 lib/doc-support/getopt.c  |  4 
 lib/doc-support/getopt.h  |  4 
 lib/doc-support/getopt1.c |  4 
 lib/glob/collsyms.h   |  4 
 lib/glob/glob.c   |  8 
 lib/intl/explodename.c|  9 -
 lib/readline/history.h|  4 
 lib/readline/xmalloc.h|  8 +---
 lib/sh/strtrans.c | 11 ---
 lib/sh/vprint.c   |  8 
 lib/tilde/tilde.c |  8 
 mksyntax.c|  5 -
 support/endian.c  |  4 
 xmalloc.c |  6 +-
 xmalloc.h |  8 +---
 25 files changed, 7 insertions(+), 176 deletions(-)

diff --git a/aclocal.m4 b/aclocal.m4
index b8f67e75..5a0fa1fb 100644
--- a/aclocal.m4
+++ b/aclocal.m4
@@ -556,11 +556,6 @@ AC_CACHE_VAL(bash_cv_getenv_redef,
 #  include 
 #endif
 #include 
-#ifndef __STDC__
-#  ifndef const
-#define const
-#  endif
-#endif
 char *
 getenv (const char *name)
 {
@@ -600,11 +595,6 @@ AC_CACHE_CHECK([for standard-conformant putenv 
declaration], bash_cv_std_putenv,
 #if HAVE_STDDEF_H
 #include 
 #endif
-#ifndef __STDC__
-#  ifndef const
-#define const
-#  endif
-#endif
 extern int putenv (char *);
 ]], [[return (putenv == 0);]] )],
 [bash_cv_std_putenv=yes], [bash_cv_std_putenv=no]
@@ -625,11 +615,6 @@ AC_CACHE_CHECK([for standard-conformant unsetenv 
declaration], bash_cv_std_unset
 #if HAVE_STDDEF_H
 #include 
 #endif
-#ifndef __STDC__
-#  ifndef const
-#define const
-#  endif
-#endif
 extern int unsetenv (const char *);
 ]], [[return (unsetenv == 0);]] )],
 [bash_cv_std_unsetenv=yes], [bash_cv_std_unsetenv=no]
diff --git a/builtins/enable.def b/builtins/enable.def
index e6948bac..f44820b3 100644
--- a/builtins/enable.def
+++ b/builtins/enable.def
@@ -488,11 +488,7 @@ delete_builtin (struct builtin *b)
   struct builtin *new_shell_builtins;
 
   /* XXX - funky pointer arithmetic - XXX */
-#ifdef __STDC__
   ind = b - shell_builtins;
-#else
-  ind = ((int)b - (int)shell_builtins) / sizeof (struct builtin);
-#endif
   size = num_shell_builtins * sizeof (struct builtin);
   new_shell_builtins = (struct builtin *)xmalloc (size);
 
diff --git a/builtins/gen-helpfiles.c b/builtins/gen-helpfiles.c
index 76f7c06b..771e1e45 100644
--- a/builtins/gen-helpfiles.c
+++ b/builtins/gen-helpfiles.c
@@ -72,10 +72,6 @@
 extern int errno;
 #endif
 
-#if !defined (__STDC__) && !defined (strcpy)
-extern char *strcpy ();
-#endif /* !__STDC__ && !strcpy */
-
 #define whitespace(c) (((c) == ' ') || ((c) == '\t'))
 
 /* Flag values that builtins can have. */
diff --git a/builtins/help.def b/builtins/help.def
index 293f23de..3b248cdd 100644
--- a/builtins/help.def
+++ b/builtins/help.def
@@ -193,19 +193,12 @@ void
 builtin_help (void)
 {
   int ind;
-  ptrdiff_t d;
 
   current_builtin = builtin_address_internal (this_command_name, 0);
   if (current_builtin == 0)
 return;
 
-  d = current_builtin - shell_builtins;
-
-#if defined (__STDC__)
-  ind = (int)d;
-#else
-  ind = (int)d / sizeof (struct builtin);
-#endif
+  ind = current_builtin - shell_builtins;
 
   printf ("%s: %s\n", this_command_name, _(shell_builtins[ind].short_doc));
   show_longdoc (ind);  
diff --git a/builtins/printf.def b/builtins/printf.def
index 2a6e2658..cbf09039 100644
--- a/builtins/printf.def
+++ b/builtins/printf.def
@@ -1034,12 +1034,7 @@ tescape (char *estart, char *cp, int *lenp, int *sawc)
 
   switch (c = *p++)
 {
-#if defined (__STDC__)
   case 'a': *cp = '\a'; break;
-#else
-  case 'a': *cp = '\007'; break;
-#endif
-
   case 'b': *cp = '\b'; break;
 
   case 'e':
diff --git a/general.h b/general.h
index 2b81f683..f5b1e875 100644
--- a/general.h
+++ b/general.h
@@ -45,15 +45,6 @@
 
 #include "xmalloc.h"
 
-/* NULL pointer type. */
-#if !defined (NULL)
-#  if defined (__STDC__)
-#define NULL ((void *) 0)
-#  else
-#define NULL 0x0
-#  endif /* !__STDC__ */
-#endif /* !NULL */
-
 /* Hardly used anymore */
 #define pointer_to_int(x)  (int)((char *)x - (char *)0)
 
diff --git a/hashlib.h b/hashlib.h
index 623ad0aa..0b4126ab 100644
--- a/hashlib.h
+++ b/hashlib.h
@@ -24,11 +24,7 @@
 #include "stdc.h"
 
 #ifndef PTR_T
-#  ifdef __STDC__
-#define PTR_T void *
-#  else
-#define PTR_T char *
-#  endif
+# define PTR_T void *
 #endif
 
 typedef struct bucket_contents {
@@ -81,12 +77,4 @@ extern unsigned

[PATCH 3/4] Port unwind protection to C23

2023-03-26 Thread Paul Eggert
Do not assume that all pointers have the same representation at
the machine level and that address space is linear, as the C
standard does not guarantee this and it is not true on a few
unusual platforms.  Fixing this also uncovered a bug on
conventional 64-bit platforms, where the call 'add_unwind_protect
(pop_scope, should_keep ? "1" : 0)' eventually casts a nonnull
pointer to to an int that is tested against zero to see whether
the pointer was null; this does not work if pointers are 64 bits,
ints are 32 bits, and half the nonnull pointer happens to be all
bits zero.

Strictly speaking, the old code wasn't portable even to C89 on
hypothetical platforms.  However, C23 makes this more urgent since
it removes support for K&R-style function declarations.

Use the generic function type void (*) (void *) for all unwind
cleanups.  When an existing cleanup doesn't already have that
type, change the type if the function is used only as a cleanup,
and add a shim function otherwise.  If the shim is used in more
than one compilation unit, put the shim function next to the
cleanup as an extern function; otherwise, put the shim in the
compilation unit as a static function.

Although this does not finish the job of porting to C23,
one step at a time.

* builtins/mkbuiltins.c, general.h, readline/rltypedefs.h
(_FUNCTION_DEF, Function, VFunction, CPFunction, CPPFunction):
Remove; no longer used, as they are no longer needed.
Their meaning changes in C23 anyway.
* configure.ac (AC_TYPE_INTPTR_T): Use this.
* execute_cmd.c (execute_command_internal):
Remove a 'volatile' that didn't type check and appears to
be a typo anyway.  Perhaps 'void *volatile' was meant, but
in that case the 'volatile' appears to be unnecessary anyway.
* general.h (STREQ, STREQN): Now inline functions instead of
macros; needed for unwind_prot.c now that it passes void *
to STREQ.
* unwind_prot.c (UNWIND_ELT): Use a prototype for head.cleanup.
arg.v is now void *, not char *; this simplifies use.
(without_interrupts): Remove, as this vestigial function just
got in the way of type checking.
---
 builtins/command.def  |   2 +-
 builtins/evalfile.c   |   4 +-
 builtins/evalstring.c |  35 +---
 builtins/fc.def   |  10 +++-
 builtins/jobs.def |   2 +-
 builtins/mkbuiltins.c |   1 -
 builtins/read.def |  35 +---
 builtins/source.def   |   6 +-
 configure.ac  |   1 +
 dispose_cmd.c |  10 
 dispose_cmd.h |   2 +
 execute_cmd.c | 117 +++---
 execute_cmd.h |   3 +
 general.h |  22 ---
 lib/readline/rltypedefs.h |  21 ---
 pcomplete.c   |  26 ++---
 print_cmd.c   |   4 +-
 subst.c   |   2 +-
 trap.c|  10 ++--
 trap.h|   8 +--
 unwind_prot.c |  82 +++---
 unwind_prot.h |   2 +-
 variables.c   |  11 +++-
 variables.h   |   5 +-
 24 files changed, 254 insertions(+), 167 deletions(-)

diff --git a/builtins/command.def b/builtins/command.def
index e695fdd1..a376131e 100644
--- a/builtins/command.def
+++ b/builtins/command.def
@@ -131,7 +131,7 @@ command_builtin (WORD_LIST *list)
   command->flags |= COMMAND_BUILTIN_FLAGS;
   command->value.Simple->flags |= COMMAND_BUILTIN_FLAGS;
 
-  add_unwind_protect ((char *)dispose_command, command);
+  add_unwind_protect (unwind_dispose_command, command);
   result = execute_command (command);
 
   run_unwind_frame ("command_builtin");
diff --git a/builtins/evalfile.c b/builtins/evalfile.c
index 9b6f4215..46788398 100644
--- a/builtins/evalfile.c
+++ b/builtins/evalfile.c
@@ -247,7 +247,7 @@ file_error_and_exit:
   fa->funcname_a = funcname_a;
   fa->funcname_v = funcname_v;
   if (flags & FEVAL_UNWINDPROT)
-add_unwind_protect (restore_funcarray_state, fa);
+add_unwind_protect (unwind_restore_funcarray_state, fa);
 
 #  if defined (DEBUGGER)
   /* Have to figure out a better way to do this when `source' is supplied
@@ -260,7 +260,7 @@ file_error_and_exit:
   tt[0] = '1'; tt[1] = '\0';
   array_push (bash_argc_a, tt);
   if (flags & FEVAL_UNWINDPROT)
-   add_unwind_protect (pop_args, 0);
+   add_unwind_protect (unwind_pop_args, 0);
 }
 #  endif
 #endif
diff --git a/builtins/evalstring.c b/builtins/evalstring.c
index 243becbc..b52a1a26 100644
--- a/builtins/evalstring.c
+++ b/builtins/evalstring.c
@@ -70,14 +70,14 @@ static int cat_file (REDIRECT *);
 
 #if defined (HISTORY)
 static void
-set_history_remembering (void)
+set_history_remembering (void *ignored)
 {
   remember_on_history = enable_history_list;
 }
 #endif
 
 static void
-restore_lastcom (char *x)
+restore_lastcom (void *x)
 {
   FREE (the_printed_command_except_trap);
   the_printed_command_except_trap = x;
@@ -204,6 +204,26 @@ parse_and_execute_cleanup (int old_running_trap)
 parse_and_execute_level = 0;

[PATCH] Pacify gcc -Wpointer-to-int-cast

2023-03-26 Thread Paul Eggert
* lib/sh/random.c (genseed): Use a different type, to pacify GCC
"warning: cast from pointer to integer of different size
[-Wpointer-to-int-cast]" on platforms with 64-bit pointers
and 32-bit int.
---
 lib/sh/random.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/sh/random.c b/lib/sh/random.c
index 1faeacae..16877430 100644
--- a/lib/sh/random.c
+++ b/lib/sh/random.c
@@ -91,7 +91,7 @@ genseed (void)
   u_bits32_t iv;
 
   gettimeofday (&tv, NULL);
-  iv = (u_bits32_t)seedrand;   /* let the compiler truncate */
+  iv = (uintptr_t)seedrand;/* let the compiler truncate */
   iv = tv.tv_sec ^ tv.tv_usec ^ getpid () ^ getppid () ^ current_user.uid ^ iv;
   return (iv);
 }
-- 
2.39.2




[PATCH] Port lib/sh/tmpfile.c to hosts without mkdtemp

2023-03-24 Thread Paul Eggert
* lib/sh/tmpfile.c (sh_mktmpdir) [!USE_MKDTEMP]:
Fix use of undeclared var 'fd'.
---
 lib/sh/tmpfile.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/lib/sh/tmpfile.c b/lib/sh/tmpfile.c
index 18582b10..610bd3dc 100644
--- a/lib/sh/tmpfile.c
+++ b/lib/sh/tmpfile.c
@@ -311,13 +311,12 @@ sh_mktmpdir (const char *nameroot, int flags)
   do
 {
   filename = sh_mktmpname (nameroot, flags);
-  fd = mkdir (filename, 0700);
-  if (fd == 0)
+  if (mkdir (filename, 0700) == 0)
break;
   free (filename);
   filename = (char *)NULL;
 }
-  while (fd < 0 && errno == EEXIST);
+  while (errno == EEXIST);
 
   return (filename);
 #endif /* !USE_MKDTEMP */
-- 
2.39.2




[PATCH v2 2/2] Work around GNU/Linux timestamp glitch

2023-03-24 Thread Paul Eggert
Without this patch, Bash can hand out user-visible timestamps
that are out of order, because on GNU/Linux the 'time'
function uses a different clock than file timestamps
and the 'gettimeofday' function.
The out-of-order timestamps can lead to user-confusion.
https://sourceware.org/bugzilla/show_bug.cgi?id=30200

This fixes a bug reported against Bash in 2020 by felix
https://lists.gnu.org/archive/html/bug-bash/2020-04/msg00072.html

* include/posixtime.h (getnow): New function.
All calls to 'time' changed to use this function.
* support/man2html.c (print_sig): Prefer gettimeofday if available.
---
 general.h  |  2 +-
 include/posixtime.h| 10 ++
 lib/readline/history.c |  4 +++-
 parse.y|  6 +++---
 support/man2html.c |  8 +++-
 5 files changed, 24 insertions(+), 6 deletions(-)

diff --git a/general.h b/general.h
index fa57251a..2232fabd 100644
--- a/general.h
+++ b/general.h
@@ -242,7 +242,7 @@ typedef int sh_builtin_func_t (WORD_LIST *); /* 
sh_wlist_func_t */
 
 #endif /* SH_FUNCTION_TYPEDEF */
 
-#define NOW((time_t) time ((time_t *) 0))
+#define NOWgetnow ()
 #define GETTIME(tv)gettimeofday(&(tv), NULL)
 
 /* Some defines for calling file status functions. */
diff --git a/include/posixtime.h b/include/posixtime.h
index 319cb168..7b0fc035 100644
--- a/include/posixtime.h
+++ b/include/posixtime.h
@@ -52,6 +52,16 @@ struct timeval
 extern int gettimeofday (struct timeval * restrict, void * restrict);
 #endif
 
+static inline time_t
+getnow (void)
+{
+  /* Avoid time (NULL), which can disagree with gettimeofday and with
+ filesystem timestamps.  */
+  struct timeval now;
+  gettimeofday (&now, 0);
+  return now.tv_sec;
+}
+
 /* These exist on BSD systems, at least. */
 #if !defined (timerclear)
 #  define timerclear(tvp)  do { (tvp)->tv_sec = 0; (tvp)->tv_usec = 0; } 
while (0)
diff --git a/lib/readline/history.c b/lib/readline/history.c
index 42580301..9dc90147 100644
--- a/lib/readline/history.c
+++ b/lib/readline/history.c
@@ -48,6 +48,7 @@
 #include "history.h"
 #include "histlib.h"
 
+#include "posixtime.h"
 #include "xmalloc.h"
 
 #if !defined (errno)
@@ -261,7 +262,8 @@ hist_inittime (void)
   time_t t;
   char ts[64], *ret;
 
-  t = (time_t) time ((time_t *)0);
+  t = getnow ();
+
 #if defined (HAVE_VSNPRINTF)   /* assume snprintf if vsnprintf exists 
*/
   snprintf (ts, sizeof (ts) - 1, "X%lu", (unsigned long) t);
 #else
diff --git a/parse.y b/parse.y
index b758756a..2a61eb8c 100644
--- a/parse.y
+++ b/parse.y
@@ -85,7 +85,7 @@ typedef void *alias_t;
 #  ifndef _MINIX
 #include 
 #  endif
-#  include 
+#  include "posixtime.h"
 #  if defined (TM_IN_SYS_TIME)
 #include 
 #include 
@@ -5976,7 +5976,7 @@ decode_prompt_string (char *string)
case '@':
case 'A':
  /* Make the current time/date into a string. */
- (void) time (&the_time);
+ the_time = getnow ();
 #if defined (HAVE_TZSET)
  sv_tz ("TZ"); /* XXX -- just make sure */
 #endif
@@ -6010,7 +6010,7 @@ decode_prompt_string (char *string)
  if (string[1] != '{') /* } */
goto not_escape;
 
- (void) time (&the_time);
+ the_time = getnow ();
  tm = localtime (&the_time);
  string += 2;  /* skip { */
  t = string;
diff --git a/support/man2html.c b/support/man2html.c
index 58165796..61f05f10 100644
--- a/support/man2html.c
+++ b/support/man2html.c
@@ -452,8 +452,14 @@ print_sig(void)
struct tm *timetm;
time_t  clock;
 
-   datbuf[0] = '\0';
+#if HAVE_GETTIMEOFDAY
+   struct timeval tv;
+   gettimeofday (&tv, NULL);
+   clock = tv.tv_sec;
+#else
clock = time(NULL);
+#endif
+   datbuf[0] = '\0';
timetm = localtime(&clock);
if (timetm)
  strftime(datbuf, MED_STR_MAX, TIMEFORMAT, timetm);
-- 
2.39.2




[PATCH v2 1/2] Don't dump core if localtime returns NULL

2023-03-24 Thread Paul Eggert
* examples/loadables/stat.c (stattime):
* examples/loadables/strftime.c (strftime_builtin):
* lib/readline/examples/histexamp.c (main):
* parse.y (decode_prompt_string):
* support/man2html.c (print_sig):
Do something reasonable if localtime returns NULL.
This can happen, for example, if someone sets the system
clock to such an absurdly high value so that tm_year cannot
represent the year, and localtime returns NULL with
errno == EOVERFLOW.
---
 examples/loadables/stat.c |  2 ++
 examples/loadables/strftime.c |  7 +++
 lib/readline/examples/histexamp.c |  6 --
 parse.y   | 35 +--
 support/man2html.c|  5 -
 5 files changed, 41 insertions(+), 14 deletions(-)

diff --git a/examples/loadables/stat.c b/examples/loadables/stat.c
index 3ca1a589..3ca2417a 100644
--- a/examples/loadables/stat.c
+++ b/examples/loadables/stat.c
@@ -261,6 +261,8 @@ stattime (time_t t, const char *timefmt)
 
   fmt = timefmt ? timefmt : DEFTIMEFMT;
   tm = localtime (&t);
+  if (!tm)
+return itos (t);
 
   ret = xmalloc (TIMELEN_MAX);
 
diff --git a/examples/loadables/strftime.c b/examples/loadables/strftime.c
index e6c8141e..43fb3839 100644
--- a/examples/loadables/strftime.c
+++ b/examples/loadables/strftime.c
@@ -80,6 +80,13 @@ strftime_builtin (WORD_LIST *list)
 secs = NOW;
 
   t = localtime (&secs);
+  if (!t)
+{
+  builtin_error ("%s: %s",
+list && list->word->word ? list->word->word : "now",
+_("timestamp out of range"));
+  return (EXECUTION_FAILURE);
+}
 
   tbsize = strlen (format) * 4;
   tbuf = 0;
diff --git a/lib/readline/examples/histexamp.c 
b/lib/readline/examples/histexamp.c
index 309d769b..b321dd0b 100644
--- a/lib/readline/examples/histexamp.c
+++ b/lib/readline/examples/histexamp.c
@@ -97,9 +97,11 @@ main (argc, argv)
  if (the_list)
for (i = 0; the_list[i]; i++)
  {
+   struct tm *tm;
tt = history_get_time (the_list[i]);
-   if (tt)
- strftime (timestr, sizeof (timestr), "%a %R", localtime(&tt));
+   tm = tt ? localtime (&tt) : 0;
+   if (tm)
+ strftime (timestr, sizeof (timestr), "%a %R", tm);
else
  strcpy (timestr, "??");
printf ("%d: %s: %s\n", i + history_base, timestr, 
the_list[i]->line);
diff --git a/parse.y b/parse.y
index 639912b6..b758756a 100644
--- a/parse.y
+++ b/parse.y
@@ -5982,7 +5982,12 @@ decode_prompt_string (char *string)
 #endif
  tm = localtime (&the_time);
 
- if (c == 'd')
+ if (!tm)
+   {
+ strcpy (timebuf, "??");
+ tslen = 2;
+   }
+ else if (c == 'd')
tslen = strftime (timebuf, sizeof (timebuf), "%a %b %d", tm);
  else if (c == 't')
tslen = strftime (timebuf, sizeof (timebuf), "%H:%M:%S", tm);
@@ -6008,19 +6013,27 @@ decode_prompt_string (char *string)
  (void) time (&the_time);
  tm = localtime (&the_time);
  string += 2;  /* skip { */
- timefmt = xmalloc (strlen (string) + 3);
- for (t = timefmt; *string && *string != '}'; )
-   *t++ = *string++;
- *t = '\0';
+ t = string;
+ while (*string && *string != '}')
+   string++;
  c = *string;  /* tested at add_string */
- if (timefmt[0] == '\0')
+
+ if (tm)
+   {
+ size_t timefmtlen = string - t;
+ timefmt = xmalloc (timefmtlen + 3);
+ memcpy (timefmt, t, timefmtlen);
+ timefmt[timefmtlen] = '\0';
+ if (timefmtlen == 0)
+   strcpy (timefmt, "%X"); /* locale-specific current time */
+ tslen = strftime (timebuf, sizeof (timebuf), timefmt, tm);
+ free (timefmt);
+   }
+ else
{
- timefmt[0] = '%';
- timefmt[1] = 'X'; /* locale-specific current time */
- timefmt[2] = '\0';
+ strcpy (timebuf, "??");
+ tslen = 2;
}
- tslen = strftime (timebuf, sizeof (timebuf), timefmt, tm);
- free (timefmt);
 
  if (tslen == 0)
timebuf[0] = '\0';
diff --git a/support/man2html.c b/support/man2html.c
index e6f441b4..58165796 100644
--- a/support/man2html.c
+++ b/support/man2html.c
@@ -455,7 +455,10 @@ print_sig(void)
datbuf[0] = '\0';
clock = time(NULL);
timetm = localtime(&clock);
-   strftime(datbuf, MED_STR_MAX, TIMEFORMAT, timetm);
+   if (timetm)
+ strftime(datbuf, MED_STR_MAX, TIMEFORMAT, timetm);
+   else
+ strcpy(datbuf, "??");
  

Re: Bash not portable to C23

2023-03-23 Thread Paul Eggert

On 3/23/23 18:23, Lawrence Velázquez wrote:

On Thu, Mar 23, 2023, at 9:16 PM, Paul Eggert wrote:

I see that Bash won't compile with a C23 compiler, since it still uses
old-style function definitions which C23 no longer supports. Is there
any effort and/or interest in fixing this portability problem in Bash?


I believe this was done a few months ago on the devel branch.

https://git.savannah.gnu.org/cgit/bash.git/commit/?h=devel&id=a61ffa78ede6df4d1127fddd2e8a1a77a7186ea1


Oh, thanks, I was looking at the wrong branch.

However, Bash's devel branch still has old-style function definitions 
and therefore won't compile with a strict C23 compiler. For example, 
get_variable_value in variables.c is old-style. I assume there would be 
interest in fixing remaining areas where Bash won't port to C23?





Re: [PATCH] Work around GNU/Linux timestamp glitch

2023-03-23 Thread Paul Eggert

On 3/23/23 17:51, Koichi Murase wrote:

By the way, you should prepare patches based on the devel branch of Bash.


Thanks for letting me know; I'll resend based on devel.



Bash not portable to C23

2023-03-23 Thread Paul Eggert
I see that Bash won't compile with a C23 compiler, since it still uses 
old-style function definitions which C23 no longer supports. Is there 
any effort and/or interest in fixing this portability problem in Bash?


It's OK these days to assume C89 or later, so it's OK for Bash to switch 
to new-style function definitions. Indeed, most GNU projects I'm 
familiar with assume many C99 constructs.




[PATCH] Work around GNU/Linux timestamp glitch

2023-03-23 Thread Paul Eggert
Without this patch, Bash can hand out user-visible timestamps
that are out of order, because on GNU/Linux the 'time'
function uses a different clock than file timestamps
and the 'gettimeofday' function.  See
.
* include/posixtime.h (getnow): New function.
All calls to 'time' changed to use this function.
* support/man2html.c (print_sig): Prefer gettimeofday if available.

(This patch assumes my recent patch proposed for localtime
.)
---
 general.h|  2 +-
 include/posixtime.h  | 10 ++
 lib/readline/history.c   |  4 +++-
 lib/readline/posixtime.h | 10 ++
 parse.y  |  6 +++---
 support/man2html.c   |  8 +++-
 6 files changed, 34 insertions(+), 6 deletions(-)

diff --git a/general.h b/general.h
index 8064c50e..9b082cbc 100644
--- a/general.h
+++ b/general.h
@@ -245,7 +245,7 @@ typedef int sh_builtin_func_t PARAMS((WORD_LIST *)); /* 
sh_wlist_func_t */
 
 #endif /* SH_FUNCTION_TYPEDEF */
 
-#define NOW((time_t) time ((time_t *) 0))
+#define NOWgetnow ()
 #define GETTIME(tv)gettimeofday(&(tv), NULL)
 
 /* Some defines for calling file status functions. */
diff --git a/include/posixtime.h b/include/posixtime.h
index e70ebec6..a7b2957a 100644
--- a/include/posixtime.h
+++ b/include/posixtime.h
@@ -52,6 +52,16 @@ struct timeval
 extern int gettimeofday PARAMS((struct timeval *, void *));
 #endif
 
+static inline time_t
+getnow (void)
+{
+  /* Avoid time (NULL), which can disagree with gettimeofday and with
+ filesystem timestamps.  */
+  struct timeval now;
+  gettimeofday (&now, 0);
+  return now.tv_sec;
+}
+
 /* These exist on BSD systems, at least. */
 #if !defined (timerclear)
 #  define timerclear(tvp)  do { (tvp)->tv_sec = 0; (tvp)->tv_usec = 0; } 
while (0)
diff --git a/lib/readline/history.c b/lib/readline/history.c
index 81d4c168..d141e942 100644
--- a/lib/readline/history.c
+++ b/lib/readline/history.c
@@ -48,6 +48,7 @@
 #include "history.h"
 #include "histlib.h"
 
+#include "posixtime.h"
 #include "xmalloc.h"
 
 #if !defined (errno)
@@ -261,7 +262,8 @@ hist_inittime (void)
   time_t t;
   char ts[64], *ret;
 
-  t = (time_t) time ((time_t *)0);
+  t = getnow ();
+
 #if defined (HAVE_VSNPRINTF)   /* assume snprintf if vsnprintf exists 
*/
   snprintf (ts, sizeof (ts) - 1, "X%lu", (unsigned long) t);
 #else
diff --git a/lib/readline/posixtime.h b/lib/readline/posixtime.h
index e70ebec6..a7b2957a 100644
--- a/lib/readline/posixtime.h
+++ b/lib/readline/posixtime.h
@@ -52,6 +52,16 @@ struct timeval
 extern int gettimeofday PARAMS((struct timeval *, void *));
 #endif
 
+static inline time_t
+getnow (void)
+{
+  /* Avoid time (NULL), which can disagree with gettimeofday and with
+ filesystem timestamps.  */
+  struct timeval now;
+  gettimeofday (&now, 0);
+  return now.tv_sec;
+}
+
 /* These exist on BSD systems, at least. */
 #if !defined (timerclear)
 #  define timerclear(tvp)  do { (tvp)->tv_sec = 0; (tvp)->tv_usec = 0; } 
while (0)
diff --git a/parse.y b/parse.y
index 1d188101..6f9c626f 100644
--- a/parse.y
+++ b/parse.y
@@ -84,7 +84,7 @@ typedef void *alias_t;
 #  ifndef _MINIX
 #include 
 #  endif
-#  include 
+#  include "posixtime.h"
 #  if defined (TM_IN_SYS_TIME)
 #include 
 #include 
@@ -5769,7 +5769,7 @@ decode_prompt_string (string)
case '@':
case 'A':
  /* Make the current time/date into a string. */
- (void) time (&the_time);
+ the_time = getnow ();
 #if defined (HAVE_TZSET)
  sv_tz ("TZ"); /* XXX -- just make sure */
 #endif
@@ -5803,7 +5803,7 @@ decode_prompt_string (string)
  if (string[1] != '{') /* } */
goto not_escape;
 
- (void) time (&the_time);
+ the_time = getnow ();
  tm = localtime (&the_time);
  string += 2;  /* skip { */
  t = string;
diff --git a/support/man2html.c b/support/man2html.c
index e6f441b4..6f552388 100644
--- a/support/man2html.c
+++ b/support/man2html.c
@@ -452,8 +452,14 @@ print_sig(void)
struct tm *timetm;
time_t  clock;
 
-   datbuf[0] = '\0';
+#ifdef HAVE_GETTIMEOFDAY
+   struct timeval tv;
+   gettimeofday (&tv, NULL);
+   clock = tv.tv_sec;
+#else
clock = time(NULL);
+#endif
+   datbuf[0] = '\0';
timetm = localtime(&clock);
strftime(datbuf, MED_STR_MAX, TIMEFORMAT, timetm);
printf(signature, manpage, datbuf);
-- 
2.39.2




[PATCH] Don't dump core if localtime returns NULL

2023-03-22 Thread Paul Eggert
* examples/loadables/stat.c (stattime):
* examples/loadables/strftime.c (strftime_builtin):
* lib/readline/examples/histexamp.c (main):
* parse.y (decode_prompt_string):
Do something reasonable if localtime returns NULL.
This can happen, for example, if someone sets the system
clock to such an absurdly high value so that tm_year cannot
represent the year, and localtime returns NULL with
errno == EOVERFLOW.
---
 examples/loadables/stat.c |  2 ++
 examples/loadables/strftime.c |  7 ++
 lib/readline/examples/histexamp.c |  6 +++--
 parse.y   | 40 ++-
 4 files changed, 42 insertions(+), 13 deletions(-)

diff --git a/examples/loadables/stat.c b/examples/loadables/stat.c
index 1e60e7b6..cc722c05 100644
--- a/examples/loadables/stat.c
+++ b/examples/loadables/stat.c
@@ -271,6 +271,8 @@ stattime (t, timefmt)
 
   fmt = timefmt ? timefmt : DEFTIMEFMT;
   tm = localtime (&t);
+  if (!tm)
+return itos (t);
 
   ret = xmalloc (TIMELEN_MAX);
 
diff --git a/examples/loadables/strftime.c b/examples/loadables/strftime.c
index f4e194e6..656ecdeb 100644
--- a/examples/loadables/strftime.c
+++ b/examples/loadables/strftime.c
@@ -81,6 +81,13 @@ strftime_builtin (list)
 secs = NOW;
 
   t = localtime (&secs);
+  if (!t)
+{
+  builtin_error ("%s: %s",
+list && list->word->word ? list->word->word : "now",
+_("timestamp out of range"));
+  return (EXECUTION_FAILURE);
+}
 
   tbsize = strlen (format) * 4;
   tbuf = 0;
diff --git a/lib/readline/examples/histexamp.c 
b/lib/readline/examples/histexamp.c
index 309d769b..b321dd0b 100644
--- a/lib/readline/examples/histexamp.c
+++ b/lib/readline/examples/histexamp.c
@@ -97,9 +97,11 @@ main (argc, argv)
  if (the_list)
for (i = 0; the_list[i]; i++)
  {
+   struct tm *tm;
tt = history_get_time (the_list[i]);
-   if (tt)
- strftime (timestr, sizeof (timestr), "%a %R", localtime(&tt));
+   tm = tt ? localtime (&tt) : 0;
+   if (tm)
+ strftime (timestr, sizeof (timestr), "%a %R", tm);
else
  strcpy (timestr, "??");
printf ("%d: %s: %s\n", i + history_base, timestr, 
the_list[i]->line);
diff --git a/parse.y b/parse.y
index 1d12e639..1d188101 100644
--- a/parse.y
+++ b/parse.y
@@ -5775,7 +5775,12 @@ decode_prompt_string (string)
 #endif
  tm = localtime (&the_time);
 
- if (c == 'd')
+ if (!tm)
+   {
+ strcpy (timebuf, "??");
+ n = 2;
+   }
+ else if (c == 'd')
n = strftime (timebuf, sizeof (timebuf), "%a %b %d", tm);
  else if (c == 't')
n = strftime (timebuf, sizeof (timebuf), "%H:%M:%S", tm);
@@ -5801,19 +5806,32 @@ decode_prompt_string (string)
  (void) time (&the_time);
  tm = localtime (&the_time);
  string += 2;  /* skip { */
- timefmt = xmalloc (strlen (string) + 3);
- for (t = timefmt; *string && *string != '}'; )
-   *t++ = *string++;
- *t = '\0';
+ t = string;
+ while (*string && *string != '}')
+   string++;
  c = *string;  /* tested at add_string */
- if (timefmt[0] == '\0')
+ 
+ if (tm)
+   {
+ size_t timefmtlen = string - t;
+ timefmt = xmalloc (timefmtlen + 3);
+ memcpy (timefmt, t, timefmtlen);
+ timefmt[timefmtlen] = '\0';
+ 
+ if (timefmt[0] == '\0')
+   {
+ timefmt[0] = '%';
+ timefmt[1] = 'X'; /* locale-specific current time */
+ timefmt[2] = '\0';
+   }
+ n = strftime (timebuf, sizeof (timebuf), timefmt, tm);
+ free (timefmt);
+   }
+ else
{
- timefmt[0] = '%';
- timefmt[1] = 'X'; /* locale-specific current time */
- timefmt[2] = '\0';
+ strcpy (timebuf, "??");
+ n = 2;
}
- n = strftime (timebuf, sizeof (timebuf), timefmt, tm);
- free (timefmt);
 
  if (n == 0)
timebuf[0] = '\0';
-- 
2.39.2




Re: Parallelization of shell scripts for 'configure' etc.

2022-06-14 Thread Paul Eggert

On 6/14/22 18:55, Ángel wrote:

Do you have any handy example of configure that takes too long to run?


Sure. Coreutils, emacs. Pretty much any nontrivial configure script 
takes longer than it should.


I understand that parallelization of shell scripts is nontrivial.




Re: Parallelization of shell scripts for 'configure' etc.

2022-06-14 Thread Paul Eggert

On 6/14/22 10:11, Nick Bowler wrote:


The resulting config.h is correct but pa.sh took almost 1 minute to run
the configure script, about ten times longer than dash takes to run the
same script.  More than half of that time appears to be spent just
loading the program into pa.sh, before a single shell command is
actually executed.


Ouch. Thanks for looking into this, and sorry it took so much of your 
time. It appears that PaSh itself isn't suitable for prime-time use. 
This isn't too surprising, though, as it's a research project and I 
wouldn't expect it to compete with production shells. The main question 
here is whether the ideas of PaSh are good ones for improving Bash.





Re: Parallelization of shell scripts for 'configure' etc.

2022-06-13 Thread Paul Eggert

On 6/13/22 18:25, Dale R. Worley wrote:

It seems to me that bash provides the needed tools -- "( ... ) &" lets
you run things in parallel.  Similarly, if you've got a lot of small
tasks with a complex web of dependencies, you can encode that in a
"makefile".

It seems to me that the heavy work is rebuilding how "configure" scripts
are constructed based on which items can be run in parallel.


Yes, all that could be done in theory, but it'd take a lot of hacking 
and it's been decades and it hasn't happened.


I'd rather have shell scripts "just work" in parallel with a minimum of 
fuss.





Parallelization of shell scripts for 'configure' etc.

2022-06-13 Thread Paul Eggert
In many Gnu projects, the 'configure' script is the biggest barrier to 
building because it takes s long to run. Is there some way that we 
could improve its performance without completely reengineering it, by 
improving Bash so that it can parallelize 'configure' scripts?


For ideas about this, please see PaSh-JIT:

Kallas K, Mustafa T, Bielak J, Karnikis D, Dang THY, Greenberg M, 
Vasilakis N. Practically correct, just-in-time shell script 
parallelization. Proc OSDI 22. July 2022. 
https://nikos.vasilak.is/p/pash:osdi:2022.pdf


I've wanted something like this for *years* (I assigned a simpler 
version to my undergraduates but of course it was too much to expect 
them to implement it) and I hope some sort of parallelization like this 
can get into production with Bash at some point (or some other shell if 
Bash can't use this idea).




Re: bug#54785: for floating point, printf should use double like in C instead of long double

2022-04-30 Thread Paul Eggert

On 4/30/22 05:48, Vincent Lefevre wrote:

Yes, but to be clear, POSIX says:

   shall be evaluated as if by the strtod() function if the
   corresponding conversion specifier is a, A, e, E, f, F, g, or G

so the number should be regarded as a double-precision number
(type double).


Yes, but POSIX does not require the C type 'double' and the C function 
strtod to be implemented via IEEE-754 64-bit floating point. POSIX 
allows 'double' and 'strtod' to be implemented via x86-64 
extended-precision (80-bit) floating point, or by any other 
floating-point type that satisfies some (weak) properties. I see no 
requirement that the shell must be implemented as if by the standard c99 
command with the default options.


The POSIX requirements on the implementation of 'double' and 'strtod' 
are so lax that Bash 'printf' could even use IEEE-754 32-bit floating 
point, if it wanted to. One could build Bash with 'gcc -mlong-double=32 
-mdouble=32' assuming these options work, and the result would conform 
to POSIX. (Not that I'm suggesting this!)




Concerning the compatibility, the question is: with what?


I agree that it'd be a net win for Bash to use plain 'double' here; your 
discussion of the various compatibility plusses of doing that is 
compelling to me.




Re: bug#54785: for floating point, printf should use double like in C instead of long double

2022-04-29 Thread Paul Eggert

On 4/29/22 13:04, Chet Ramey wrote:


I think I'm going to stick with the behavior I proposed, fixing the POSIX
conformance issue and preserving backwards compatibility, until I hear more
about whether backwards compatibility is an issue here.


Come to think of it, as far as POSIX is concerned Bash doesn't need to 
change what it does. POSIX doesn't require that the shelll printf 
command be compiled with any particular environment. It would conform to 
POSIX, for example, if Bash's printf were compiled with an IBM floating 
point implementation rather than with an IEEE floating point 
implementation, so long as Bash's printf parses floating-point strings 
the way strtod is supposed to parse strings on an IBM mainframe. 
Similarly, Bash's printf can use an 80-bit floating point format if 
available; it will still conform to POSIX.


So this isn't a POSIX conformance issue; only a compatibility issue. Is 
it more important for the Bash printf to behave like most other shells 
and other programs, or is it more important for Bash printf to behave 
like it has for the last 18 years or so?




Re: bug#54785: for floating point, printf should use double like in C instead of long double

2022-04-25 Thread Paul Eggert

On 4/25/22 11:22, Chet Ramey wrote:

Thanks for the input.


You're welcome. Whenever you decide what to do about this, could you 
please let us know? I'd like coreutils printf to stay compatible with 
Bash printf. Thanks.




Re: bug#54785: for floating point, printf should use double like in C instead of long double

2022-04-25 Thread Paul Eggert

On 4/11/22 11:52, Chet Ramey wrote:

On 4/9/22 3:31 PM, Paul Eggert wrote:



It sounds like there are three cases.

1. If the `L' modifier is supplied, as an extension (POSIX doesn't allow
    length modifiers for the printf utility), use long double. This would
    work in both default and posix modes.

2. In posix mode, use strtod() and double.

3. In default mode, use the existing code to get the highest possible
    precision, as the code has done for over 20 years.


That'll fix the POSIX compatibility bug. However, it may be better for 
Bash to just do (1) if 'L' is supplied and (2) otherwise, even if this 
is less precise than (3). Doing it this simpler way will likely be more 
useful for the small number of people who care whether 'printf' uses 
'double' or 'long double' internally (and nobody else will care).


Doing it this way is what BSD sh does, and it's good to be compatible 
with BSD sh. Similarly for dash and for other shells.


It's also what other GNU programs do. For example, on x86-64:

  $ awk 'BEGIN {printf "%.100g\n", 0.1}'
  0.155511151231257827021181583404541015625
  $ emacs -batch -eval '(message "%.100g" 0.1)'
  0.155511151231257827021181583404541015625
  $ printf "%.100g\n" 0.1
  0.100013552527156068805425093160010874271392822265625

printf is the outlier here, and although its answer is closer to the 
mathematical value, that's not as useful as being closer to what most 
other apps do.


Perhaps it was OK for sh printf to use long double 20 years ago. I even 
had a hand in implementing that.[1] But nowadays it feels like a 
misfire. The overwhelming majority of apps that have developed over the 
past 20 years that use newer languages like JavaScript and Java, do not 
support 'long double'; when interoperating with these apps, using 'long 
double' in Bash printf likely causes more trouble than it cures.


[1]: 
https://git.savannah.gnu.org/cgit/coreutils.git/commit/?id=830de2708207b7e48464e4778b55e582bac49832




Re: bug#54785: for floating point, printf should use double like in C instead of long double

2022-04-09 Thread Paul Eggert

Vincent Lefevre wrote in :


$ zsh -fc '/usr/bin/printf "%a\n" $((43./2**22))'
0xa.c00025cp-20

instead of

0xa.cp-20


To summarize, this test case is:

printf '%a\n' 1.0251998901367188e-05

and the problem is that converting 1.0251998901367188e-05 to long double 
prints the too-precise "0xa.c00025cp-20", whereas you want it to 
convert to double (which matches what most other programs do) and to 
print "0xa.cp-20" or equivalent.



(Note that ksh uses long double internally, but does not ensure the
round trip back to long double


Yes, ksh messes up here. However, it's more important for Coreutils 
printf to be compatible with the GNU shell, and Bash uses long double:


$ echo $BASH_VERSION
5.1.8(1)-release
$ /usr/bin/printf --version | head -n1
printf (GNU coreutils) 8.32
$ printf '%a\n' 1.0251998901367188e-05
0xa.c00025cp-20
$ /usr/bin/printf '%a\n' 1.0251998901367188e-05
0xa.c00025cp-20



I suggest to parse the argument as a "long double" only if the "L"
length modifier is provided, like in C.

Thanks, good idea.

I checked, and this also appears to be a POSIX conformance issue. POSIX 
 says that floating point operands "shall be evaluated as if by the 
strtod() function". This means double, not long double.


Whatever decision we make here, we should be consistent with Bash so 
I'll cc this email to bug-bash.


I propose that we change both coreutils and Bash to use 'double' rather 
than 'long double' here, unless the user specifies the L modifier (e.g., 
"printf '%La\n' ...". I've written up a patch (attached) to Bash 5.2 
alpha to do that. Assuming the Bash maintainer likes this proposal, I 
plan to implement something similar for Coreutils printf.diff '-x*~' -pru bash-5.2-alpha/builtins/printf.def bash-5.2-alpha-double/builtins/printf.def
--- bash-5.2-alpha/builtins/printf.def	2021-12-29 13:09:20.0 -0800
+++ bash-5.2-alpha-double/builtins/printf.def	2022-04-09 12:02:35.330476097 -0700
@@ -215,13 +215,14 @@ static uintmax_t getuintmax PARAMS((void
 
 #if defined (HAVE_LONG_DOUBLE) && HAVE_DECL_STRTOLD && !defined(STRTOLD_BROKEN)
 typedef long double floatmax_t;
-#  define FLOATMAX_CONV	"L"
+#  define USE_LONG_DOUBLE 1
 #  define strtofltmax	strtold
 #else
 typedef double floatmax_t;
-#  define FLOATMAX_CONV	""
+#  define USE_LONG_DOUBLE 0
 #  define strtofltmax	strtod
 #endif
+static double getdouble PARAMS((void));
 static floatmax_t getfloatmax PARAMS((void));
 
 static intmax_t asciicode PARAMS((void));
@@ -247,7 +248,7 @@ printf_builtin (list)
  WORD_LIST *list;
 {
   int ch, fieldwidth, precision;
-  int have_fieldwidth, have_precision;
+  int have_fieldwidth, have_precision, use_Lmod;
   char convch, thisch, nextch, *format, *modstart, *precstart, *fmt, *start;
 #if defined (HANDLE_MULTIBYTE)
   char mbch[25];		/* 25 > MB_LEN_MAX, plus can handle 4-byte UTF-8 and large Unicode characters*/
@@ -422,8 +423,12 @@ printf_builtin (list)
 
 	  /* skip possible format modifiers */
 	  modstart = fmt;
+	  use_Lmod = 0;
 	  while (*fmt && strchr (LENMODS, *fmt))
-	fmt++;
+	{
+	  use_Lmod |= USE_LONG_DOUBLE && *fmt == 'L';
+	  fmt++;
+	}
 	
 	  if (*fmt == 0)
 	{
@@ -694,11 +699,24 @@ printf_builtin (list)
 #endif
 	  {
 		char *f;
-		floatmax_t p;
 
-		p = getfloatmax ();
-		f = mklong (start, FLOATMAX_CONV, sizeof(FLOATMAX_CONV) - 1);
-		PF (f, p);
+		if (use_Lmod)
+		  {
+		floatmax_t p;
+
+		p = getfloatmax ();
+		f = mklong (start, "L", 1);
+		PF (f, p);
+		  }
+		else
+		  {
+		double p;
+
+		p = getdouble ();
+		f = mklong (start, "", 0);
+		PF (f, p);
+		  }
+
 		break;
 	  }
 
@@ -1248,35 +1266,40 @@ getuintmax ()
   return (ret);
 }
 
+#define getfloat(ret, convert) \
+  char *ep; \
+  if (garglist == 0) \
+return 0; \
+  if (garglist->word->word[0] == '\'' || garglist->word->word[0] == '"') \
+return asciicode (); \
+  errno = 0; \
+  (ret) = (convert) (garglist->word->word, &ep); \
+  if (*ep) \
+{ \
+  sh_invalidnum (garglist->word->word); \
+  /* Same thing about POSIX.2 conversion error requirements. */ \
+  if (0) \
+(ret) = 0; \
+  conversion_error = 1; \
+} \
+  else if (errno == ERANGE) \
+printf_erange (garglist->word->word); \
+  garglist = garglist->next
+
+static double
+getdouble ()
+{
+  double ret;
+  getfloat (ret, strtod);
+  return ret;
+}
+
 static floatmax_t
 getfloatmax ()
 {
   floatmax_t ret;
-  char *ep;
-
-  if (garglist == 0)
-return (0);
-
-  if (garglist->word->word[0] == '\'' || garglist->word->word[0] == '"')
-return asciicode ();
-
-  errno = 0;
-  ret = strtofltmax (garglist->word->word, &ep);
-
-  if (*ep)
-{
-  sh_invalidnum (garglist->word->word);
-#if 0
-  /* Same thing about POSIX.2 conversion error requirements. */
-  ret = 0;
-#endif
-  conversion_error = 1;
-}
-  else if (errno == ERANGE)
-printf_erange (garglist->word->word);
-
-  ga

Bash 4.4-rc1 incompatibility with future Emacs $EMACS

2016-04-08 Thread Paul Eggert
[Sending this to bug-bash@gnu.org since the mail was rejected by 
bash-test...@cwru.edu.]


Configuration Information [Automatically generated, do not change]:
Machine: x86_64
OS: linux-gnu
Compiler: gcc
Compilation CFLAGS:  -DPROGRAM='bash' -DCONF_HOSTTYPE='x86_64'
-DCONF_OSTYPE='linux-gnu' -DCONF_MACHTYPE='x86_64-unknown-linux-gnu'
-DCONF_VENDOR='unknown' -DLOCALEDIR='/tmp/prefix/share/locale'
-DPACKAGE='bash' -DSHELL -DHAVE_CONFIG_H -DDEBUG -DMALLOC_DEBUG -I. -I.
-I./include -I./lib   -g -O2 -Wno-parentheses -Wno-format-security
uname output: Linux penguin.cs.ucla.edu 4.4.6-300.fc23.x86_64 #1 SMP Wed
Mar 16 22:10:37 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
Machine Type: x86_64-unknown-linux-gnu

Bash Version: 4.4
Patch Level: 0
Release Status: rc1

Description:
 Please see attached patch.

Repeat-By:
 Please see attached patch.

Fix:
 Please see attached patch.
From 75d409f43d09d1323416db90121bc6bf54cbc3ff Mon Sep 17 00:00:00 2001
From: Paul Eggert 
Date: Fri, 8 Apr 2016 11:22:39 -0700
Subject: [PATCH] Fix compatibility problem with INSIDE_EMACS etc.

The checks for deciding whether bash is being run in a GNU Emacs shell
window have been tweaked to better support how the future versions of
Emacs will set environment variables.

Here are details about the problem.  Bash's heuristic that infers
whether Bash is being run inside the Emacs 'M-x term' command will
have problems when running inside future versions of Emacs.  Although
Emacs 25 'M-x term' will continue to set both variables (e.g.,
EMACS='25.1 (term:0.96)' and INSIDE_EMACS='25.1,term:0.96') for
compatibility with Bash 4.3 and earlier, we would like Bash 4.4 and
later to work with future versions of Emacs that that set only
INSIDE_EMACS.

Problem reported by Phillip Lord in <http://bugs.gnu.org/20484#108>.

* shell.c (main): Tweak tests for whether we are running in an Emacs
shell window, to accommodate future Emacs versions better, and to
document and reflect historical practice more accurately.
---
 shell.c | 38 ++
 1 file changed, 30 insertions(+), 8 deletions(-)

diff --git a/shell.c b/shell.c
index 63f139b..c91baf0 100644
--- a/shell.c
+++ b/shell.c
@@ -570,25 +570,47 @@ main (argc, argv, env)
   set_default_locale_vars ();
 
   /*
-   * M-x term -> TERM=eterm EMACS=22.1 (term:0.96)	(eterm)
-   * M-x shell -> TERM=dumb EMACS=t			(no line editing)
-   * M-x terminal -> TERM=emacs-em7955 EMACS=		(line editing)
+   * M-x term -> TERM='eterm-color' INSIDE_EMACS='25.1,term:0.96' (eterm)
+   * M-x shell -> TERM='dumb' INSIDE_EMACS='25.1,comint' (no line editing)
+   *
+   * Older versions of Emacs may set EMACS to 't' or to something like
+   * '22.1 (term:0.96)' instead of (or in addition to) setting INSIDE_EMACS.
+   * They may set TERM to 'eterm' instead of 'eterm-color'.  They may have
+   * a now-obsolete command that sets neither EMACS nor INSIDE_EMACS:
+   * M-x terminal -> TERM='emacs-em7955' (line editing)
*/
   if (interactive_shell)
 {
-  char *term, *emacs;
+  char *term, *emacs, *inside_emacs;
+  int emacs_term, in_emacs;
 
   term = get_string_value ("TERM");
   emacs = get_string_value ("EMACS");
+  inside_emacs = get_string_value ("INSIDE_EMACS");
+
+  if (inside_emacs)
+	{
+	  emacs_term = strstr (inside_emacs, ",term:") != 0;
+	  in_emacs = 1;
+	}
+  else if (emacs)
+	{
+	  /* Infer whether we are in an older Emacs.  Do not accept
+	 just any value for EMACS, as the value might be an
+	 executable file name or a shell command.  */
+	  emacs_term = strstr (emacs, " (term:") != 0;
+	  in_emacs = emacs_term || STREQ (emacs, "t");
+	}
+  else
+	emacs_term = in_emacs = 0;
 
   /* Not sure any emacs terminal emulator sets TERM=emacs any more */
   no_line_editing |= STREQ (term, "emacs");
-  no_line_editing |= emacs && emacs[0] == 't' && emacs[1] == '\0' && STREQ (term, "dumb");
-  no_line_editing |= get_string_value ("INSIDE_EMACS") != 0;
+  no_line_editing |= in_emacs && STREQ (term, "dumb");
 
   /* running_under_emacs == 2 for `eterm' */
-  running_under_emacs = (emacs != 0) || STREQN (term, "emacs", 5);
-  running_under_emacs += STREQN (term, "eterm", 5) && emacs && strstr (emacs, "term");
+  running_under_emacs = in_emacs || STREQN (term, "emacs", 5);
+  running_under_emacs += emacs_term && STREQN (term, "eterm", 5);
 
   if (running_under_emacs)
 	gnu_error_format = 1;
-- 
2.5.5



Bash should look at INSIDE_EMACS not just EMACS

2015-03-30 Thread Paul Eggert
Configuration Information [Automatically generated, do not change]:
Machine: x86_64
OS: linux-gnu
Compiler: gcc
Compilation CFLAGS:  -DPROGRAM='bash' -DCONF_HOSTTYPE='x86_64' 
-DCONF_OSTYPE='linux-gnu' -DCONF_MACHTYPE='x86_64-unknown-linux-gnu' 
-DCONF_VENDOR='unknown' -DLOCALEDIR='/tmp/prefix/share/locale' -DPACKAGE='bash' 
-DSHELL -DHAVE_CONFIG_H   -I.  -I. -I./include -I./lib   -g -O2
uname output: Linux Penguin.CS.UCLA.EDU 3.19.2-201.fc21.x86_64 #1 SMP Tue Mar 
24 03:08:23 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux
Machine Type: x86_64-unknown-linux-gnu

Bash Version: 4.3
Patch Level: 33
Release Status: release

Description:
Currently 'bash' looks at the EMACS environment variable when
deciding whether it is running under Emacs.  As described in
the "Interactive Subshell" chapter of the Emacs manual

http://www.gnu.org/software/emacs/manual/html_node/emacs/Interactive-Shell.html
this variable is obsolescent and software is supposed to use the
variable INSIDE_EMACS instead.

Repeat-By:
Run a future version of Emacs, which does not set EMACS,
and run Bash as a subshell of it.

Fix:

2015-03-30  Paul Eggert  

* shell.c (main): Also look at INSIDE_EMACS when deciding
whether to use line editing.  Simplify nearby code that tests
'term', since 'term' is guaranteed to be non-null here.

--- bash-4.3.33/shell.c 2015-03-30 10:42:10.871889889 -0700
+++ bash-4.3.33-fix/shell.c 2015-03-30 14:34:28.698052813 -0700
@@ -580,12 +580,13 @@ main (argc, argv, env)
   emacs = get_string_value ("EMACS");

   /* Not sure any emacs terminal emulator sets TERM=emacs any more */
-  no_line_editing |= term && (STREQ (term, "emacs"));
+  no_line_editing |= STREQ (term, "emacs");
   no_line_editing |= emacs && emacs[0] == 't' && emacs[1] == '\0' && STREQ 
(term, "dumb");
+  no_line_editing |= get_string_value ("INSIDE_EMACS") != 0;

   /* running_under_emacs == 2 for `eterm' */
-  running_under_emacs = (emacs != 0) || (term && STREQN (term, "emacs", 
5));
-  running_under_emacs += term && STREQN (term, "eterm", 5) && emacs && 
strstr (emacs, "term");
+  running_under_emacs = (emacs != 0) || STREQN (term, "emacs", 5);
+  running_under_emacs += STREQN (term, "eterm", 5) && emacs && strstr 
(emacs, "term");

   if (running_under_emacs)
gnu_error_format = 1;



Re: locale specific ordering in EN_US -- why is a

2013-06-28 Thread Paul Eggert
On 06/28/2013 09:48 AM, Paolo Bonzini wrote:
> I may even agree, but the fact remains that until you fix it in glibc,
> you have not fixed it.  As long as glibc doesn't change, there's no
> point in changing everything else.

Unfortunately, one reason to change glibc is: "Ouch! all these
GNU applications have awful workarounds for glibc's undesirable behavior."
So I'm afraid there is a point to changing modules outside glibc:
it strengthens the argument for changing glibc.




Bash loops and otherwise mishandles long lines

2012-12-23 Thread Paul Eggert

Here's how to reproduce the problem:

(printf 'ln '
 perl -e 'print "x"x(2**31)'
 printf ' '
 perl -e 'print "x"x(2**30)'
 printf '\n'
) >bigscript
bash bigscript

On my x86-64 host, Bash loops, seemingly forever.
I expect it's using a 32-bit integer to keep track
of line lengths, somewhere.

This bug report was inspired by the following report:

http://debbugs.gnu.org/13258

That bug report is against coreutils, but the real
bug was in bash, so I'm closing bug 13258 and forwarding
this to bug-bash@gnu.org.



'exec

2011-11-12 Thread Paul Eggert
Configuration Information [Automatically generated, do not change]:
Machine: x86_64
OS: linux-gnu
Compiler: gcc
Compilation CFLAGS:  -DPROGRAM='bash' -DCONF_HOSTTYPE='x86_64' 
-DCONF_OSTYPE='linux-gnu' -DCONF_MACHTYPE='x86_64-unknown-linux-gnu' 
-DCONF_VENDOR='unknown' -DLOCALEDIR='/usr/local/cs/bash-4.2/share/locale' 
-DPACKAGE='bash' -DSHELL -DHAVE_CONFIG_H   -I.  -I. -I./include -I./lib   -g -O2
uname output: Linux lnxsrvg1.seas.ucla.edu 2.6.18-274.7.1.el5 #1 SMP Mon Oct 17 
11:57:14 EDT 2011 x86_64 x86_64 x86_64 GNU/Linux
Machine Type: x86_64-unknown-linux-gnu

Bash Version: 4.2
Patch Level: 10
Release Status: release

Description:
Bash can't do I/O redirection using 'exec' when operating
in an environment where all FDs above 10 are taken, even
if there are FDs available below 10.

This caused a coreutils test case to fail.  There is a
workaround, but the Bash bug should get fixed too.  See:
.

Repeat-By:
Run this command:

  bash -c 'ulimit -n 6; exec 

Autoconf test failure caused by Bash bug with "{ ... } >unwritable"

2007-11-02 Thread Paul Eggert
Configuration Information [Automatically generated, do not change]:
Machine: sparc
OS: solaris2.8
Compiler: gcc -m64
Compilation CFLAGS:  -DPROGRAM='bash' -DCONF_HOSTTYPE='sparc' 
-DCONF_OSTYPE='solaris2.8' -DCONF_MACHTYPE='sparc-sun-solaris2.8' 
-DCONF_VENDOR='sun' -DLOCALEDIR='/usr/local/cs/bash-3.2/share/locale' 
-DPACKAGE='bash' -DSHELL -DHAVE_CONFIG_H -DSOLARIS   -I.  -I. -I./include 
-I./lib   -g -O2
uname output: SunOS westholme 5.8 Generic_117350-49 sun4u sparc 
SUNW,Sun-Fire-280R
Machine Type: sparc-sun-solaris2.8

Bash Version: 3.2
Patch Level: 25
Release Status: release

Description:

I'm following up on this thread:

http://lists.gnu.org/archive/html/autoconf/2007-11/msg7.html

which reported an Autoconf problem that we have tracked down to a bug
in Bash.  The problem is that this command:

   bash -c '{ echo foo; } >unwriteable'

exits with status 0.  We have a workaround, but the Bash bug should
get fixed.

Repeat-By:

$ touch foo
$ chmod a-w foo
$ bash -c '{ echo foo; } >foo'; echo $?
bash: foo: Permission denied
0

The last line of output should be 1, not 0.

Fix:

2007-11-02  Paul Eggert  <[EMAIL PROTECTED]>

* execute_cmd.c (execute_command_internal): Consider a redirection
failure to be a failure in the last compound command.
* tests/redir7.sub: Test for this bug.

--- execute_cmd.c~  2007-11-02 13:01:35.789664000 -0700
+++ execute_cmd.c   2007-11-02 14:44:51.40199 -0700
@@ -614,7 +614,7 @@
   cleanup_redirects (redirection_undo_list);
   redirection_undo_list = (REDIRECT *)NULL;
   dispose_exec_redirects ();
-  return (EXECUTION_FAILURE);
+  return (last_command_exit_value = EXECUTION_FAILURE);
 }
 
   if (redirection_undo_list)
--- tests/redir7.sub~   2005-10-11 13:00:28.0 -0700
+++ tests/redir7.sub2007-11-02 14:39:02.220301200 -0700
@@ -67,3 +67,10 @@
 
 # fixed in bash-3.1
 echo 'exec <&3' | ${THIS_SH} 3<&0
+
+# fixed in bash-3.3
+if ${THIS_SH} -c '{ echo foo; } > /' 2>/dev/null; then
+  echo "bash -c '{ echo foo; } > /' succeeded, but it should fail."
+else
+  :
+fi




Re: echo "enhancement" leads to confused legacy script tools...

2006-03-27 Thread Paul Eggert
Andreas Schwab <[EMAIL PROTECTED]> writes:

>> There's a little history here.  POSIX 1003.2-1992 said that echo has
>> implementation-defined behavior if given any options, or if any
>
> Are you sure about "any option"?  The current spec only talks about -n.

Yes, I have the printed copy of POSIX 1003.2-1992, and it has
different wording in this area.

Quite a zoo, huh?


___
Bug-bash mailing list
Bug-bash@gnu.org
http://lists.gnu.org/mailman/listinfo/bug-bash


Re: echo "enhancement" leads to confused legacy script tools...

2006-03-20 Thread Paul Eggert
Linda W <[EMAIL PROTECTED]> writes:

> I believe bash is broken in regards to using "any" number after
> "\" as an octal value.  The shell specifications require the leading
> zero for an octal constant

I'm afraid this is backwards.  This POSIX+XSI requirement constrains
applications, not implementations.

POSIX requires that if an application wants an octal escape for (say)
the character with octal code 123, it must execute "echo '\0123'".  If
an application executes "echo '\123'" (without the "0"), POSIX says
that the results are implementation-defined.  Hence Bash can interpret
\123 as an octal escape as well, if it so chooses, and still conform
to POSIX+XSI.  A similar analysis applies to \x escapes.

For details, please see .

Autoconf deals with shells that do not conform to XSI, and where the
results are implementation-defined if there's a backslash anywhere in
the string, so to some extent this point is moot for Autoconf (though
it's undeniably a portability problem, one that is documented in the
Autoconf manual under "Limitations of Builtins").


___
Bug-bash mailing list
Bug-bash@gnu.org
http://lists.gnu.org/mailman/listinfo/bug-bash


Re: echo "enhancement" leads to confused legacy script tools...

2006-03-20 Thread Paul Eggert
Andreas Schwab <[EMAIL PROTECTED]> writes:

> But note that bash interprets -n as an option, which is not compliant with
> XSI.

Bash doesn't claim conformance to XSI, so that's OK as far as Bash is
concerned.  Autoconf (and I assume Squid) is supposed be portable to
all POSIX hosts, not merely POSIX+XSI hosts, so it should work with
Bash; so this is still a bug in either Autoconf or Squid, not in Bash.

There's a little history here.  POSIX 1003.2-1992 said that echo has
implementation-defined behavior if given any options, or if any
operands contain '\'.  This allows both traditional (echo -n) and
System V (backslash) interpretation.

SUSv2 came down squarely on the System V side.

But the BSD folks revolted on this, and POSIX 1003.1-2001 reverted to
the POSIX 1003.2-1992 spec, with the compromise of putting the System
V stuff into the XSI ghetto.


___
Bug-bash mailing list
Bug-bash@gnu.org
http://lists.gnu.org/mailman/listinfo/bug-bash


Re: echo "enhancement" leads to confused legacy script tools...

2006-03-19 Thread Paul Eggert
Henrik Nordstrom <[EMAIL PROTECTED]> writes:

> sön 2006-03-19 klockan 12:57 -0800 skrev Paul Eggert:
>
>> Autoconf deals with shells that do not conform to XSI, and where the
>> results are implementation-defined if there's a backslash anywhere in
>> the string, so to some extent this point is moot for Autoconf (though
>> it's undeniably a portability problem, one that is documented in the
>> Autoconf manual under "Limitations of Builtins").
>
> I thought so too, but in this case it is a autoconf 2.57 output which is
> failing, ending up with a lot of control characters instead of the
> expected sed backreferences..

Autoconf 2.57 is pretty old.  Do you have the same problem with 2.59?
If not, then the problem's solved from the Autoconf point of view.
Otherwise, I'd ask you to try it with CVS Autoconf (which has further
fixes in this area).


___
Bug-bash mailing list
Bug-bash@gnu.org
http://lists.gnu.org/mailman/listinfo/bug-bash


coordinating bash and coreutils: which bash?

2005-10-20 Thread Paul Eggert
A few months ago we went through a POSIX-compatibility sweep of
coreutils, and in my nonexistent spare time I'd like to migrate some
of those fixes into the Bash builtins that duplicate coreutils.
Conversely, I'd like to migrate any fixes made by Bash in this area
into coreutils.

Which version of Bash should I use to do this?  I vaguely recall that
an alpha or beta version was released recently, but I can't find this
announcement on the Web, nor could I find recent sources when I poked
around in the obvious FTP or CVS places.

Thanks.


___
Bug-bash mailing list
Bug-bash@gnu.org
http://lists.gnu.org/mailman/listinfo/bug-bash