summaryrefslogtreecommitdiff
path: root/usr/src/test/libc-tests/tests/asprintf-14933.c
blob: e63c0436d11a7e259b08c1f3e997e81ba0cac795 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
/*
 * This file and its contents are supplied under the terms of the
 * Common Development and Distribution License ("CDDL"), version 1.0.
 * You may only use this file in accordance with the terms of version
 * 1.0 of the CDDL.
 *
 * A full copy of the text of the CDDL should have accompanied this
 * source.  A copy of the CDDL is also available via the Internet at
 * http://www.illumos.org/license/CDDL.
 */

/*
 * Copyright 2022 Oxide Computer Company
 */

/*
 * This is a regression test for illumos#14933 where asprintf() in small buffers
 * was thrown off by an embedded NUL. Test both short and large buffers with
 * embedded NULs. "large" at the time 14933 was anything that exceeded 128
 * bytes.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <sys/sysmacros.h>

const char *longstr = "0123456789abcdefghijklmnopqrstuvwxyz";

int
main(void)
{
	int eval = EXIT_SUCCESS;
	char short_exp[] = { '0', '1', '2', '3', '\0', 'a', 'b', 'c', '\0' };
	size_t short_len = ARRAY_SIZE(short_exp);
	size_t long_len;
	char *out;
	int ret;

	ret = asprintf(&out, "%s%c%s", "0123", '\0', "abc");
	if (ret != short_len - 1) {
		(void) fprintf(stderr, "TEST FAILED: short asprintf returned "
		    "wrong length: found %u, expected %u\n", ret,
		    short_len - 1);
		eval = EXIT_FAILURE;
	} else {
		(void) printf("TEST PASSED: short buffer embedded nul has "
		    "correct length\n");
	}

	if (memcmp(short_exp, out, short_len) != 0) {
		(void) fprintf(stderr, "TEST FAILED: short example returned "
		    "wrong value\nexpected:");
		for (size_t i = 0; i < short_len; i++) {
			(void) fprintf(stderr, " 0x%02x", short_exp[i]);
		}
		(void) fprintf(stderr, "\nactual:  ");
		for (size_t i = 0; i < short_len; i++) {
			(void) fprintf(stderr, " 0x%02x", out[i]);
		}
		(void) fputc('\n', stderr);
		eval = EXIT_FAILURE;
	} else {
		(void) printf("TEST PASSED: short buffer data contents "
		    "match\n");
	}

	free(out);
	long_len = strlen(longstr) * 5 + 5;
	ret = asprintf(&out, "%s%c%s%c%s%c%s%c%s", longstr, '\0', longstr, '\0',
	    longstr, '\0', longstr, '\0', longstr);
	if (ret != long_len - 1) {
		(void) fprintf(stderr, "TEST FAILED: long asprintf returned "
		    "wrong length: found %u, expected %u\n", ret, long_len - 1);
		eval = EXIT_FAILURE;
	} else {
		(void) printf("TEST PASSED: long buffer embedded nul has "
		    "correct length\n");
	}

	bool large_pass = true;
	for (uint_t i = 0; i < 5; i++) {
		size_t offset = (strlen(longstr) + 1) * i;
		if (strcmp(longstr, out + offset) != 0) {
			(void) fprintf(stderr, "TEST FAILED: long asprintf "
			    "data buffer mismatch at copy %u\n", i);
			eval = EXIT_FAILURE;
			large_pass = false;
		}
	}
	if (large_pass) {
		(void) printf("TEST PASSED: long buffer data contents match\n");
	}

	return (eval);
}