1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright 2024 Bill Sommerfeld <sommerfeld@hamachi.org>
14  */
15 
16 /*
17  * Regression test for illumos bug #16352: verify that strftime behaves
18  * properly if the buffer length is overly large.
19  */
20 
21 #include <limits.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <time.h>
26 
27 static int status = EXIT_SUCCESS;
28 
29 static const char expected_buf[] = "2024 04 23";
30 static int expected_ret = 10;
31 
32 static void
check_results(const char * name,int ret,const char * buf)33 check_results(const char *name, int ret, const char *buf)
34 {
35 	if (ret == 0) {
36 		fprintf(stderr, "TEST FAILED: %s returned 0\n", name);
37 		status = EXIT_FAILURE;
38 	}
39 
40 	if (ret != 10) {
41 		fprintf(stderr, "TEST FAILED: %s length %d (expected %d)\n",
42 		    name, ret, expected_ret);
43 		status = EXIT_FAILURE;
44 	}
45 
46 	if (strcmp(buf, expected_buf) != 0) {
47 		fprintf(stderr, "TEST FAILED: %s contents [%s]"
48 		    " (expected [%s])\n", name, buf, expected_buf);
49 		status = EXIT_FAILURE;
50 	}
51 }
52 
53 int
main(void)54 main(void)
55 {
56 	int ret;
57 	struct tm t;
58 	char buf[1024];
59 
60 	memset(&t, 0, sizeof (t));
61 	t.tm_year = 124;
62 	t.tm_mon = 3;
63 	t.tm_mday = 23;
64 
65 	/*
66 	 * Test that ascftime() behaves properly; ascftime calls
67 	 * strftime(buf, LONG_MAX, format, t).  For an unfixed libc,
68 	 * this will fail if buf lies above the midpoint of the
69 	 * process address space, as the computation of buf + len
70 	 * overflows and wraps around.
71 	 */
72 	ret = ascftime(buf, "%Y %m %d", &t);
73 	check_results("ascftime", ret, buf);
74 
75 	/*
76 	 * Repeat test with strftime passed the maximum possible length.
77 	 * This will wrap around as long as buf is not NULL, letting us
78 	 * exercise the fix even if the user address space is restricted
79 	 * in some way.
80 	 */
81 	ret = strftime(buf, ULONG_MAX, "%Y %m %d", &t);
82 	check_results("strftime", ret, buf);
83 
84 	if (status == EXIT_SUCCESS) {
85 		(void) printf("TEST PASSED: observed expected output\n");
86 	}
87 	printf("NOTE: buffer is %p\n", buf);
88 	return (status);
89 }
90