xref: /openbsd/regress/lib/libc/strlcpy/strlcpytest.c (revision de8b408b)
1*de8b408bSmillert /*	$OpenBSD: strlcpytest.c,v 1.5 2021/09/27 19:33:58 millert Exp $ */
26f05df2dSmillert 
36f05df2dSmillert /*
4bf198cc6Smillert  * Copyright (c) 2014 Todd C. Miller <millert@openbsd.org>
56f05df2dSmillert  *
66f05df2dSmillert  * Permission to use, copy, modify, and distribute this software for any
76f05df2dSmillert  * purpose with or without fee is hereby granted, provided that the above
86f05df2dSmillert  * copyright notice and this permission notice appear in all copies.
96f05df2dSmillert  *
106f05df2dSmillert  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
116f05df2dSmillert  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
126f05df2dSmillert  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
136f05df2dSmillert  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
146f05df2dSmillert  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
156f05df2dSmillert  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
166f05df2dSmillert  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
176f05df2dSmillert  */
186f05df2dSmillert 
196f05df2dSmillert #include <sys/types.h>
206f05df2dSmillert 
216f05df2dSmillert #include <stdio.h>
226f05df2dSmillert #include <stdlib.h>
236f05df2dSmillert #include <string.h>
24f191fa1fSmillert #include <signal.h>
25f191fa1fSmillert #include <setjmp.h>
266f05df2dSmillert #include <unistd.h>
276f05df2dSmillert 
28f191fa1fSmillert volatile sig_atomic_t got_signal;
29f191fa1fSmillert sigjmp_buf jmpenv;
30f191fa1fSmillert 
31f191fa1fSmillert void
handler(int signo)32f191fa1fSmillert handler(int signo)
33f191fa1fSmillert {
34f191fa1fSmillert 	got_signal = signo;
35f191fa1fSmillert 	siglongjmp(jmpenv, 1);
36f191fa1fSmillert }
37f191fa1fSmillert 
38f191fa1fSmillert int
main(int argc,char * argv[])39f191fa1fSmillert main(int argc, char *argv[])
406f05df2dSmillert {
416f05df2dSmillert 	char *buf, *buf2, *cp, *ep;
42f191fa1fSmillert 	struct sigaction sa;
436f05df2dSmillert 	size_t len, bufsize;
44*de8b408bSmillert 	volatile int failures = 0;
456f05df2dSmillert 
466f05df2dSmillert 	bufsize = getpagesize(); /* trigger guard pages easily */
476f05df2dSmillert 	buf = malloc(bufsize);
486f05df2dSmillert 	buf2 = malloc(bufsize);
496f05df2dSmillert 	if (buf == NULL || buf2 == NULL) {
506f05df2dSmillert 		fprintf(stderr, "unable to allocate memory\n");
516f05df2dSmillert 		return 1;
526f05df2dSmillert 	}
53f191fa1fSmillert 	memset(buf, 'z', bufsize);
546f05df2dSmillert 	ep = buf + bufsize;
556f05df2dSmillert 
566f05df2dSmillert 	/* Test copying to a zero-length NULL buffer. */
576f05df2dSmillert 	len = strlcpy(NULL, "abcd", 0);
586f05df2dSmillert 	if (len != 4) {
59f191fa1fSmillert 		fprintf(stderr,
60f191fa1fSmillert 		    "strlcpy: failed zero-length buffer test (1a)\n");
616f05df2dSmillert 		failures++;
626f05df2dSmillert 	}
636f05df2dSmillert 
646f05df2dSmillert 	/* Test copying small string to a large buffer. */
656f05df2dSmillert 	len = strlcpy(buf, "abcd", bufsize);
666f05df2dSmillert 	if (len != 4) {
67f191fa1fSmillert 		fprintf(stderr, "strlcpy: failed large buffer test (2a)\n");
686f05df2dSmillert 		failures++;
696f05df2dSmillert 	}
706f05df2dSmillert 	/* Make sure we only wrote where expected. */
716f05df2dSmillert 	if (memcmp(buf, "abcd", sizeof("abcd")) != 0) {
72f191fa1fSmillert 		fprintf(stderr, "strlcpy: failed large buffer test (2b)\n");
736f05df2dSmillert 		failures++;
746f05df2dSmillert 	}
756f05df2dSmillert 	for (cp = buf + len + 1; cp < ep; cp++) {
76f191fa1fSmillert 		if (*cp != 'z') {
77f191fa1fSmillert 			fprintf(stderr,
78f191fa1fSmillert 			    "strlcpy: failed large buffer test (2c)\n");
796f05df2dSmillert 			failures++;
806f05df2dSmillert 			break;
816f05df2dSmillert 		}
826f05df2dSmillert 	}
836f05df2dSmillert 
846f05df2dSmillert 	/* Test copying large string to a small buffer. */
85f191fa1fSmillert 	memset(buf, 'z', bufsize);
866f05df2dSmillert 	memset(buf2, 'x', bufsize - 1);
876f05df2dSmillert 	buf2[bufsize - 1] = '\0';
886f05df2dSmillert 	len = strlcpy(buf, buf2, bufsize / 2);
896f05df2dSmillert 	if (len != bufsize - 1) {
90f191fa1fSmillert 		fprintf(stderr, "strlcpy: failed small buffer test (3a)\n");
916f05df2dSmillert 		failures++;
926f05df2dSmillert 	}
936f05df2dSmillert 	/* Make sure we only wrote where expected. */
946f05df2dSmillert 	len = (bufsize / 2) - 1;
956f05df2dSmillert 	if (memcmp(buf, buf2, len) != 0 || buf[len] != '\0') {
96f191fa1fSmillert 		fprintf(stderr, "strlcpy: failed small buffer test (3b)\n");
976f05df2dSmillert 		failures++;
986f05df2dSmillert 	}
996f05df2dSmillert 	for (cp = buf + len + 1; cp < ep; cp++) {
100f191fa1fSmillert 		if (*cp != 'z') {
101f191fa1fSmillert 			fprintf(stderr,
102f191fa1fSmillert 			    "strlcpy: failed small buffer test (3c)\n");
1036f05df2dSmillert 			failures++;
1046f05df2dSmillert 			break;
1056f05df2dSmillert 		}
1066f05df2dSmillert 	}
1076f05df2dSmillert 
1086f05df2dSmillert 	/* Test copying to a 1-byte buffer. */
109f191fa1fSmillert 	memset(buf, 'z', bufsize);
1106f05df2dSmillert 	len = strlcpy(buf, "abcd", 1);
1116f05df2dSmillert 	if (len != 4) {
112f191fa1fSmillert 		fprintf(stderr, "strlcpy: failed 1-byte buffer test (4a)\n");
1136f05df2dSmillert 		failures++;
1146f05df2dSmillert 	}
1156f05df2dSmillert 	/* Make sure we only wrote where expected. */
1166f05df2dSmillert 	if (buf[0] != '\0') {
117f191fa1fSmillert 		fprintf(stderr, "strlcpy: failed 1-byte buffer test (4b)\n");
1186f05df2dSmillert 		failures++;
1196f05df2dSmillert 	}
1206f05df2dSmillert 	for (cp = buf + 1; cp < ep; cp++) {
121f191fa1fSmillert 		if (*cp != 'z') {
122f191fa1fSmillert 			fprintf(stderr,
123f191fa1fSmillert 			    "strlcpy: failed 1-byte buffer test (4c)\n");
1246f05df2dSmillert 			failures++;
1256f05df2dSmillert 			break;
1266f05df2dSmillert 		}
1276f05df2dSmillert 	}
1286f05df2dSmillert 
129f191fa1fSmillert 	/*
130f191fa1fSmillert 	 * The following tests should result in SIGSEGV, however some
131f191fa1fSmillert 	 * systems may erroneously report SIGBUS.
132f191fa1fSmillert 	 * These tests assume that strlcpy() is signal-safe.
133f191fa1fSmillert 	 */
134f191fa1fSmillert 	memset(&sa, 0, sizeof(sa));
135f191fa1fSmillert 	sigemptyset(&sa.sa_mask);
136f191fa1fSmillert 	sa.sa_handler = handler;
137f191fa1fSmillert 	sigaction(SIGSEGV, &sa, NULL);
138f191fa1fSmillert 	sigaction(SIGBUS, &sa, NULL);
139f191fa1fSmillert 
140f191fa1fSmillert 	/* Test copying to a NULL buffer with non-zero size. */
141f191fa1fSmillert 	got_signal = 0;
142f191fa1fSmillert 	if (sigsetjmp(jmpenv, 1) == 0) {
143f191fa1fSmillert 		len = strlcpy(NULL, "abcd", sizeof(buf));
144f191fa1fSmillert 		fprintf(stderr, "strlcpy: failed NULL dst test (5a), "
145f191fa1fSmillert 		    "expected signal %d, got len %zu\n", SIGSEGV, len);
146f191fa1fSmillert 		failures++;
147f191fa1fSmillert 	} else if (got_signal != SIGSEGV) {
148f191fa1fSmillert 		fprintf(stderr, "strlcpy: failed NULL dst test (5b), "
149f191fa1fSmillert 		    "expected signal %d, got %d\n", SIGSEGV, got_signal);
150f191fa1fSmillert 		failures++;
151f191fa1fSmillert 	}
152f191fa1fSmillert 
153f191fa1fSmillert 	/* Test copying from a NULL src. */
154f191fa1fSmillert 	got_signal = 0;
155f191fa1fSmillert 	if (sigsetjmp(jmpenv, 1) == 0) {
156f191fa1fSmillert 		len = strlcpy(buf, NULL, sizeof(buf));
157f191fa1fSmillert 		fprintf(stderr, "strlcpy: failed NULL src test (6a), "
158f191fa1fSmillert 		    "expected signal %d, got len %zu\n", SIGSEGV, len);
159f191fa1fSmillert 		failures++;
160f191fa1fSmillert 	} else if (got_signal != SIGSEGV) {
161f191fa1fSmillert 		fprintf(stderr, "strlcpy: failed NULL src test (6b), "
162f191fa1fSmillert 		    "expected signal %d, got %d\n", SIGSEGV, got_signal);
163f191fa1fSmillert 		failures++;
164f191fa1fSmillert 	}
165f191fa1fSmillert 
1666f05df2dSmillert 	return failures;
1676f05df2dSmillert }
168