From d890583ecccd1a035cd609a19ff910af8c797b7e Mon Sep 17 00:00:00 2001
From: Ethan Pini <ethan@pini.dev>
Date: Sat, 27 Jun 2026 20:46:46 -0700
Subject: [PATCH 3/3] non-blocking write instead of limiting HEREDOC_PIPESIZE
 on Mac

---
 configure    |  2 +-
 configure.ac |  2 +-
 general.c    | 15 +++++++++++++++
 general.h    |  1 +
 redir.c      | 22 ++++++++++++++++++++++
 5 files changed, 40 insertions(+), 2 deletions(-)

diff --git a/configure b/configure
index e1b3547d..037eeed4 100755
--- a/configure
+++ b/configure
@@ -23133,7 +23133,7 @@ hpux*)		LOCAL_CFLAGS="-DHPUX -DTGETENT_BROKEN -DTGETFLAG_BROKEN" ;;
 dgux*)		LOCAL_CFLAGS=-D_DGUX_SOURCE; LOCAL_LIBS=-ldgc ;;
 isc*)		LOCAL_CFLAGS=-Disc386 ;;
 rhapsody*)	LOCAL_CFLAGS=-DRHAPSODY ;;
-darwin*)	LOCAL_CFLAGS="-DMACOSX -DHEREDOC_PIPESIZE=512";;
+darwin*)	LOCAL_CFLAGS="-DMACOSX -DPIPESIZE_DYNAMIC";;
 sco3.2v5*)	LOCAL_CFLAGS="-b elf -DWAITPID_BROKEN -DPATH_MAX=1024" ;;
 sco3.2v4*)	LOCAL_CFLAGS="-DMUST_UNBLOCK_CHLD -DPATH_MAX=1024" ;;
 sco3.2*)	LOCAL_CFLAGS=-DMUST_UNBLOCK_CHLD ;;
diff --git a/configure.ac b/configure.ac
index 0b9adc8f..b53aa1d2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1209,7 +1209,7 @@ hpux*)		LOCAL_CFLAGS="-DHPUX -DTGETENT_BROKEN -DTGETFLAG_BROKEN" ;;
 dgux*)		LOCAL_CFLAGS=-D_DGUX_SOURCE; LOCAL_LIBS=-ldgc ;;
 isc*)		LOCAL_CFLAGS=-Disc386 ;;
 rhapsody*)	LOCAL_CFLAGS=-DRHAPSODY ;;
-darwin*)	LOCAL_CFLAGS="-DMACOSX -DHEREDOC_PIPESIZE=512";;
+darwin*)	LOCAL_CFLAGS="-DMACOSX -DPIPESIZE_DYNAMIC";;
 sco3.2v5*)	LOCAL_CFLAGS="-b elf -DWAITPID_BROKEN -DPATH_MAX=1024" ;;
 sco3.2v4*)	LOCAL_CFLAGS="-DMUST_UNBLOCK_CHLD -DPATH_MAX=1024" ;;
 sco3.2*)	LOCAL_CFLAGS=-DMUST_UNBLOCK_CHLD ;;
diff --git a/general.c b/general.c
index aeffda5c..abd32ab1 100644
--- a/general.c
+++ b/general.c
@@ -609,6 +609,21 @@ sh_validfd (int fd)
   return (fcntl (fd, F_GETFD, 0) >= 0);
 }
 
+/* Set O_NONBLOCK on file descriptor FD. */
+int
+sh_setnonblock (int fd)
+{
+  int fl;
+
+  fl = fcntl (fd, F_GETFL, 0);
+  if (fl < 0)
+  {
+    return fl;
+  }
+
+  return fcntl (fd, F_SETFL, fl | O_NONBLOCK);
+}
+
 int
 fd_ispipe (int fd)
 {
diff --git a/general.h b/general.h
index 5b1eac08..2c936a3b 100644
--- a/general.h
+++ b/general.h
@@ -318,6 +318,7 @@ extern int assignment (const char *, int);
 
 extern int sh_unset_nodelay_mode (int);
 extern int sh_setclexec (int);
+extern int sh_setnonblock (int);
 extern int sh_validfd (int);
 extern int fd_ispipe (int);
 extern void check_dev_tty (void);
diff --git a/redir.c b/redir.c
index 343536b7..da11bba9 100644
--- a/redir.c
+++ b/redir.c
@@ -472,7 +472,29 @@ here_document_to_fd (WORD_DESC *redirectee, enum r_instruction ri)
 	}
 #endif
 
+#if defined (PIPESIZE_DYNAMIC)
+      /* Pipe capacity may be smaller than detected at build time. Set
+         O_NONBLOCK on the write end and make a best-effort attempt,
+         falling back to a tempfile if it would otherwise block. */
+      if (sh_setnonblock (herepipe[1]) < 0)
+      {
+        close (herepipe[0]);
+        close (herepipe[1]);
+        goto use_tempfile;
+      }
+#endif
+
       r = heredoc_write (herepipe[1], document, document_len);
+
+#if defined (PIPESIZE_DYNAMIC)
+      if (r == ENOSPC /* set by heredoc_write if written != herelen */)
+      {
+        close (herepipe[0]);
+        close (herepipe[1]);
+        goto use_tempfile;
+      }
+#endif
+
       if (document != redirectee->word)
 	free (document);
       close (herepipe[1]);
-- 
2.49.0

