Petr Šabata 33fc6c
From 41f5420db7a911fb0833be693205f4db41f05434 Mon Sep 17 00:00:00 2001
Petr Šabata 33fc6c
From: Chet Ramey <chet.ramey@case.edu>
Petr Šabata 33fc6c
Date: Sat, 20 Apr 2019 14:25:52 -0400
Petr Šabata 33fc6c
Subject: [PATCH] Bash-5.0 patch 5: prevent optimizing forks away too
Petr Šabata 33fc6c
 aggressively
Petr Šabata 33fc6c
Petr Šabata 33fc6c
---
Petr Šabata 33fc6c
 builtins/evalstring.c | 26 +++++++++++++++++++++++---
Petr Šabata 33fc6c
 command.h             |  1 +
Petr Šabata 33fc6c
 execute_cmd.c         |  2 ++
Petr Šabata 33fc6c
 patchlevel.h          |  2 +-
Petr Šabata 33fc6c
 4 files changed, 27 insertions(+), 4 deletions(-)
Petr Šabata 33fc6c
Petr Šabata 33fc6c
diff --git a/builtins/evalstring.c b/builtins/evalstring.c
Petr Šabata 33fc6c
index 1496eeec..cadc9bc0 100644
Petr Šabata 33fc6c
--- a/builtins/evalstring.c
Petr Šabata 33fc6c
+++ b/builtins/evalstring.c
Petr Šabata 33fc6c
@@ -100,12 +100,22 @@ should_suppress_fork (command)
Petr Šabata 33fc6c
 	  ((command->flags & CMD_INVERT_RETURN) == 0));
Petr Šabata 33fc6c
 }
Petr Šabata 33fc6c
 
Petr Šabata 33fc6c
+int
Petr Šabata 33fc6c
+can_optimize_connection (command)
Petr Šabata 33fc6c
+     COMMAND *command;
Petr Šabata 33fc6c
+{
Petr Šabata 33fc6c
+  return (*bash_input.location.string == '\0' &&
Petr Šabata 33fc6c
+	  (command->value.Connection->connector == AND_AND || command->value.Connection->connector == OR_OR || command->value.Connection->connector == ';') &&
Petr Šabata 33fc6c
+	  command->value.Connection->second->type == cm_simple);
Petr Šabata 33fc6c
+}
Petr Šabata 33fc6c
+
Petr Šabata 33fc6c
 void
Petr Šabata 33fc6c
 optimize_fork (command)
Petr Šabata 33fc6c
      COMMAND *command;
