xref: /openbsd-src/regress/lib/libc/strlcat/strlcattest.c (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
1 /*	$OpenBSD: strlcattest.c,v 1.2 2014/12/03 18:25:18 millert Exp $ */
2 
3 /*
4  * Copyright (c) 2014 Todd C. Miller <Todd.Miller@courtesan.com>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/types.h>
20 
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <setjmp.h>
25 #include <signal.h>
26 #include <unistd.h>
27 
28 volatile sig_atomic_t got_signal;
29 sigjmp_buf jmpenv;
30 
31 void
32 handler(int signo)
33 {
34         got_signal = signo;
35 	siglongjmp(jmpenv, 1);
36 }
37 
38 int
39 main(int argc, char *argv[])
40 {
41 	char *buf, *cp, *ep;
42 	struct sigaction sa;
43 	size_t len, bufsize;
44 	int failures = 0;
45 
46 	/* Enable malloc security options. */
47 	setenv("MALLOC_OPTIONS", "S", 0);
48 
49 	bufsize = getpagesize(); /* trigger guard pages easily */
50 	buf = malloc(bufsize);
51 	if (buf == NULL) {
52 		fprintf(stderr, "unable to allocate memory\n");
53 		return 1;
54 	}
55 	memset(buf, 'z', bufsize);
56 	ep = buf + bufsize;
57 
58 	/* Test appending to an unterminated string. */
59 	len = strlcat(buf, "abcd", bufsize);
60 	if (len != 4 + bufsize) {
61 		fprintf(stderr,
62 		    "strlcat: failed unterminated buffer test (1a)\n");
63 		failures++;
64 	}
65 	/* Make sure we only wrote where expected. */
66 	for (cp = buf; cp < ep; cp++) {
67 		if (*cp != 'z') {
68 			fprintf(stderr,
69 			    "strlcat: failed unterminated buffer test (1b)\n");
70 			failures++;
71 			break;
72 		}
73 	}
74 
75 	/* Test appending to a full string. */
76 	ep[-1] = '\0';
77 	len = strlcat(buf, "abcd", bufsize);
78 	if (len != 4 + bufsize - 1) {
79 		fprintf(stderr, "strlcat: failed full buffer test (2a)\n");
80 		failures++;
81 	}
82 	/* Make sure we only wrote where expected. */
83 	for (cp = buf; cp < ep - 1; cp++) {
84 		if (*cp != 'z') {
85 			fprintf(stderr,
86 			    "strlcat: failed full buffer test (2b)\n");
87 			failures++;
88 			break;
89 		}
90 	}
91 
92 	/* Test appending to an empty string. */
93 	ep[-1] = 'z';
94 	buf[0] = '\0';
95 	len = strlcat(buf, "abcd", bufsize);
96 	if (len != 4) {
97 		fprintf(stderr, "strlcat: failed empty buffer test (3a)\n");
98 		failures++;
99 	}
100 	/* Make sure we only wrote where expected. */
101 	if (memcmp(buf, "abcd", sizeof("abcd")) != 0) {
102 		fprintf(stderr, "strlcat: failed empty buffer test (3b)\n");
103 		failures++;
104 	}
105 	for (cp = buf + len + 1; cp < ep; cp++) {
106 		if (*cp != 'z') {
107 			fprintf(stderr,
108 			    "strlcat: failed empty buffer test (3c)\n");
109 			failures++;
110 			break;
111 		}
112 	}
113 
114 	/* Test appending to a NUL-terminated string. */
115 	memcpy(buf, "abcd", sizeof("abcd"));
116 	len = strlcat(buf, "efgh", bufsize);
117 	if (len != 8) {
118 		fprintf(stderr, "strlcat: failed empty buffer test (4a)\n");
119 		failures++;
120 	}
121 	/* Make sure we only wrote where expected. */
122 	if (memcmp(buf, "abcdefgh", sizeof("abcdefgh")) != 0) {
123 		fprintf(stderr, "strlcat: failed empty buffer test (4b)\n");
124 		failures++;
125 	}
126 	for (cp = buf + len + 1; cp < ep; cp++) {
127 		if (*cp != 'z') {
128 			fprintf(stderr,
129 			    "strlcat: failed empty buffer test (4c)\n");
130 			failures++;
131 			break;
132 		}
133 	}
134 
135         /*
136          * The following tests should result in SIGSEGV, however some
137          * systems may erroneously report SIGBUS.
138          * These tests assume that strlcat() is signal-safe.
139          */
140         memset(&sa, 0, sizeof(sa));
141         sigemptyset(&sa.sa_mask);
142         sa.sa_handler = handler;
143         sigaction(SIGSEGV, &sa, NULL);
144         sigaction(SIGBUS, &sa, NULL);
145 
146         /* Test copying to a NULL buffer with non-zero size. */
147         got_signal = 0;
148         if (sigsetjmp(jmpenv, 1) == 0) {
149                 len = strlcat(NULL, "abcd", sizeof(buf));
150                 fprintf(stderr, "strlcat: failed NULL dst test (5a), "
151                     "expected signal %d, got len %zu\n", SIGSEGV, len);
152                 failures++;
153         } else if (got_signal != SIGSEGV) {
154                 fprintf(stderr, "strlcat: failed NULL dst test (5b), "
155                     "expected signal %d, got %d\n", SIGSEGV, got_signal);
156                 failures++;
157         }
158 
159         /* Test copying from a NULL src. */
160 	memcpy(buf, "abcd", sizeof("abcd"));
161         got_signal = 0;
162         if (sigsetjmp(jmpenv, 1) == 0) {
163                 len = strlcat(buf, NULL, sizeof(buf));
164                 fprintf(stderr, "strlcat: failed NULL src test (6a), "
165                     "expected signal %d, got len %zu\n", SIGSEGV, len);
166                 failures++;
167         } else if (got_signal != SIGSEGV) {
168                 fprintf(stderr, "strlcat: failed NULL src test (6b), "
169                     "expected signal %d, got %d\n", SIGSEGV, got_signal);
170                 failures++;
171         }
172 
173 	return failures;
174 }
175