[SV 17448] Ignore whitespace around $(file ...) names

The other issues related to whitespace reported in this bug are
not addressed by this change.

* src/functions.c (func_file): Strip whitespace from the start and
end of the filename provided to the $(file ...) function.
* tests/scripts/functions/file: Add tests for this.
* tests/test_driver.pl: Use 3-arg version of open().
This commit is contained in:
Paul Smith 2023-01-08 18:06:54 -05:00
parent a275f4e9ab
commit 36f955b0e8
3 changed files with 53 additions and 18 deletions

View File

@ -2327,6 +2327,10 @@ func_file (char *o, char **argv, const char *funcname UNUSED)
if (fn[0] == '>') if (fn[0] == '>')
{ {
size_t len;
const char *end;
const char *start;
char *nm;
FILE *fp; FILE *fp;
const char *mode = "w"; const char *mode = "w";
@ -2337,14 +2341,21 @@ func_file (char *o, char **argv, const char *funcname UNUSED)
mode = "a"; mode = "a";
++fn; ++fn;
} }
NEXT_TOKEN (fn);
if (fn[0] == '\0') start = next_token (fn);
if (start[0] == '\0')
O (fatal, *expanding_var, _("file: missing filename")); O (fatal, *expanding_var, _("file: missing filename"));
ENULLLOOP (fp, fopen (fn, mode)); end = end_of_token (start);
len = end - start;
nm = alloca (len + 1);
memcpy (nm, start, len);
nm[len] = '\0';
ENULLLOOP (fp, fopen (nm, mode));
if (fp == NULL) if (fp == NULL)
OSS (fatal, reading_file, _("open: %s: %s"), fn, strerror (errno)); OSS (fatal, reading_file, _("open: %s: %s"), nm, strerror (errno));
/* We've changed the contents of a directory, possibly. /* We've changed the contents of a directory, possibly.
Another option would be to look up the directory we changed and reset Another option would be to look up the directory we changed and reset
@ -2357,30 +2368,44 @@ func_file (char *o, char **argv, const char *funcname UNUSED)
int nl = l == 0 || argv[1][l-1] != '\n'; int nl = l == 0 || argv[1][l-1] != '\n';
if (fputs (argv[1], fp) == EOF || (nl && fputc ('\n', fp) == EOF)) if (fputs (argv[1], fp) == EOF || (nl && fputc ('\n', fp) == EOF))
OSS (fatal, reading_file, _("write: %s: %s"), fn, strerror (errno)); OSS (fatal, reading_file, _("write: %s: %s"), nm, strerror (errno));
} }
if (fclose (fp)) if (fclose (fp))
OSS (fatal, reading_file, _("close: %s: %s"), fn, strerror (errno)); OSS (fatal, reading_file, _("close: %s: %s"), nm, strerror (errno));
} }
else if (fn[0] == '<') else if (fn[0] == '<')
{ {
size_t n = 0; size_t n = 0;
size_t len;
const char *end;
const char *start;
char *nm;
FILE *fp; FILE *fp;
++fn; start = next_token (fn + 1);
NEXT_TOKEN (fn);
if (fn[0] == '\0') if (start[0] == '\0')
O (fatal, *expanding_var, _("file: missing filename")); O (fatal, *expanding_var, _("file: missing filename"));
if (argv[1]) if (argv[1])
O (fatal, *expanding_var, _("file: too many arguments")); O (fatal, *expanding_var, _("file: too many arguments"));
ENULLLOOP (fp, fopen (fn, "r")); end = end_of_token (start);
len = end - start;
nm = alloca (len + 1);
memcpy (nm, start, len);
nm[len] = '\0';
ENULLLOOP (fp, fopen (nm, "r"));
if (fp == NULL) if (fp == NULL)
{ {
if (errno == ENOENT) if (errno == ENOENT)
{
DB (DB_VERBOSE, (_("file: Failed to open '%s': %s\n"),
nm, strerror (errno)));
return o; return o;
OSS (fatal, reading_file, _("open: %s: %s"), fn, strerror (errno)); }
OSS (fatal, reading_file, _("open: %s: %s"), nm, strerror (errno));
} }
while (1) while (1)
@ -2394,12 +2419,12 @@ func_file (char *o, char **argv, const char *funcname UNUSED)
} }
if (ferror (fp)) if (ferror (fp))
if (errno != EINTR) if (errno != EINTR)
OSS (fatal, reading_file, _("read: %s: %s"), fn, strerror (errno)); OSS (fatal, reading_file, _("read: %s: %s"), nm, strerror (errno));
if (feof (fp)) if (feof (fp))
break; break;
} }
if (fclose (fp)) if (fclose (fp))
OSS (fatal, reading_file, _("close: %s: %s"), fn, strerror (errno)); OSS (fatal, reading_file, _("close: %s: %s"), nm, strerror (errno));
/* Remove trailing newline. */ /* Remove trailing newline. */
if (n && o[-1] == '\n') if (n && o[-1] == '\n')

View File

@ -219,4 +219,14 @@ run_make_test('$(file <)', '',
run_make_test('$(file foo)', '', run_make_test('$(file foo)', '',
"#MAKEFILE#:1: *** file: invalid file operation: foo. Stop.\n", 512); "#MAKEFILE#:1: *** file: invalid file operation: foo. Stop.\n", 512);
# SV 17448: check whitespace
create_file('out1', "1\n");
run_make_test(q!
all:;$(info $(file < out1 ))
!,
'', "1\n#MAKE#: 'all' is up to date.");
unlink('out1');
1; 1;

View File

@ -434,7 +434,7 @@ sub get_osname
# See if the filesystem supports long file names with multiple # See if the filesystem supports long file names with multiple
# dots. DOS doesn't. # dots. DOS doesn't.
$short_filenames = 0; $short_filenames = 0;
(open (TOUCHFD, "> fancy.file.name") and close (TOUCHFD)) (open (TOUCHFD, '>', 'fancy.file.name') and close (TOUCHFD))
or $short_filenames = 1; or $short_filenames = 1;
unlink ("fancy.file.name") or $short_filenames = 1; unlink ("fancy.file.name") or $short_filenames = 1;
@ -1287,7 +1287,7 @@ sub remove_directory_tree_inner
# #
# foreach my $file (@filenames) { # foreach my $file (@filenames) {
# utime ($now, $now, $file) # utime ($now, $now, $file)
# or (open (TOUCHFD, ">> $file") and close (TOUCHFD)) # or (open (TOUCHFD, '>>', $file) and close (TOUCHFD))
# or &error ("Couldn't touch $file: $!\n", 1); # or &error ("Couldn't touch $file: $!\n", 1);
# } # }
# return 1; # return 1;
@ -1334,7 +1334,7 @@ sub create_file
{ {
my ($filename, @lines) = @_; my ($filename, @lines) = @_;
open (CF, "> $filename") or &error ("Couldn't open $filename: $!\n", 1); open (CF, '>', $filename) or &error ("Couldn't open '$filename': $!\n", 1);
foreach $line (@lines) { foreach $line (@lines) {
print CF $line; print CF $line;
} }