Petr Šabata 33fc6c
 {
Petr Šabata 33fc6c
   if (command->type == cm_connection &&
Petr Šabata 33fc6c
-      (command->value.Connection->connector == AND_AND || command->value.Connection->connector == OR_OR) &&
Petr Šabata 33fc6c
+      (command->value.Connection->connector == AND_AND || command->value.Connection->connector == OR_OR || command->value.Connection->connector == ';') &&
Petr Šabata 33fc6c
+      (command->value.Connection->second->flags & CMD_TRY_OPTIMIZING) &&
Petr Šabata 33fc6c
       should_suppress_fork (command->value.Connection->second))
Petr Šabata 33fc6c
     {
Petr Šabata 33fc6c
       command->value.Connection->second->flags |= CMD_NO_FORK;
Petr Šabata 33fc6c
@@ -412,8 +422,18 @@ parse_and_execute (string, from_file, flags)
Petr Šabata 33fc6c
 		  command->flags |= CMD_NO_FORK;
Petr Šabata 33fc6c
 		  command->value.Simple->flags |= CMD_NO_FORK;
Petr Šabata 33fc6c
 		}
Petr Šabata 33fc6c
-	      else if (command->type == cm_connection)
Petr Šabata 33fc6c
-		optimize_fork (command);
Petr Šabata 33fc6c
+
Petr Šabata 33fc6c
+	      /* Can't optimize forks out here execept for simple commands.
Petr Šabata 33fc6c
+		 This knows that the parser sets up commands as left-side heavy
Petr Šabata 33fc6c
+		 (&& and || are left-associative) and after the single parse,
Petr Šabata 33fc6c
+		 if we are at the end of the command string, the last in a
Petr Šabata 33fc6c
+		 series of connection commands is
Petr Šabata 33fc6c
+		 command->value.Connection->second. */
Petr Šabata 33fc6c
+	      else if (command->type == cm_connection && can_optimize_connection (command))
Petr Šabata 33fc6c
+		{
Petr Šabata 33fc6c
+		  command->value.Connection->second->flags |= CMD_TRY_OPTIMIZING;
Petr Šabata 33fc6c
+		  command->value.Connection->second->value.Simple->flags |= CMD_TRY_OPTIMIZING;
Petr Šabata 33fc6c
+		}
Petr Šabata 33fc6c
 #endif /* ONESHOT */
Petr Šabata 33fc6c
 
Petr Šabata 33fc6c
 	      /* See if this is a candidate for $( 
Petr Šabata 33fc6c
diff --git a/command.h b/command.h
Petr Šabata 33fc6c
index 32495162..b9e9b669 100644
Petr Šabata 33fc6c
--- a/command.h
Petr Šabata 33fc6c
+++ b/command.h
Petr Šabata 33fc6c
@@ -186,6 +186,7 @@ typedef struct element {
Petr Šabata 33fc6c
 #define CMD_COPROC_SUBSHELL 0x1000
Petr Šabata 33fc6c
 #define CMD_LASTPIPE	    0x2000
Petr Šabata 33fc6c
 #define CMD_STDPATH	    0x4000	/* use standard path for command lookup */
Petr Šabata 33fc6c
+#define CMD_TRY_OPTIMIZING  0x8000	/* try to optimize this simple command */
Petr Šabata 33fc6c
 
Petr Šabata 33fc6c
 /* What a command looks like. */
Petr Šabata 33fc6c
 typedef struct command {
Petr Šabata 33fc6c
diff --git a/execute_cmd.c b/execute_cmd.c
Petr Šabata 33fc6c
index 8b3c83aa..f1d74bfe 100644
Petr Šabata 33fc6c
--- a/execute_cmd.c
Petr Šabata 33fc6c
+++ b/execute_cmd.c
Petr Šabata 33fc6c
@@ -2767,6 +2767,8 @@ execute_connection (command, asynchronous, pipe_in, pipe_out, fds_to_close)
Petr Šabata 33fc6c
 	  ((command->value.Connection->connector == OR_OR) &&
Petr Šabata 33fc6c
 	   (exec_result != EXECUTION_SUCCESS)))
Petr Šabata 33fc6c
 	{
Petr Šabata 33fc6c
+	  optimize_fork (command);
Petr Šabata 33fc6c
+
Petr Šabata 33fc6c
 	  second = command->value.Connection->second;
Petr Šabata 33fc6c
 	  if (ignore_return && second)
Petr Šabata 33fc6c
 	    second->flags |= CMD_IGNORE_RETURN;
Petr Šabata 33fc6c
diff --git a/patchlevel.h b/patchlevel.h
Petr Šabata 33fc6c
index c059f0bd..1bc098b8 100644
Petr Šabata 33fc6c
--- a/patchlevel.h
Petr Šabata 33fc6c
+++ b/patchlevel.h
Petr Šabata 33fc6c
@@ -25,6 +25,6 @@
Petr Šabata 33fc6c
    regexp `^#define[ 	]*PATCHLEVEL', since that's what support/mkversion.sh
Petr Šabata 33fc6c
    looks for to find the patch level (for the sccs version string). */
Petr Šabata 33fc6c
 
Petr Šabata 33fc6c
-#define PATCHLEVEL 4
Petr Šabata 33fc6c
+#define PATCHLEVEL 5
Petr Šabata 33fc6c
 
Petr Šabata 33fc6c
 #endif /* _PATCHLEVEL_H_ */
Petr Šabata 33fc6c
-- 
Petr Šabata 33fc6c
2.17.2
Petr Šabata 33fc6c