xref: /openbsd-src/regress/lib/libc/strlcpy/strlcpytest.c (revision 56d68f1e19ff848c889ecfa71d3a06340ff64892)
1 /*	$OpenBSD: strlcpytest.c,v 1.3 2019/01/25 00:19:26 millert Exp $ */
2 
3 /*
4  * Copyright (c) 2014 Todd C. Miller <millert@openbsd.org>
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 <signal.h>
25 #include <setjmp.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, *buf2, *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 	buf2 = malloc(bufsize);
52 	if (buf == NULL || buf2 == NULL) {
53 		fprintf(stderr, "unable to allocate memory\n");
54 		return 1;
55 	}
56 	memset(buf, 'z', bufsize);
57 	ep = buf + bufsize;
58 
59 	/* Test copying to a zero-length NULL buffer. */
60 	len = strlcpy(NULL, "abcd", 0);
61 	if (len != 4) {
62 		fprintf(stderr,
63 		    "strlcpy: failed zero-length buffer test (1a)\n");
64 		failures++;
65 	}
66 
67 	/* Test copying small string to a large buffer. */
68 	len = strlcpy(buf, "abcd", bufsize);
69 	if (len != 4) {
70 		fprintf(stderr, "strlcpy: failed large buffer test (2a)\n");
71 		failures++;
72 	}
73 	/* Make sure we only wrote where expected. */
74 	if (memcmp(buf, "abcd", sizeof("abcd")) != 0) {
75 		fprintf(stderr, "strlcpy: failed large buffer test (2b)\n");
76 		failures++;
77 	}
78 	for (cp = buf + len + 1; cp < ep; cp++) {
79 		if (*cp != 'z') {
80 			fprintf(stderr,
81 			    "strlcpy: failed large buffer test (2c)\n");
82 			failures++;
83 			break;
84 		}
85 	}
86 
87 	/* Test copying large string to a small buffer. */
88 	memset(buf, 'z', bufsize);
89 	memset(buf2, 'x', bufsize - 1);
90 	buf2[bufsize - 1] = '\0';
91 	len = strlcpy(buf, buf2, bufsize / 2);
92 	if (len != bufsize - 1) {
93 		fprintf(stderr, "strlcpy: failed small buffer test (3a)\n");
94 		failures++;
95 	}
96 	/* Make sure we only wrote where expected. */
97 	len = (bufsize / 2) - 1;
98 	if (memcmp(buf, buf2, len) != 0 || buf[len] != '\0') {
99 		fprintf(stderr, "strlcpy: failed small buffer test (3b)\n");
100 		failures++;
101 	}
102 	for (cp = buf + len + 1; cp < ep; cp++) {
103 		if (*cp != 'z') {
104 			fprintf(stderr,
105 			    "strlcpy: failed small buffer test (3c)\n");
106 			failures++;
107 			break;
108 		}
109 	}
110 
111 	/* Test copying to a 1-byte buffer. */
112 	memset(buf, 'z', bufsize);
113 	len = strlcpy(buf, "abcd", 1);
114 	if (len != 4) {
115 		fprintf(stderr, "strlcpy: failed 1-byte buffer test (4a)\n");
116 		failures++;
117 	}
118 	/* Make sure we only wrote where expected. */
119 	if (buf[0] != '\0') {
120 		fprintf(stderr, "strlcpy: failed 1-byte buffer test (4b)\n");
121 		failures++;
122 	}
123 	for (cp = buf + 1; cp < ep; cp++) {
124 		if (*cp != 'z') {
125 			fprintf(stderr,
126 			    "strlcpy: failed 1-byte buffer test (4c)\n");
127 			failures++;
128 			break;
129 		}
130 	}
131 
132 	/*
133 	 * The following tests should result in SIGSEGV, however some
134 	 * systems may erroneously report SIGBUS.
135 	 * These tests assume that strlcpy() is signal-safe.
136 	 */
137 	memset(&sa, 0, sizeof(sa));
138 	sigemptyset(&sa.sa_mask);
139 	sa.sa_handler = handler;
140 	sigaction(SIGSEGV, &sa, NULL);
141 	sigaction(SIGBUS, &sa, NULL);
142 
143 	/* Test copying to a NULL buffer with non-zero size. */
144 	got_signal = 0;
145 	if (sigsetjmp(jmpenv, 1) == 0) {
146 		len = strlcpy(NULL, "abcd", sizeof(buf));
147 		fprintf(stderr, "strlcpy: failed NULL dst test (5a), "
148 		    "expected signal %d, got len %zu\n", SIGSEGV, len);
149 		failures++;
150 	} else if (got_signal != SIGSEGV) {
151 		fprintf(stderr, "strlcpy: failed NULL dst test (5b), "
152 		    "expected signal %d, got %d\n", SIGSEGV, got_signal);
153 		failures++;
154 	}
155 
156 	/* Test copying from a NULL src. */
157 	got_signal = 0;
158 	if (sigsetjmp(jmpenv, 1) == 0) {
159 		len = strlcpy(buf, NULL, sizeof(buf));
160 		fprintf(stderr, "strlcpy: failed NULL src test (6a), "
161 		    "expected signal %d, got len %zu\n", SIGSEGV, len);
162 		failures++;
163 	} else if (got_signal != SIGSEGV) {
164 		fprintf(stderr, "strlcpy: failed NULL src test (6b), "
165 		    "expected signal %d, got %d\n", SIGSEGV, got_signal);
166 		failures++;
167 	}
168 
169 	return failures;
170 }
171