xref: /openbsd/regress/lib/libc/strlcpy/strlcpytest.c (revision de8b408b)
1 /*	$OpenBSD: strlcpytest.c,v 1.5 2021/09/27 19:33:58 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
handler(int signo)32 handler(int signo)
33 {
34 	got_signal = signo;
35 	siglongjmp(jmpenv, 1);
36 }
37 
38 int
main(int argc,char * argv[])39 main(int argc, char *argv[])
40 {
41 	char *buf, *buf2, *cp, *ep;
42 	struct sigaction sa;
43 	size_t len, bufsize;
44 	volatile int failures = 0;
45 
46 	bufsize = getpagesize(); /* trigger guard pages easily */
47 	buf = malloc(bufsize);
48 	buf2 = malloc(bufsize);
49 	if (buf == NULL || buf2 == NULL) {
50 		fprintf(stderr, "unable to allocate memory\n");
51 		return 1;
52 	}
53 	memset(buf, 'z', bufsize);
54 	ep = buf + bufsize;
55 
56 	/* Test copying to a zero-length NULL buffer. */
57 	len = strlcpy(NULL, "abcd", 0);
58 	if (len != 4) {
59 		fprintf(stderr,
60 		    "strlcpy: failed zero-length buffer test (1a)\n");
61 		failures++;
62 	}
63 
64 	/* Test copying small string to a large buffer. */
65 	len = strlcpy(buf, "abcd", bufsize);
66 	if (len != 4) {
67 		fprintf(stderr, "strlcpy: failed large buffer test (2a)\n");
68 		failures++;
69 	}
70 	/* Make sure we only wrote where expected. */
71 	if (memcmp(buf, "abcd", sizeof("abcd")) != 0) {
72 		fprintf(stderr, "strlcpy: failed large buffer test (2b)\n");
73 		failures++;
74 	}
75 	for (cp = buf + len + 1; cp < ep; cp++) {
76 		if (*cp != 'z') {
77 			fprintf(stderr,
78 			    "strlcpy: failed large buffer test (2c)\n");
79 			failures++;
80 			break;
81 		}
82 	}
83 
84 	/* Test copying large string to a small buffer. */
85 	memset(buf, 'z', bufsize);
86 	memset(buf2, 'x', bufsize - 1);
87 	buf2[bufsize - 1] = '\0';
88 	len = strlcpy(buf, buf2, bufsize / 2);
89 	if (len != bufsize - 1) {
90 		fprintf(stderr, "strlcpy: failed small buffer test (3a)\n");
91 		failures++;
92 	}
93 	/* Make sure we only wrote where expected. */
94 	len = (bufsize / 2) - 1;
95 	if (memcmp(buf, buf2, len) != 0 || buf[len] != '\0') {
96 		fprintf(stderr, "strlcpy: failed small buffer test (3b)\n");
97 		failures++;
98 	}
99 	for (cp = buf + len + 1; cp < ep; cp++) {
100 		if (*cp != 'z') {
101 			fprintf(stderr,
102 			    "strlcpy: failed small buffer test (3c)\n");
103 			failures++;
104 			break;
105 		}
106 	}
107 
108 	/* Test copying to a 1-byte buffer. */
109 	memset(buf, 'z', bufsize);
110 	len = strlcpy(buf, "abcd", 1);
111 	if (len != 4) {
112 		fprintf(stderr, "strlcpy: failed 1-byte buffer test (4a)\n");
113 		failures++;
114 	}
115 	/* Make sure we only wrote where expected. */
116 	if (buf[0] != '\0') {
117 		fprintf(stderr, "strlcpy: failed 1-byte buffer test (4b)\n");
118 		failures++;
119 	}
120 	for (cp = buf + 1; cp < ep; cp++) {
121 		if (*cp != 'z') {
122 			fprintf(stderr,
123 			    "strlcpy: failed 1-byte buffer test (4c)\n");
124 			failures++;
125 			break;
126 		}
127 	}
128 
129 	/*
130 	 * The following tests should result in SIGSEGV, however some
131 	 * systems may erroneously report SIGBUS.
132 	 * These tests assume that strlcpy() is signal-safe.
133 	 */
134 	memset(&sa, 0, sizeof(sa));
135 	sigemptyset(&sa.sa_mask);
136 	sa.sa_handler = handler;
137 	sigaction(SIGSEGV, &sa, NULL);
138 	sigaction(SIGBUS, &sa, NULL);
139 
140 	/* Test copying to a NULL buffer with non-zero size. */
141 	got_signal = 0;
142 	if (sigsetjmp(jmpenv, 1) == 0) {
143 		len = strlcpy(NULL, "abcd", sizeof(buf));
144 		fprintf(stderr, "strlcpy: failed NULL dst test (5a), "
145 		    "expected signal %d, got len %zu\n", SIGSEGV, len);
146 		failures++;
147 	} else if (got_signal != SIGSEGV) {
148 		fprintf(stderr, "strlcpy: failed NULL dst test (5b), "
149 		    "expected signal %d, got %d\n", SIGSEGV, got_signal);
150 		failures++;
151 	}
152 
153 	/* Test copying from a NULL src. */
154 	got_signal = 0;
155 	if (sigsetjmp(jmpenv, 1) == 0) {
156 		len = strlcpy(buf, NULL, sizeof(buf));
157 		fprintf(stderr, "strlcpy: failed NULL src test (6a), "
158 		    "expected signal %d, got len %zu\n", SIGSEGV, len);
159 		failures++;
160 	} else if (got_signal != SIGSEGV) {
161 		fprintf(stderr, "strlcpy: failed NULL src test (6b), "
162 		    "expected signal %d, got %d\n", SIGSEGV, got_signal);
163 		failures++;
164 	}
165 
166 	return failures;
167 }
168