summaryrefslogtreecommitdiff
path: root/tests/util
diff options
context:
space:
mode:
authorRuss Allbery <rra@stanford.edu>2007-10-04 22:21:19 +0000
committerRuss Allbery <rra@stanford.edu>2007-10-04 22:21:19 +0000
commit9ff667addf39128f43d08d4ec56a6a94ec3bb062 (patch)
tree41cd39045fb2d37d343608af57aebf844ecd5690 /tests/util
parent2f9387bdf0e047bbd193532c4fed209acabd0e7a (diff)
Initial import of a C portability framework and utility functions from
remctl so that the wallet client error handling can rest on a firmer foundation.
Diffstat (limited to 'tests/util')
-rw-r--r--tests/util/concat-t.c54
-rw-r--r--tests/util/messages-t.c278
-rw-r--r--tests/util/xmalloc-t.in107
-rw-r--r--tests/util/xmalloc.c294
4 files changed, 733 insertions, 0 deletions
diff --git a/tests/util/concat-t.c b/tests/util/concat-t.c
new file mode 100644
index 0000000..c18cd19
--- /dev/null
+++ b/tests/util/concat-t.c
@@ -0,0 +1,54 @@
+/* $Id$ */
+/* concat test suite. */
+
+/* Copyright (c) 2004, 2005, 2006
+ by Internet Systems Consortium, Inc. ("ISC")
+ Copyright (c) 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
+ 2002, 2003 by The Internet Software Consortium and Rich Salz
+
+ This code is derived from software contributed to the Internet Software
+ Consortium by Rich Salz.
+
+ Permission to use, copy, modify, and distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY
+ SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <config.h>
+#include <system.h>
+
+#include <tests/libtest.h>
+#include <util/util.h>
+
+#define END (char *) 0
+
+/* Memory leaks everywhere! Whoo-hoo! */
+int
+main(void)
+{
+ test_init(13);
+
+ ok_string( 1, "a", concat("a", END));
+ ok_string( 2, "ab", concat("a", "b", END));
+ ok_string( 3, "ab", concat("ab", "", END));
+ ok_string( 4, "ab", concat("", "ab", END));
+ ok_string( 5, "", concat("", END));
+ ok_string( 6, "abcde", concat("ab", "c", "", "de", END));
+ ok_string( 7, "abcde", concat("abc", "de", END, "f", END));
+
+ ok_string( 8, "/foo", concatpath("/bar", "/foo"));
+ ok_string( 9, "/foo/bar", concatpath("/foo", "bar"));
+ ok_string(10, "./bar", concatpath("/foo", "./bar"));
+ ok_string(11, "/bar/baz/foo/bar", concatpath("/bar/baz", "foo/bar"));
+ ok_string(12, "./foo", concatpath(NULL, "foo"));
+ ok_string(13, "/foo/bar", concatpath(NULL, "/foo/bar"));
+
+ return 0;
+}
diff --git a/tests/util/messages-t.c b/tests/util/messages-t.c
new file mode 100644
index 0000000..ef58737
--- /dev/null
+++ b/tests/util/messages-t.c
@@ -0,0 +1,278 @@
+/* $Id$ */
+/* Test suite for error handling routines. */
+
+/* Copyright (c) 2004, 2005, 2006
+ by Internet Systems Consortium, Inc. ("ISC")
+ Copyright (c) 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
+ 2002, 2003 by The Internet Software Consortium and Rich Salz
+
+ This code is derived from software contributed to the Internet Software
+ Consortium by Rich Salz.
+
+ Permission to use, copy, modify, and distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY
+ SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <config.h>
+#include <system.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#include <tests/libtest.h>
+#include <util/util.h>
+
+#define END (char *) 0
+
+/* Test function type. */
+typedef void (*test_function_t)(void);
+
+/* Fork and execute the provided function, connecting stdout and stderr to a
+ pipe. Captures the output into the provided buffer and returns the exit
+ status as a waitpid status value. */
+static int
+run_test(test_function_t function, char *buf, size_t buflen)
+{
+ int fds[2];
+ pid_t child;
+ ssize_t count, status;
+ int rval;
+
+ /* Flush stdout before we start to avoid odd forking issues. */
+ fflush(stdout);
+
+ /* Set up the pipe and call the function, collecting its output. */
+ if (pipe(fds) == -1)
+ sysdie("can't create pipe");
+ child = fork();
+ if (child == (pid_t) -1) {
+ sysdie("can't fork");
+ } else if (child == 0) {
+ /* In child. Set up our stdout and stderr. */
+ close(fds[0]);
+ if (dup2(fds[1], 1) == -1)
+ _exit(255);
+ if (dup2(fds[1], 2) == -1)
+ _exit(255);
+
+ /* Now, run the function and exit successfully if it returns. */
+ (*function)();
+ fflush(stdout);
+ _exit(0);
+ } else {
+ /* In the parent; close the extra file descriptor, read the output
+ if any, and then collect the exit status. */
+ close(fds[1]);
+ count = 0;
+ do {
+ status = read(fds[0], buf + count, buflen - count - 1);
+ if (status > 0)
+ count += status;
+ } while (status > 0);
+ buf[count < 0 ? 0 : count] = '\0';
+ if (waitpid(child, &rval, 0) == (pid_t) -1)
+ sysdie("waitpid failed");
+ }
+ return rval;
+}
+
+/* Test functions. */
+static void test1(void) { warn("warning"); }
+static void test2(void) { die("fatal"); }
+static void test3(void) { errno = EPERM; syswarn("permissions"); }
+static void test4(void) { errno = EACCES; sysdie("fatal access"); }
+static void test5(void) {
+ message_program_name = "test5";
+ warn("warning");
+}
+static void test6(void) {
+ message_program_name = "test6";
+ die("fatal");
+}
+static void test7(void) {
+ message_program_name = "test7";
+ errno = EPERM;
+ syswarn("perms %d", 7);
+}
+static void test8(void) {
+ message_program_name = "test8";
+ errno = EACCES;
+ sysdie("%st%s", "fa", "al");
+}
+
+static int return10(void) { return 10; }
+
+static void test9(void) {
+ message_fatal_cleanup = return10;
+ die("fatal");
+}
+static void test10(void) {
+ message_program_name = 0;
+ message_fatal_cleanup = return10;
+ errno = EPERM;
+ sysdie("fatal perm");
+}
+static void test11(void) {
+ message_program_name = "test11";
+ message_fatal_cleanup = return10;
+ errno = EPERM;
+ fputs("1st ", stdout);
+ sysdie("fatal");
+}
+
+static void log_msg(int len, const char *format, va_list args, int error) {
+ fprintf(stderr, "%d %d ", len, error);
+ vfprintf(stderr, format, args);
+ fprintf(stderr, "\n");
+}
+
+static void test12(void) {
+ message_handlers_warn(1, log_msg);
+ warn("warning");
+}
+static void test13(void) {
+ message_handlers_die(1, log_msg);
+ die("fatal");
+}
+static void test14(void) {
+ message_handlers_warn(2, log_msg, log_msg);
+ errno = EPERM;
+ syswarn("warning");
+}
+static void test15(void) {
+ message_handlers_die(2, log_msg, log_msg);
+ message_fatal_cleanup = return10;
+ errno = EPERM;
+ sysdie("fatal");
+}
+static void test16(void) {
+ message_handlers_warn(2, message_log_stderr, log_msg);
+ message_program_name = "test16";
+ errno = EPERM;
+ syswarn("warning");
+}
+static void test17(void) { notice("notice"); }
+static void test18(void) {
+ message_program_name = "test18";
+ notice("notice");
+}
+static void test19(void) { debug("debug"); }
+static void test20(void) {
+ message_handlers_notice(1, log_msg);
+ notice("foo");
+}
+static void test21(void) {
+ message_handlers_debug(1, message_log_stdout);
+ message_program_name = "test23";
+ debug("baz");
+}
+static void test22(void) {
+ message_handlers_die(0);
+ die("hi mom!");
+}
+static void test23(void) {
+ message_handlers_warn(0);
+ warn("this is a test");
+}
+static void test24(void) {
+ notice("first");
+ message_handlers_notice(0);
+ notice("second");
+ message_handlers_notice(1, message_log_stdout);
+ notice("third");
+}
+
+/* Given the test number, intended exit status and message, and the function
+ to run, print ok or not ok. */
+static void
+test_error(int n, int status, const char *output, test_function_t function)
+{
+ int real_status;
+ char buf[256];
+ int succeeded = 1;
+
+ real_status = run_test(function, buf, sizeof(buf));
+ if (!WIFEXITED(real_status) || status != WEXITSTATUS(real_status)) {
+ printf(" unexpected exit status %d\n", real_status);
+ succeeded = 0;
+ }
+ if (strcmp(output, buf)) {
+ printf(" unexpected output: %s", buf);
+ printf(" expected output: %s", output);
+ succeeded = 0;
+ }
+ printf("%sok %d\n", succeeded ? "" : "not ", n);
+}
+
+/* Given the test number, intended status, intended message sans the
+ appended strerror output, errno, and the function to run, print ok or not
+ ok. */
+static void
+test_strerror(int n, int status, const char *output, int error,
+ test_function_t function)
+{
+ char *full_output;
+
+ full_output = concat(output, ": ", strerror(error), "\n", END);
+ test_error(n, status, full_output, function);
+ free(full_output);
+}
+
+/* Run the tests. */
+int
+main(void)
+{
+ char buff[32];
+
+ test_init(24);
+
+ test_error(1, 0, "warning\n", test1);
+ test_error(2, 1, "fatal\n", test2);
+ test_strerror(3, 0, "permissions", EPERM, test3);
+ test_strerror(4, 1, "fatal access", EACCES, test4);
+ test_error(5, 0, "test5: warning\n", test5);
+ test_error(6, 1, "test6: fatal\n", test6);
+ test_strerror(7, 0, "test7: perms 7", EPERM, test7);
+ test_strerror(8, 1, "test8: fatal", EACCES, test8);
+ test_error(9, 10, "fatal\n", test9);
+ test_strerror(10, 10, "fatal perm", EPERM, test10);
+ test_strerror(11, 10, "1st test11: fatal", EPERM, test11);
+ test_error(12, 0, "7 0 warning\n", test12);
+ test_error(13, 1, "5 0 fatal\n", test13);
+
+ sprintf(buff, "%d", EPERM);
+
+ test_error(14, 0,
+ concat("7 ", buff, " warning\n7 ", buff, " warning\n", END),
+ test14);
+ test_error(15, 10,
+ concat("5 ", buff, " fatal\n5 ", buff, " fatal\n", END),
+ test15);
+ test_error(16, 0,
+ concat("test16: warning: ", strerror(EPERM), "\n7 ", buff,
+ " warning\n", END),
+ test16);
+
+ test_error(17, 0, "notice\n", test17);
+ test_error(18, 0, "test18: notice\n", test18);
+ test_error(19, 0, "", test19);
+ test_error(20, 0, "3 0 foo\n", test20);
+ test_error(21, 0, "test23: baz\n", test21);
+
+ /* Make sure that it's possible to turn off a message type entirely. */
+ test_error(22, 1, "", test22);
+ test_error(23, 0, "", test23);
+ test_error(24, 0, "first\nthird\n", test24);
+
+ return 0;
+}
diff --git a/tests/util/xmalloc-t.in b/tests/util/xmalloc-t.in
new file mode 100644
index 0000000..e4e971d
--- /dev/null
+++ b/tests/util/xmalloc-t.in
@@ -0,0 +1,107 @@
+#! /bin/sh
+# $Id$
+#
+# Test suite for xmalloc and friends.
+
+# The count starts at 1 and is updated each time ok is printed. printcount
+# takes "ok" or "not ok".
+count=1
+printcount () {
+ echo "$1 $count $2"
+ count=`expr $count + 1`
+}
+
+# Run a program expected to succeed, and print ok if it does.
+runsuccess () {
+ output=`$xmalloc "$1" "$2" "$3" 2>&1 >/dev/null`
+ status=$?
+ if test $status = 0 && test -z "$output" ; then
+ printcount "ok"
+ else
+ if test $status = 2 ; then
+ printcount "ok" "# skip no data limit support"
+ else
+ printcount "not ok"
+ echo " $output"
+ fi
+ fi
+}
+
+# Run a program expected to fail and make sure it fails with an exit status
+# of 2 and the right failure message. Strip the colon and everything after
+# it off the error message since it's system-specific.
+runfailure () {
+ output=`$xmalloc "$1" "$2" "$3" 2>&1 >/dev/null`
+ status=$?
+ output=`echo "$output" | sed 's/:.*//' \
+ | sed 's% [^ ]*/xmalloc.c% xmalloc.c%'`
+ if test $status = 1 && test x"$output" = x"$4" ; then
+ printcount "ok"
+ else
+ if test $status = 2 ; then
+ printcount "ok" "# skip no data limit support"
+ else
+ printcount "not ok"
+ echo " saw: $output"
+ echo " not: $4"
+ fi
+ fi
+}
+
+# Find where the helper program is.
+xmalloc="@abs_top_builddir@/tests/util/xmalloc"
+
+# Total tests.
+echo 36
+
+# First run the tests expected to succeed.
+runsuccess "m" "21" "0"
+runsuccess "m" "128000" "0"
+runsuccess "m" "0" "0"
+runsuccess "r" "21" "0"
+runsuccess "r" "128000" "0"
+runsuccess "s" "21" "0"
+runsuccess "s" "128000" "0"
+runsuccess "n" "21" "0"
+runsuccess "n" "128000" "0"
+runsuccess "c" "24" "0"
+runsuccess "c" "128000" "0"
+runsuccess "a" "24" "0"
+runsuccess "a" "128000" "0"
+runsuccess "v" "24" "0"
+runsuccess "v" "128000" "0"
+
+# Now limit our memory to 120KB and then try the large ones again, all of
+# which should fail.
+runfailure "m" "128000" "120000" \
+ "failed to malloc 128000 bytes at xmalloc.c line 54"
+runfailure "r" "128000" "120000" \
+ "failed to realloc 128000 bytes at xmalloc.c line 80"
+runfailure "s" "64000" "120000" \
+ "failed to strdup 64000 bytes at xmalloc.c line 109"
+runfailure "n" "64000" "120000" \
+ "failed to strndup 64000 bytes at xmalloc.c line 133"
+runfailure "c" "128000" "120000" \
+ "failed to calloc 128000 bytes at xmalloc.c line 155"
+runfailure "a" "64000" "120000" \
+ "failed to asprintf 64000 bytes at xmalloc.c line 177"
+runfailure "v" "64000" "120000" \
+ "failed to vasprintf 64000 bytes at xmalloc.c line 196"
+
+# Check our custom error handler.
+runfailure "M" "128000" "120000" "malloc 128000 xmalloc.c 54"
+runfailure "R" "128000" "120000" "realloc 128000 xmalloc.c 80"
+runfailure "S" "64000" "120000" "strdup 64000 xmalloc.c 109"
+runfailure "N" "64000" "120000" "strndup 64000 xmalloc.c 133"
+runfailure "C" "128000" "120000" "calloc 128000 xmalloc.c 155"
+runfailure "A" "64000" "120000" "asprintf 64000 xmalloc.c 177"
+runfailure "V" "64000" "120000" "vasprintf 64000 xmalloc.c 196"
+
+# Check the smaller ones again just for grins.
+runsuccess "m" "21" "96000"
+runsuccess "r" "32" "96000"
+runsuccess "s" "64" "96000"
+runsuccess "n" "20" "96000"
+runsuccess "c" "24" "96000"
+runsuccess "a" "30" "96000"
+runsuccess "v" "35" "96000"
diff --git a/tests/util/xmalloc.c b/tests/util/xmalloc.c
new file mode 100644
index 0000000..4327681
--- /dev/null
+++ b/tests/util/xmalloc.c
@@ -0,0 +1,294 @@
+/* $Id$ */
+/* Test suite for xmalloc and family. */
+
+/* Copyright (c) 2004, 2005, 2006
+ by Internet Systems Consortium, Inc. ("ISC")
+ Copyright (c) 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
+ 2002, 2003 by The Internet Software Consortium and Rich Salz
+
+ This code is derived from software contributed to the Internet Software
+ Consortium by Rich Salz.
+
+ Permission to use, copy, modify, and distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY
+ SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <config.h>
+#include <system.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+/* Linux requires sys/time.h be included before sys/resource.h. */
+#include <sys/resource.h>
+
+#include <util/util.h>
+
+/* A customized error handler for checking xmalloc's support of them.
+ Prints out the error message and exits with status 1. */
+static void
+test_handler(const char *function, size_t size, const char *file, int line)
+{
+ die("%s %lu %s %d", function, (unsigned long) size, file, line);
+}
+
+/* Allocate the amount of memory given and write to all of it to make sure
+ we can, returning true if that succeeded and false on any sort of
+ detectable error. */
+static int
+test_malloc(size_t size)
+{
+ char *buffer;
+ size_t i;
+
+ buffer = xmalloc(size);
+ if (buffer == NULL)
+ return 0;
+ if (size > 0)
+ memset(buffer, 1, size);
+ for (i = 0; i < size; i++)
+ if (buffer[i] != 1)
+ return 0;
+ free(buffer);
+ return 1;
+}
+
+/* Allocate half the memory given, write to it, then reallocate to the
+ desired size, writing to the rest and then checking it all. Returns true
+ on success, false on any failure. */
+static int
+test_realloc(size_t size)
+{
+ char *buffer;
+ size_t i;
+
+ buffer = xmalloc(size / 2);
+ if (buffer == NULL)
+ return 0;
+ if (size / 2 > 0)
+ memset(buffer, 1, size / 2);
+ buffer = xrealloc(buffer, size);
+ if (buffer == NULL)
+ return 0;
+ if (size > 0)
+ memset(buffer + size / 2, 2, size - size / 2);
+ for (i = 0; i < size / 2; i++)
+ if (buffer[i] != 1)
+ return 0;
+ for (i = size / 2; i < size; i++)
+ if (buffer[i] != 2)
+ return 0;
+ free(buffer);
+ return 1;
+}
+
+/* Generate a string of the size indicated, call xstrdup on it, and then
+ ensure the result matches. Returns true on success, false on any
+ failure. */
+static int
+test_strdup(size_t size)
+{
+ char *string, *copy;
+ int match;
+
+ string = xmalloc(size);
+ if (string == NULL)
+ return 0;
+ memset(string, 1, size - 1);
+ string[size - 1] = '\0';
+ copy = xstrdup(string);
+ if (copy == NULL)
+ return 0;
+ match = strcmp(string, copy);
+ free(string);
+ free(copy);
+ return (match == 0);
+}
+
+/* Generate a string of the size indicated plus some, call xstrndup on it, and
+ then ensure the result matches. Returns true on success, false on any
+ failure. */
+static int
+test_strndup(size_t size)
+{
+ char *string, *copy;
+ int match, toomuch;
+
+ string = xmalloc(size + 1);
+ if (string == NULL)
+ return 0;
+ memset(string, 1, size - 1);
+ string[size - 1] = 2;
+ string[size] = '\0';
+ copy = xstrndup(string, size - 1);
+ if (copy == NULL)
+ return 0;
+ match = strncmp(string, copy, size - 1);
+ toomuch = strcmp(string, copy);
+ free(string);
+ free(copy);
+ return (match == 0 && toomuch != 0);
+}
+
+/* Allocate the amount of memory given and check that it's all zeroed,
+ returning true if that succeeded and false on any sort of detectable
+ error. */
+static int
+test_calloc(size_t size)
+{
+ char *buffer;
+ size_t i, nelems;
+
+ nelems = size / 4;
+ if (nelems * 4 != size)
+ return 0;
+ buffer = xcalloc(nelems, 4);
+ if (buffer == NULL)
+ return 0;
+ for (i = 0; i < size; i++)
+ if (buffer[i] != 0)
+ return 0;
+ free(buffer);
+ return 1;
+}
+
+/* Test asprintf with a large string (essentially using it as strdup).
+ Returns true if successful, false otherwise. */
+static int
+test_asprintf(size_t size)
+{
+ char *copy, *string;
+ int status;
+ size_t i;
+
+ string = xmalloc(size);
+ memset(string, 42, size - 1);
+ string[size - 1] = '\0';
+ status = xasprintf(&copy, "%s", string);
+ free(string);
+ for (i = 0; i < size - 1; i++)
+ if (copy[i] != 42)
+ return 0;
+ if (copy[size - 1] != '\0')
+ return 0;
+ free(copy);
+ return 1;
+}
+
+/* Wrapper around vasprintf to do the va_list stuff. */
+static int
+xvasprintf_wrapper(char **strp, const char *format, ...)
+{
+ va_list args;
+ int status;
+
+ va_start(args, format);
+ status = xvasprintf(strp, format, args);
+ va_end(args);
+ return status;
+}
+
+/* Test vasprintf with a large string (essentially using it as strdup).
+ Returns true if successful, false otherwise. */
+static int
+test_vasprintf(size_t size)
+{
+ char *copy, *string;
+ int status;
+ size_t i;
+
+ string = xmalloc(size);
+ memset(string, 42, size - 1);
+ string[size - 1] = '\0';
+ status = xvasprintf_wrapper(&copy, "%s", string);
+ free(string);
+ for (i = 0; i < size - 1; i++)
+ if (copy[i] != 42)
+ return 0;
+ if (copy[size - 1] != '\0')
+ return 0;
+ free(copy);
+ return 1;
+}
+
+/* Take the amount of memory to allocate in bytes as a command-line argument
+ and call test_malloc with that amount of memory. */
+int
+main(int argc, char *argv[])
+{
+ size_t size, max;
+ size_t limit = 0;
+ int willfail = 0;
+ unsigned char code;
+ struct rlimit rl;
+
+ if (argc < 3)
+ die("Usage error. Type, size, and limit must be given.");
+ errno = 0;
+ size = strtol(argv[2], 0, 10);
+ if (size == 0 && errno != 0)
+ sysdie("Invalid size");
+ errno = 0;
+ limit = strtol(argv[3], 0, 10);
+ if (limit == 0 && errno != 0)
+ sysdie("Invalid limit");
+
+ /* If a memory limit was given and we can set memory limits, set it.
+ Otherwise, exit 2, signalling to the driver that the test should be
+ skipped. We do this here rather than in the driver due to some
+ pathological problems with Linux (setting ulimit in the shell caused
+ the shell to die). */
+ if (limit > 0) {
+#if HAVE_SETRLIMIT && defined(RLIMIT_DATA)
+ rl.rlim_cur = limit;
+ rl.rlim_max = limit;
+ if (setrlimit(RLIMIT_DATA, &rl) < 0) {
+ syswarn("Can't set data limit to %lu", (unsigned long) limit);
+ exit(2);
+ }
+#else
+ warn("Data limits aren't supported.");
+ exit(2);
+#endif
+ }
+
+ /* If the code is capitalized, install our customized error handler. */
+ code = argv[1][0];
+ if (isupper(code)) {
+ xmalloc_error_handler = test_handler;
+ code = tolower(code);
+ }
+
+ /* Decide if the allocation should fail. If it should, set willfail to
+ 2, so that if it unexpectedly succeeds, we exit with a status
+ indicating that the test should be skipped. */
+ max = size;
+ if (code == 's' || code == 'n' || code == 'a' || code == 'v')
+ max *= 2;
+ if (limit > 0 && max > limit)
+ willfail = 2;
+
+ switch (code) {
+ case 'c': exit(test_calloc(size) ? willfail : 1);
+ case 'm': exit(test_malloc(size) ? willfail : 1);
+ case 'r': exit(test_realloc(size) ? willfail : 1);
+ case 's': exit(test_strdup(size) ? willfail : 1);
+ case 'n': exit(test_strndup(size) ? willfail : 1);
+ case 'a': exit(test_asprintf(size) ? willfail : 1);
+ case 'v': exit(test_vasprintf(size) ? willfail : 1);
+ default:
+ die("Unknown mode %c", argv[1][0]);
+ break;
+ }
+ exit(1);
+}