Blame posix/wordexp-test.c

Packit 6c4009
/* Copyright (C) 1997-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#include <sys/stat.h>
Packit 6c4009
#include <sys/types.h>
Packit 6c4009
#include <sys/mman.h>
Packit 6c4009
#include <fcntl.h>
Packit 6c4009
#include <unistd.h>
Packit 6c4009
#include <pwd.h>
Packit 6c4009
#include <stdio.h>
Packit 6c4009
#include <stdint.h>
Packit 6c4009
#include <stdlib.h>
Packit 6c4009
#include <string.h>
Packit 6c4009
#include <wordexp.h>
Packit 6c4009
#include <libc-pointer-arith.h>
Packit 6c4009
#include <dso_handle.h>
Packit 6c4009
Packit 6c4009
#define IFS " \n\t"
Packit 6c4009
Packit 6c4009
extern int __register_atfork (void (*) (void), void (*) (void), void (*) (void), void *);
Packit 6c4009
Packit 6c4009
static int __app_register_atfork (void (*prepare) (void), void (*parent) (void), void (*child) (void))
Packit 6c4009
{
Packit 6c4009
  return __register_atfork (prepare, parent, child, __dso_handle);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Number of forks seen.  */
Packit 6c4009
static int registered_forks;
Packit 6c4009
Packit 6c4009
/* For each fork increment the fork count.  */
Packit 6c4009
static void
Packit 6c4009
register_fork (void)
Packit 6c4009
{
Packit 6c4009
  registered_forks++;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
struct test_case_struct
Packit 6c4009
{
Packit 6c4009
  int retval;
Packit 6c4009
  const char *env;
Packit 6c4009
  const char *words;
Packit 6c4009
  int flags;
Packit 6c4009
  size_t wordc;
Packit 6c4009
  const char *wordv[10];
Packit 6c4009
  const char *ifs;
Packit 6c4009
} test_case[] =
Packit 6c4009
  {
Packit 6c4009
    /* Simple word- and field-splitting */
Packit 6c4009
    { 0, NULL, "one", 0, 1, { "one", }, IFS },
Packit 6c4009
    { 0, NULL, "one two", 0, 2, { "one", "two", }, IFS },
Packit 6c4009
    { 0, NULL, "one two three", 0, 3, { "one", "two", "three", }, IFS },
Packit 6c4009
    { 0, NULL, " \tfoo\t\tbar ", 0, 2, { "foo", "bar", }, IFS },
Packit 6c4009
    { 0, NULL, "red , white blue", 0, 4, { "red", ",", "white", "blue", }, " ," },
Packit 6c4009
    { 0, NULL, "one two three", 0, 3, { "one", "two", "three", }, "" },
Packit 6c4009
    { 0, NULL, "one \"two three\"", 0, 2, { "one", "two three", }, IFS },
Packit 6c4009
    { 0, NULL, "one \"two three\"", 0, 2, { "one", "two three", }, "" },
Packit 6c4009
    { 0, "two three", "one \"$var\"", 0, 2, { "one", "two three", }, IFS },
Packit 6c4009
    { 0, "two three", "one $var", 0, 3, { "one", "two", "three", }, IFS },
Packit 6c4009
    { 0, "two three", "one \"$var\"", 0, 2, { "one", "two three", }, "" },
Packit 6c4009
    { 0, "two three", "one $var", 0, 2, { "one", "two three", }, "" },
Packit 6c4009
Packit 6c4009
    /* The non-whitespace IFS char at the end delimits the second field
Packit 6c4009
     * but does NOT start a new field. */
Packit 6c4009
    { 0, ":abc:", "$var", 0, 2, { "", "abc", }, ":" },
Packit 6c4009
Packit 6c4009
    { 0, NULL, "$(echo :abc:)", 0, 2, { "", "abc", }, ":" },
Packit 6c4009
    { 0, NULL, "$(echo :abc:\\ )", 0, 2, { "", "abc", }, ": " },
Packit 6c4009
    { 0, NULL, "$(echo :abc\\ )", 0, 2, { "", "abc", }, ": " },
Packit 6c4009
    { 0, ":abc:", "$(echo $var)", 0, 2, { "", "abc", }, ":" },
Packit 6c4009
    { 0, NULL, ":abc:", 0, 1, { ":abc:", }, ":" },
Packit 6c4009
    { 0, NULL, "$(echo :abc:)def", 0, 3, { "", "abc", "def", },
Packit 6c4009
      ":" },
Packit 6c4009
    { 0, NULL, "$(echo abc:de)f", 0, 2, { "abc", "def", }, ":" },
Packit 6c4009
    { 0, NULL, "$(echo abc:de)f:ghi", 0, 2, { "abc", "def:ghi", },
Packit 6c4009
      ":" },
Packit 6c4009
    { 0, NULL, "abc:d$(echo ef:ghi)", 0, 2, { "abc:def", "ghi", },
Packit 6c4009
      ":" },
Packit 6c4009
    { 0, "abc:", "$var$(echo def:ghi)", 0, 3, { "abc", "def",
Packit 6c4009
							  "ghi", }, ":" },
Packit 6c4009
    { 0, "abc:d", "$var$(echo ef:ghi)", 0, 3, { "abc", "def",
Packit 6c4009
							  "ghi", }, ":" },
Packit 6c4009
    { 0, "def:ghi", "$(echo abc:)$var", 0, 3, { "abc", "def",
Packit 6c4009
							  "ghi", }, ":" },
Packit 6c4009
    { 0, "ef:ghi", "$(echo abc:d)$var", 0, 3, { "abc", "def",
Packit 6c4009
							  "ghi", }, ":" },
Packit 6c4009
Packit 6c4009
    /* Simple parameter expansion */
Packit 6c4009
    { 0, "foo", "${var}", 0, 1, { "foo", }, IFS },
Packit 6c4009
    { 0, "foo", "$var", 0, 1, { "foo", }, IFS },
Packit 6c4009
    { 0, "foo", "\\\"$var\\\"", 0, 1, { "\"foo\"", }, IFS },
Packit 6c4009
    { 0, "foo", "%$var%", 0, 1, { "%foo%", }, IFS },
Packit 6c4009
    { 0, "foo", "-$var-", 0, 1, { "-foo-", }, IFS },
Packit 6c4009
Packit 6c4009
    /* Simple quote removal */
Packit 6c4009
    { 0, NULL, "\"quoted\"", 0, 1, { "quoted", }, IFS },
Packit 6c4009
    { 0, "foo", "\"$var\"\"$var\"", 0, 1, { "foofoo", }, IFS },
Packit 6c4009
    { 0, NULL, "'singly-quoted'", 0, 1, { "singly-quoted", }, IFS },
Packit 6c4009
    { 0, NULL, "contin\\\nuation", 0, 1, { "continuation", }, IFS },
Packit 6c4009
    { 0, NULL, "explicit ''", 0, 2, { "explicit", "", }, IFS },
Packit 6c4009
    { 0, NULL, "explicit \"\"", 0, 2, { "explicit", "", }, IFS },
Packit 6c4009
    { 0, NULL, "explicit ``", 0, 1, { "explicit", }, IFS },
Packit 6c4009
Packit 6c4009
    /* Simple command substitution */
Packit 6c4009
    { 0, NULL, "$(echo hello)", 0, 1, { "hello", }, IFS },
Packit 6c4009
    { 0, NULL, "$( (echo hello) )", 0, 1, { "hello", }, IFS },
Packit 6c4009
    { 0, NULL, "$((echo hello);(echo there))", 0, 2, { "hello", "there", }, IFS },
Packit 6c4009
    { 0, NULL, "`echo one two`", 0, 2, { "one", "two", }, IFS },
Packit 6c4009
    { 0, NULL, "$(echo ')')", 0, 1, { ")" }, IFS },
Packit 6c4009
    { 0, NULL, "$(echo hello; echo)", 0, 1, { "hello", }, IFS },
Packit 6c4009
    { 0, NULL, "a$(echo b)c", 0, 1, { "abc", }, IFS },
Packit 6c4009
Packit 6c4009
    /* Simple arithmetic expansion */
Packit 6c4009
    { 0, NULL, "$((1 + 1))", 0, 1, { "2", }, IFS },
Packit 6c4009
    { 0, NULL, "$((2-3))", 0, 1, { "-1", }, IFS },
Packit 6c4009
    { 0, NULL, "$((-1))", 0, 1, { "-1", }, IFS },
Packit 6c4009
    { 0, NULL, "$[50+20]", 0, 1, { "70", }, IFS },
Packit 6c4009
    { 0, NULL, "$(((2+3)*(4+5)))", 0, 1, { "45", }, IFS },
Packit 6c4009
    { 0, NULL, "$((010))", 0, 1, { "8" }, IFS },
Packit 6c4009
    { 0, NULL, "$((0x10))", 0, 1, { "16" }, IFS },
Packit 6c4009
    { 0, NULL, "$((010+0x10))", 0, 1, { "24" }, IFS },
Packit 6c4009
    { 0, NULL, "$((-010+0x10))", 0, 1, { "8" }, IFS },
Packit 6c4009
    { 0, NULL, "$((-0x10+010))", 0, 1, { "-8" }, IFS },
Packit 6c4009
Packit 6c4009
    /* Advanced parameter expansion */
Packit 6c4009
    { 0, NULL, "${var:-bar}", 0, 1, { "bar", }, IFS },
Packit 6c4009
    { 0, NULL, "${var-bar}", 0, 1, { "bar", }, IFS },
Packit 6c4009
    { 0, "", "${var:-bar}", 0, 1, { "bar", }, IFS },
Packit 6c4009
    { 0, "foo", "${var:-bar}", 0, 1, { "foo", }, IFS },
Packit 6c4009
    { 0, "", "${var-bar}", 0, 0, { NULL, }, IFS },
Packit 6c4009
    { 0, NULL, "${var:=bar}", 0, 1, { "bar", }, IFS },
Packit 6c4009
    { 0, NULL, "${var=bar}", 0, 1, { "bar", }, IFS },
Packit 6c4009
    { 0, "", "${var:=bar}", 0, 1, { "bar", }, IFS },
Packit 6c4009
    { 0, "foo", "${var:=bar}", 0, 1, { "foo", }, IFS },
Packit 6c4009
    { 0, "", "${var=bar}", 0, 0, { NULL, }, IFS },
Packit 6c4009
    { 0, "foo", "${var:?bar}", 0, 1, { "foo", }, IFS },
Packit 6c4009
    { 0, NULL, "${var:+bar}", 0, 0, { NULL, }, IFS },
Packit 6c4009
    { 0, NULL, "${var+bar}", 0, 0, { NULL, }, IFS },
Packit 6c4009
    { 0, "", "${var:+bar}", 0, 0, { NULL, }, IFS },
Packit 6c4009
    { 0, "foo", "${var:+bar}", 0, 1, { "bar", }, IFS },
Packit 6c4009
    { 0, "", "${var+bar}", 0, 1, { "bar", }, IFS },
Packit 6c4009
    { 0, "12345", "${#var}", 0, 1, { "5", }, IFS },
Packit 6c4009
    { 0, NULL, "${var:-'}'}", 0, 1, { "}", }, IFS },
Packit 6c4009
    { 0, NULL, "${var-}", 0, 0, { NULL }, IFS },
Packit 6c4009
Packit 6c4009
    { 0, "pizza", "${var#${var}}", 0, 0, { NULL }, IFS },
Packit 6c4009
    { 0, "pepperoni", "${var%$(echo oni)}", 0, 1, { "pepper" }, IFS },
Packit 6c4009
    { 0, "6pack", "${var#$((6))}", 0, 1, { "pack" }, IFS },
Packit 6c4009
    { 0, "b*witched", "${var##b*}", 0, 0, { NULL }, IFS },
Packit 6c4009
    { 0, "b*witched", "${var##\"b*\"}", 0, 1, { "witched" }, IFS },
Packit 6c4009
    { 0, "banana", "${var%na*}", 0, 1, { "bana", }, IFS },
Packit 6c4009
    { 0, "banana", "${var%%na*}", 0, 1, { "ba", }, IFS },
Packit 6c4009
    { 0, "borabora-island", "${var#*bora}", 0, 1, { "bora-island", }, IFS },
Packit 6c4009
    { 0, "borabora-island", "${var##*bora}", 0, 1, { "-island", }, IFS },
Packit 6c4009
    { 0, "coconut", "${var##\\*co}", 0, 1, { "coconut", }, IFS },
Packit 6c4009
    { 0, "100%", "${var%0%}", 0, 1, { "10" }, IFS },
Packit 6c4009
Packit 6c4009
    /* Pathname expansion */
Packit 6c4009
    { 0, NULL, "???", 0, 2, { "one", "two", }, IFS },
Packit 6c4009
    { 0, NULL, "[ot]??", 0, 2, { "one", "two", }, IFS },
Packit 6c4009
    { 0, NULL, "t*", 0, 2, { "three", "two", }, IFS },
Packit 6c4009
    { 0, NULL, "\"t\"*", 0, 2, { "three", "two", }, IFS },
Packit 6c4009
Packit 6c4009
    /* Nested constructs */
Packit 6c4009
    { 0, "one two", "$var", 0, 2, { "one", "two", }, IFS },
Packit 6c4009
    { 0, "one two three", "$var", 0, 3, { "one", "two", "three", }, IFS },
Packit 6c4009
    { 0, " \tfoo\t\tbar ", "$var", 0, 2, { "foo", "bar", }, IFS },
Packit 6c4009
    { 0, "  red  , white blue", "$var", 0, 3, { "red", "white", "blue", }, ", \n\t" },
Packit 6c4009
    { 0, "  red  , white blue", "\"$var\"", 0, 1, { "  red  , white blue", }, ", \n\t" },
Packit 6c4009
    { 0, NULL, "\"$(echo hello there)\"", 0, 1, { "hello there", }, IFS },
Packit 6c4009
    { 0, NULL, "\"$(echo \"hello there\")\"", 0, 1, { "hello there", }, IFS },
Packit 6c4009
    { 0, NULL, "${var=one two} \"$var\"", 0, 3, { "one", "two", "one two", }, IFS },
Packit 6c4009
    { 0, "1", "$(( $(echo 3)+$var ))", 0, 1, { "4", }, IFS },
Packit 6c4009
    { 0, NULL, "\"$(echo \"*\")\"", 0, 1, { "*", }, IFS },
Packit 6c4009
    { 0, NULL, "\"a\n\n$(echo)b\"", 0, 1, { "a\n\nb", }, IFS },
Packit 6c4009
    { 0, "foo", "*$var*", 0, 1, { "*foo*", }, IFS },
Packit 6c4009
    { 0, "o thr", "*$var*", 0, 2, { "two", "three" }, IFS },
Packit 6c4009
Packit 6c4009
    /* Different IFS values */
Packit 6c4009
    { 0, "a b\tc\nd  ", "$var", 0, 4, { "a", "b", "c", "d" }, NULL /* unset */ },
Packit 6c4009
    { 0, "a b\tc d  ", "$var", 0, 1, { "a b\tc d  " }, "" /* `null' */ },
Packit 6c4009
    { 0, "a,b c\n, d", "$var", 0, 3, { "a", "b c", " d" }, "\t\n," },
Packit 6c4009
Packit 6c4009
    /* Other things that should succeed */
Packit 6c4009
    { 0, NULL, "\\*\"|&;<>\"\\(\\)\\{\\}", 0, 1, { "*|&;<>(){}", }, IFS },
Packit 6c4009
    { 0, "???", "$var", 0, 1, { "???", }, IFS },
Packit 6c4009
    { 0, NULL, "$var", 0, 0, { NULL, }, IFS },
Packit 6c4009
    { 0, NULL, "\"\\n\"", 0, 1, { "\\n", }, IFS },
Packit 6c4009
    { 0, NULL, "", 0, 0, { NULL, }, IFS },
Packit 6c4009
Packit 6c4009
    /* Flags not already covered (testit() has special handling for these) */
Packit 6c4009
    { 0, NULL, "one two", WRDE_DOOFFS, 2, { "one", "two", }, IFS },
Packit 6c4009
    { 0, NULL, "appended", WRDE_APPEND, 3, { "pre1", "pre2", "appended", }, IFS },
Packit 6c4009
    { 0, NULL, "appended", WRDE_DOOFFS|WRDE_APPEND, 3, { "pre1", "pre2", "appended", }, IFS },
Packit 6c4009
Packit 6c4009
    /* Things that should fail */
Packit 6c4009
    { WRDE_BADCHAR, NULL, "new\nline", 0, 0, { NULL, }, "" /* \n not IFS */ },
Packit 6c4009
    { WRDE_BADCHAR, NULL, "pipe|symbol", 0, 0, { NULL, }, IFS },
Packit 6c4009
    { WRDE_BADCHAR, NULL, "&ampersand", 0, 0, { NULL, }, IFS },
Packit 6c4009
    { WRDE_BADCHAR, NULL, "semi;colon", 0, 0, { NULL, }, IFS },
Packit 6c4009
    { WRDE_BADCHAR, NULL, "
Packit 6c4009
    { WRDE_BADCHAR, NULL, "less>", 0, 0, { NULL, }, IFS },
Packit 6c4009
    { WRDE_BADCHAR, NULL, "(open-paren", 0, 0, { NULL, }, IFS },
Packit 6c4009
    { WRDE_BADCHAR, NULL, "close-paren)", 0, 0, { NULL, }, IFS },
Packit 6c4009
    { WRDE_BADCHAR, NULL, "{open-brace", 0, 0, { NULL, }, IFS },
Packit 6c4009
    { WRDE_BADCHAR, NULL, "close-brace}", 0, 0, { NULL, }, IFS },
Packit 6c4009
    { WRDE_CMDSUB, NULL, "$(ls)", WRDE_NOCMD, 0, { NULL, }, IFS },
Packit 6c4009
    { WRDE_BADVAL, NULL, "$var", WRDE_UNDEF, 0, { NULL, }, IFS },
Packit 6c4009
    { WRDE_BADVAL, NULL, "$9", WRDE_UNDEF, 0, { NULL, }, IFS },
Packit 6c4009
    { WRDE_SYNTAX, NULL, "$[50+20))", 0, 0, { NULL, }, IFS },
Packit 6c4009
    { WRDE_SYNTAX, NULL, "${%%noparam}", 0, 0, { NULL, }, IFS },
Packit 6c4009
    { WRDE_SYNTAX, NULL, "${missing-brace", 0, 0, { NULL, }, IFS },
Packit 6c4009
    { WRDE_SYNTAX, NULL, "$(for i in)", 0, 0, { NULL, }, IFS },
Packit 6c4009
    { WRDE_SYNTAX, NULL, "$((2+))", 0, 0, { NULL, }, IFS },
Packit 6c4009
    { WRDE_SYNTAX, NULL, "`", 0, 0, { NULL, }, IFS },
Packit 6c4009
    { WRDE_SYNTAX, NULL, "$((010+4+))", 0, 0, { NULL }, IFS },
Packit 6c4009
    /* Test for CVE-2014-7817. We test 3 combinations of command
Packit 6c4009
       substitution inside an arithmetic expression to make sure that
Packit 6c4009
       no commands are executed and error is returned.  */
Packit 6c4009
    { WRDE_CMDSUB, NULL, "$((`echo 1`))", WRDE_NOCMD, 0, { NULL, }, IFS },
Packit 6c4009
    { WRDE_CMDSUB, NULL, "$((1+`echo 1`))", WRDE_NOCMD, 0, { NULL, }, IFS },
Packit 6c4009
    { WRDE_CMDSUB, NULL, "$((1+$((`echo 1`))))", WRDE_NOCMD, 0, { NULL, }, IFS },
Packit 6c4009
Packit 6c4009
    { WRDE_SYNTAX, NULL, "`\\", 0, 0, { NULL, }, IFS },     /* BZ 18042  */
Packit 6c4009
    { WRDE_SYNTAX, NULL, "${", 0, 0, { NULL, }, IFS },      /* BZ 18043  */
Packit 6c4009
    { WRDE_SYNTAX, NULL, "L${a:", 0, 0, { NULL, }, IFS },   /* BZ 18043#c4  */
Packit 6c4009
    { WRDE_SYNTAX, NULL, "$[1/0]", WRDE_NOCMD, 0, {NULL, }, IFS }, /* BZ 18100 */
Packit 6c4009
Packit 6c4009
    { -1, NULL, NULL, 0, 0, { NULL, }, IFS },
Packit 6c4009
  };
Packit 6c4009
Packit 6c4009
static int testit (struct test_case_struct *tc);
Packit 6c4009
static int tests;
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
command_line_test (const char *words)
Packit 6c4009
{
Packit 6c4009
  wordexp_t we;
Packit 6c4009
  int i;
Packit 6c4009
  int retval = wordexp (words, &we, 0);
Packit 6c4009
  printf ("wordexp returned %d\n", retval);
Packit 6c4009
  for (i = 0; i < we.we_wordc; i++)
Packit 6c4009
    printf ("we_wordv[%d] = \"%s\"\n", i, we.we_wordv[i]);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
int
Packit 6c4009
main (int argc, char *argv[])
Packit 6c4009
{
Packit 6c4009
  const char *globfile[] = { "one", "two", "three", NULL };
Packit 6c4009
  char tmpdir[32];
Packit 6c4009
  struct passwd *pw;
Packit 6c4009
  const char *cwd;
Packit 6c4009
  int test;
Packit 6c4009
  int fail = 0;
Packit 6c4009
  int i;
Packit 6c4009
  struct test_case_struct ts;
Packit 6c4009
Packit 6c4009
  if (argc > 1)
Packit 6c4009
    {
Packit 6c4009
      command_line_test (argv[1]);
Packit 6c4009
      return 0;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  cwd = getcwd (NULL, 0);
Packit 6c4009
Packit 6c4009
  /* Set up arena for pathname expansion */
Packit 6c4009
  tmpnam (tmpdir);
Packit 6c4009
  if (mkdir (tmpdir, S_IRWXU) || chdir (tmpdir))
Packit 6c4009
    return -1;
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      int fd;
Packit 6c4009
Packit 6c4009
      for (i = 0; globfile[i]; ++i)
Packit 6c4009
	if ((fd = creat (globfile[i], S_IRUSR | S_IWUSR)) == -1
Packit 6c4009
	    || close (fd))
Packit 6c4009
	  return -1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* If we are not allowed to do command substitution, we install
Packit 6c4009
     fork handlers to verify that no forks happened.  No forks should
Packit 6c4009
     happen at all if command substitution is disabled.  */
Packit 6c4009
  if (__app_register_atfork (register_fork, NULL, NULL) != 0)
Packit 6c4009
    {
Packit 6c4009
      printf ("Failed to register fork handler.\n");
Packit 6c4009
      return -1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  for (test = 0; test_case[test].retval != -1; test++)
Packit 6c4009
    if (testit (&test_case[test]))
Packit 6c4009
      ++fail;
Packit 6c4009
Packit 6c4009
  /* Tilde-expansion tests. */
Packit 6c4009
  pw = getpwnam ("root");
Packit 6c4009
  if (pw != NULL)
Packit 6c4009
    {
Packit 6c4009
      ts.retval = 0;
Packit 6c4009
      ts.env = NULL;
Packit 6c4009
      ts.words = "~root ";
Packit 6c4009
      ts.flags = 0;
Packit 6c4009
      ts.wordc = 1;
Packit 6c4009
      ts.wordv[0] = pw->pw_dir;
Packit 6c4009
      ts.ifs = IFS;
Packit 6c4009
Packit 6c4009
      if (testit (&ts))
Packit 6c4009
	++fail;
Packit 6c4009
Packit 6c4009
      ts.retval = 0;
Packit 6c4009
      ts.env = pw->pw_dir;
Packit 6c4009
      ts.words = "${var#~root}x";
Packit 6c4009
      ts.flags = 0;
Packit 6c4009
      ts.wordc = 1;
Packit 6c4009
      ts.wordv[0] = "x";
Packit 6c4009
      ts.ifs = IFS;
Packit 6c4009
Packit 6c4009
      if (testit (&ts))
Packit 6c4009
	++fail;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* "~" expands to value of $HOME when HOME is set */
Packit 6c4009
Packit 6c4009
  setenv ("HOME", "/dummy/home", 1);
Packit 6c4009
  ts.retval = 0;
Packit 6c4009
  ts.env = NULL;
Packit 6c4009
  ts.words = "~ ~/foo";
Packit 6c4009
  ts.flags = 0;
Packit 6c4009
  ts.wordc = 2;
Packit 6c4009
  ts.wordv[0] = "/dummy/home";
Packit 6c4009
  ts.wordv[1] = "/dummy/home/foo";
Packit 6c4009
  ts.ifs = IFS;
Packit 6c4009
Packit 6c4009
  if (testit (&ts))
Packit 6c4009
    ++fail;
Packit 6c4009
Packit 6c4009
  /* "~" expands to home dir from passwd file if HOME is not set */
Packit 6c4009
Packit 6c4009
  pw = getpwuid (getuid ());
Packit 6c4009
  if (pw != NULL)
Packit 6c4009
    {
Packit 6c4009
      unsetenv ("HOME");
Packit 6c4009
      ts.retval = 0;
Packit 6c4009
      ts.env = NULL;
Packit 6c4009
      ts.words = "~";
Packit 6c4009
      ts.flags = 0;
Packit 6c4009
      ts.wordc = 1;
Packit 6c4009
      ts.wordv[0] = pw->pw_dir;
Packit 6c4009
      ts.ifs = IFS;
Packit 6c4009
Packit 6c4009
      if (testit (&ts))
Packit 6c4009
	++fail;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Integer overflow in division.  */
Packit 6c4009
  {
Packit 6c4009
    static const char *const numbers[] = {
Packit 6c4009
      "0",
Packit 6c4009
      "1",
Packit 6c4009
      "65536",
Packit 6c4009
      "2147483648",
Packit 6c4009
      "4294967296"
Packit 6c4009
      "9223372036854775808",
Packit 6c4009
      "18446744073709551616",
Packit 6c4009
      "170141183460469231731687303715884105728",
Packit 6c4009
      "340282366920938463463374607431768211456",
Packit 6c4009
      NULL
Packit 6c4009
    };
Packit 6c4009
Packit 6c4009
    for (const char *const *num = numbers; *num; ++num)
Packit 6c4009
      {
Packit 6c4009
	wordexp_t p;
Packit 6c4009
	char pattern[256];
Packit 6c4009
	snprintf (pattern, sizeof (pattern), "$[(-%s)/(-1)]", *num);
Packit 6c4009
	int ret = wordexp (pattern, &p, WRDE_NOCMD);
Packit 6c4009
	if (ret == 0)
Packit 6c4009
	  {
Packit 6c4009
	    if (p.we_wordc != 1 || strcmp (p.we_wordv[0], *num) != 0)
Packit 6c4009
	      {
Packit 6c4009
		printf ("Integer overflow for \"%s\" failed", pattern);
Packit 6c4009
		++fail;
Packit 6c4009
	      }
Packit 6c4009
	    wordfree (&p);
Packit 6c4009
	  }
Packit 6c4009
	else if (ret != WRDE_SYNTAX)
Packit 6c4009
	  {
Packit 6c4009
	    printf ("Integer overflow for \"%s\" failed with %d",
Packit 6c4009
		    pattern, ret);
Packit 6c4009
	    ++fail;
Packit 6c4009
	  }
Packit 6c4009
      }
Packit 6c4009
  }
Packit 6c4009
Packit 6c4009
  puts ("tests completed, now cleaning up");
Packit 6c4009
Packit 6c4009
  /* Clean up */
Packit 6c4009
  for (i = 0; globfile[i]; ++i)
Packit 6c4009
    remove (globfile[i]);
Packit 6c4009
Packit 6c4009
  if (cwd == NULL)
Packit 6c4009
    cwd = "..";
Packit 6c4009
Packit 6c4009
  chdir (cwd);
Packit 6c4009
  rmdir (tmpdir);
Packit 6c4009
Packit 6c4009
  printf ("tests failed: %d\n", fail);
Packit 6c4009
Packit 6c4009
  return fail != 0;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static const char *
Packit 6c4009
at_page_end (const char *words)
Packit 6c4009
{
Packit 6c4009
  const int pagesize = getpagesize ();
Packit 6c4009
  char *start = mmap (0, 2 * pagesize, PROT_READ|PROT_WRITE,
Packit 6c4009
		      MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
Packit 6c4009
Packit 6c4009
  if (start == MAP_FAILED)
Packit 6c4009
    return start;
Packit 6c4009
Packit 6c4009
  if (mprotect (start + pagesize, pagesize, PROT_NONE))
Packit 6c4009
    {
Packit 6c4009
      munmap (start, 2 * pagesize);
Packit 6c4009
      return MAP_FAILED;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Includes terminating NUL.  */
Packit 6c4009
  const size_t words_size = strlen (words) + 1;
Packit 6c4009
  char *words_start = start + pagesize - words_size;
Packit 6c4009
  memcpy (words_start, words, words_size);
Packit 6c4009
Packit 6c4009
  return words_start;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
testit (struct test_case_struct *tc)
Packit 6c4009
{
Packit 6c4009
  int retval;
Packit 6c4009
  wordexp_t we, sav_we;
Packit 6c4009
  char *dummy;
Packit 6c4009
  int bzzzt = 0;
Packit 6c4009
  int start_offs = 0;
Packit 6c4009
  int i;
Packit 6c4009
Packit 6c4009
  if (tc->env)
Packit 6c4009
    setenv ("var", tc->env, 1);
Packit 6c4009
  else
Packit 6c4009
    unsetenv ("var");
Packit 6c4009
Packit 6c4009
  if (tc->ifs)
Packit 6c4009
    setenv ("IFS", tc->ifs, 1);
Packit 6c4009
  else
Packit 6c4009
    unsetenv ("IFS");
Packit 6c4009
Packit 6c4009
  sav_we.we_wordc = 99;
Packit 6c4009
  sav_we.we_wordv = &dummy;
Packit 6c4009
  sav_we.we_offs = 3;
Packit 6c4009
  we = sav_we;
Packit 6c4009
Packit 6c4009
  printf ("Test %d (%s): ", ++tests, tc->words);
Packit 6c4009
  fflush (NULL);
Packit 6c4009
  const char *words = at_page_end (tc->words);
Packit 6c4009
Packit 6c4009
  if (tc->flags & WRDE_NOCMD)
Packit 6c4009
    registered_forks = 0;
Packit 6c4009
Packit 6c4009
  if (tc->flags & WRDE_APPEND)
Packit 6c4009
    {
Packit 6c4009
      /* initial wordexp() call, to be appended to */
Packit 6c4009
      if (wordexp ("pre1 pre2", &we, tc->flags & ~WRDE_APPEND) != 0)
Packit 6c4009
        {
Packit 6c4009
	  printf ("FAILED setup\n");
Packit 6c4009
	  return 1;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
  retval = wordexp (words, &we, tc->flags);
Packit 6c4009
Packit 6c4009
  if ((tc->flags & WRDE_NOCMD)
Packit 6c4009
      && (registered_forks > 0))
Packit 6c4009
    {
Packit 6c4009
	  printf ("FAILED fork called for WRDE_NOCMD\n");
Packit 6c4009
	  return 1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (tc->flags & WRDE_DOOFFS)
Packit 6c4009
      start_offs = sav_we.we_offs;
Packit 6c4009
Packit 6c4009
  if (retval != tc->retval || (retval == 0 && we.we_wordc != tc->wordc))
Packit 6c4009
    bzzzt = 1;
Packit 6c4009
  else if (retval == 0)
Packit 6c4009
    {
Packit 6c4009
      for (i = 0; i < start_offs; ++i)
Packit 6c4009
	if (we.we_wordv[i] != NULL)
Packit 6c4009
	  {
Packit 6c4009
	    bzzzt = 1;
Packit 6c4009
	    break;
Packit 6c4009
	  }
Packit 6c4009
Packit 6c4009
      for (i = 0; i < we.we_wordc; ++i)
Packit 6c4009
	if (we.we_wordv[i+start_offs] == NULL ||
Packit 6c4009
	    strcmp (tc->wordv[i], we.we_wordv[i+start_offs]) != 0)
Packit 6c4009
	  {
Packit 6c4009
	    bzzzt = 1;
Packit 6c4009
	    break;
Packit 6c4009
	  }
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (bzzzt)
Packit 6c4009
    {
Packit 6c4009
      printf ("FAILED\n");
Packit 6c4009
      printf ("Test words: <%s>, need retval %d, wordc %Zd\n",
Packit 6c4009
	      tc->words, tc->retval, tc->wordc);
Packit 6c4009
      if (start_offs != 0)
Packit 6c4009
	printf ("(preceded by %d NULLs)\n", start_offs);
Packit 6c4009
      printf ("Got retval %d, wordc %Zd: ", retval, we.we_wordc);
Packit 6c4009
      if (retval == 0 || retval == WRDE_NOSPACE)
Packit 6c4009
	{
Packit 6c4009
	  for (i = 0; i < we.we_wordc + start_offs; ++i)
Packit 6c4009
	    if (we.we_wordv[i] == NULL)
Packit 6c4009
	      printf ("NULL ");
Packit 6c4009
	    else
Packit 6c4009
	      printf ("<%s> ", we.we_wordv[i]);
Packit 6c4009
	}
Packit 6c4009
      printf ("\n");
Packit 6c4009
    }
Packit 6c4009
  else if (retval != 0 && retval != WRDE_NOSPACE &&
Packit 6c4009
	   (we.we_wordc != sav_we.we_wordc ||
Packit 6c4009
            we.we_wordv != sav_we.we_wordv ||
Packit 6c4009
            we.we_offs != sav_we.we_offs))
Packit 6c4009
    {
Packit 6c4009
      bzzzt = 1;
Packit 6c4009
      printf ("FAILED to restore wordexp_t members\n");
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    printf ("OK\n");
Packit 6c4009
Packit 6c4009
  if (retval == 0 || retval == WRDE_NOSPACE)
Packit 6c4009
    wordfree (&we);
Packit 6c4009
Packit 6c4009
  const int page_size = getpagesize ();
Packit 6c4009
  char *start = (char *) PTR_ALIGN_DOWN (words, page_size);
Packit 6c4009
Packit 6c4009
  if (munmap (start, 2 * page_size) != 0)
Packit 6c4009
    return 1;
Packit 6c4009
Packit 6c4009
  fflush (NULL);
Packit 6c4009
  return bzzzt;
Packit 6c4009
}