]> git.ipfire.org Git - thirdparty/make.git/commitdiff
[SV 58497] Ensure $(file <) newline removal succeeds
authorPaul Smith <psmith@gnu.org>
Mon, 15 Mar 2021 07:28:11 +0000 (03:28 -0400)
committerPaul Smith <psmith@gnu.org>
Mon, 15 Mar 2021 07:28:11 +0000 (03:28 -0400)
Keep a count of bytes read rather than comparing pointers since the
variable_buffer might get reallocated.

Bug and patch by Ken Tossell <ken@tossell.net>
Regression tests by Dmitry Goncharov <dgoncharov@users.sf.net>
Tweaked by Paul Smith <psmith@gnu.org>

* src/function.c (func_file): Use bytes read rather than a pointer.
* tests/scripts/functions/file: Provide various tests for reading
empty files, files with/without newlines, and large files.

src/function.c
tests/scripts/functions/file
tests/thelp.pl

index d36b7951cb27f8faba6f5d7c3a1aebf48e000c2a..396f129717cc8c5579c1d2c4e59f18a5fb9296fe 100644 (file)
@@ -2303,7 +2303,7 @@ func_file (char *o, char **argv, const char *funcname UNUSED)
     }
   else if (fn[0] == '<')
     {
-      char *preo = o;
+      size_t n = 0;
       FILE *fp;
 
       ++fn;
@@ -2327,8 +2327,10 @@ func_file (char *o, char **argv, const char *funcname UNUSED)
           char buf[1024];
           size_t l = fread (buf, 1, sizeof (buf), fp);
           if (l > 0)
-            o = variable_buffer_output (o, buf, l);
-
+            {
+              o = variable_buffer_output (o, buf, l);
+              n += l;
+            }
           if (ferror (fp))
             if (errno != EINTR)
               OSS (fatal, reading_file, _("read: %s: %s"), fn, strerror (errno));
@@ -2339,9 +2341,8 @@ func_file (char *o, char **argv, const char *funcname UNUSED)
         OSS (fatal, reading_file, _("close: %s: %s"), fn, strerror (errno));
 
       /* Remove trailing newline.  */
-      if (o > preo && o[-1] == '\n')
-        if (--o > preo && o[-1] == '\r')
-          --o;
+      if (n && o[-1] == '\n')
+        o -= 1 + (n > 1 && o[-2] == '\r');
     }
   else
     OS (fatal, *expanding_var, _("file: invalid file operation: %s"), fn);
index eaabd3ac29134959681d0dceef6e764a7ce3532d..a9bf111950b7b8c57d29d79f54f544b7e054a2f4 100644 (file)
@@ -118,6 +118,76 @@ x:;@echo '$(X1)'; echo '$(A)'; echo '$(B)'
 
 unlink('file.out');
 
+# Read an empty file.
+touch("file.out");
+run_make_test(q!# empty file
+X1 := x$(file <file.out)y
+x:;@echo '$(X1)'
+!,
+              '', "xy\n");
+
+unlink('file.out');
+
+# Read a file whose full contents is a newline.
+create_file('file.out', "\n");
+run_make_test(q!# <nl>
+X1 := x$(file <file.out)y
+x:;@echo '$(X1)'
+!,
+              '', "xy\n");
+
+unlink('file.out');
+
+# Read a file which does not end with a newline.
+create_file('file.out', "hello");
+# echo prints a trailig newline, because run_make_test appends a newline.
+run_make_test(q!# hello
+X1 := x$(file <file.out)y
+x:;@echo $(X1)
+!,
+              '', "xhelloy\n");
+
+unlink('file.out');
+
+# Read a file which ends with a newline.
+create_file('file.out', "hello\n");
+# echo prints a trailig newline, because run_make_test appends a newline.
+run_make_test(q!# hello<nl>
+X1 := x$(file <file.out)y
+x:;@echo '$(X1)'
+!,
+              '', "xhelloy\n");
+
+
+unlink('file.out');
+
+# Read a file which ends with multiple newlines.
+create_file('file.out', "hello\n\n");
+run_make_test(q!# hello<nl><nl>
+X1 := x$(file <file.out)y
+export X1
+x:;@echo "$$X1"
+!,
+              '', "xhello\ny\n");
+
+unlink('file.out');
+
+# Read a file whose contents exceed 200 bytes.
+# 200 is the initial size of variable_buffer.
+# File bigger than 200 bytes causes a realloc.
+# The size of the file in this test not only exceeds 200 bytes, it exceeds 65k.
+
+my $s = "hello world, hello world, hello world, hello world, hello world";
+my $answer = $s x 2000;
+create_file('file.out', $answer);
+run_make_test(q!# <hugestring>
+X1 := x$(file <file.out)y
+x:;@echo '$(X1)'
+!,
+              '', "x${answer}y\n");
+
+unlink('file.out');
+
 # Reading from non-existent file
 run_make_test(q!
 X1 := $(file <file.out)
index d8aaa667d40715edc724014dea1f6fb8c564aa43..ed8c819efa8dbe55910372b6d94ad7c18500ee6f 100755 (executable)
@@ -8,7 +8,8 @@
 # Each step consists of an operator and argument.
 #
 # It supports the following operators:
-#  out <word>   : echo <word> to stdout
+#  out <word>   : echo <word> to stdout with a newline
+#  raw <word>   : echo <word> to stdout without adding anything
 #  file <word>  : echo <word> to stdout AND create the file <word>
 #  dir <word>   : echo <word> to stdout AND create the directory <word>
 #  rm <word>    : echo <word> to stdout AND delete the file/directory <word>
@@ -34,6 +35,10 @@ sub op {
         print "$nm\n";
         return 1;
     }
+    if ($op eq 'raw') {
+        print "$nm";
+        return 1;
+    }
 
     # Show the output before creating the file
     if ($op eq 'file') {