]>
Commit | Line | Data |
---|---|---|
2add4235 | 1 | /* Test for fgetsgent_r and buffer sizes. |
6d7e8eda | 2 | Copyright (C) 2020-2023 Free Software Foundation, Inc. |
2add4235 FW |
3 | This file is part of the GNU C Library. |
4 | ||
5 | The GNU C Library is free software; you can redistribute it and/or | |
6 | modify it under the terms of the GNU Lesser General Public | |
7 | License as published by the Free Software Foundation; either | |
8 | version 2.1 of the License, or (at your option) any later version. | |
9 | ||
10 | The GNU C Library is distributed in the hope that it will be useful, | |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 | Lesser General Public License for more details. | |
14 | ||
15 | You should have received a copy of the GNU Lesser General Public | |
16 | License along with the GNU C Library; if not, see | |
17 | <https://www.gnu.org/licenses/>. */ | |
18 | ||
19 | #include <array_length.h> | |
20 | #include <errno.h> | |
21 | #include <gshadow.h> | |
22 | #include <stdbool.h> | |
23 | #include <stdlib.h> | |
24 | #include <support/check.h> | |
25 | #include <support/support.h> | |
26 | #include <support/temp_file.h> | |
27 | #include <support/xmemstream.h> | |
28 | #include <support/xstdio.h> | |
29 | ||
30 | /* Turn a parsed struct back into a line string. The returned string | |
31 | should be freed. */ | |
32 | static char * | |
33 | format_ent (const struct sgrp *e) | |
34 | { | |
35 | struct xmemstream stream; | |
36 | xopen_memstream (&stream); | |
37 | TEST_COMPARE (putsgent (e, stream.out), 0); | |
38 | xfclose_memstream (&stream); | |
39 | return stream.buffer; | |
40 | } | |
41 | ||
42 | /* An entry in the input file along with the expected output. */ | |
43 | struct input | |
44 | { | |
45 | const char *line; /* Line in the file. */ | |
46 | const char *expected; /* Expected output. NULL if skipped. */ | |
47 | }; | |
48 | ||
49 | const struct input inputs[] = | |
50 | { | |
51 | /* Regular entries. */ | |
52 | { "g1:x1::\n", "g1:x1::\n" }, | |
53 | { "g2:x2:a1:\n", "g2:x2:a1:\n" }, | |
54 | { "g3:x3:a2:u1\n", "g3:x3:a2:u1\n" }, | |
55 | { "g4:x4:a3,a4:u2,u3,u4\n", "g4:x4:a3,a4:u2,u3,u4\n" }, | |
56 | ||
57 | /* Comments and empty lines. */ | |
58 | { "\n", NULL }, | |
59 | { " \n", NULL }, | |
60 | { "\t\n", NULL }, | |
61 | { "#g:x::\n", NULL }, | |
62 | { " #g:x::\n", NULL }, | |
63 | { "\t#g:x::\n", NULL }, | |
64 | { " \t#g:x::\n", NULL }, | |
65 | ||
66 | /* Marker for synchronization. */ | |
67 | { "g5:x5::\n", "g5:x5::\n" }, | |
68 | ||
69 | /* Leading whitespace. */ | |
70 | { " g6:x6::\n", "g6:x6::\n" }, | |
71 | { "\tg7:x7::\n", "g7:x7::\n" }, | |
72 | ||
73 | /* This is expected to trigger buffer exhaustion during parsing | |
74 | (bug 20338). */ | |
75 | { | |
76 | "g8:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx:u5,u6,u7,u8,u9:\n", | |
77 | "g8:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx:u5,u6,u7,u8,u9:\n", | |
78 | }, | |
79 | { | |
80 | "g9:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx::a5,a6,a7,a8,a9,a10\n", | |
81 | "g9:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx::a5,a6,a7,a8,a9,a10\n", | |
82 | }, | |
83 | }; | |
84 | ||
85 | /* Writes the test data to a temporary file and returns its name. The | |
86 | returned pointer should be freed. */ | |
87 | static char * | |
88 | create_test_file (void) | |
89 | { | |
90 | char *path; | |
91 | int fd = create_temp_file ("tst-fgetsgent_r-", &path); | |
92 | FILE *fp = fdopen (fd, "w"); | |
93 | TEST_VERIFY_EXIT (fp != NULL); | |
94 | ||
95 | for (size_t i = 0; i < array_length (inputs); ++i) | |
96 | fputs (inputs[i].line, fp); | |
97 | ||
98 | xfclose (fp); | |
99 | return path; | |
100 | } | |
101 | ||
102 | /* Read the test file with the indicated start buffer size. Return | |
103 | true if the buffer size had to be increased during reading. */ | |
104 | static bool | |
105 | run_test (const char *path, size_t buffer_size) | |
106 | { | |
107 | bool resized = false; | |
108 | FILE *fp = xfopen (path, "r"); | |
109 | ||
110 | /* This avoids repeated lseek system calls (bug 26257). */ | |
111 | TEST_COMPARE (fseeko64 (fp, 0, SEEK_SET), 0); | |
112 | ||
113 | size_t i = 0; | |
114 | while (true) | |
115 | { | |
116 | /* Skip over unused expected entries. */ | |
117 | while (i < array_length (inputs) && inputs[i].expected == NULL) | |
118 | ++i; | |
119 | ||
120 | /* Store the data on the heap, to help valgrind to detect | |
121 | invalid accesses. */ | |
122 | struct sgrp *result_storage = xmalloc (sizeof (*result_storage)); | |
123 | char *buffer = xmalloc (buffer_size); | |
124 | struct sgrp **result_pointer_storage | |
125 | = xmalloc (sizeof (*result_pointer_storage)); | |
126 | ||
127 | int ret = fgetsgent_r (fp, result_storage, buffer, buffer_size, | |
128 | result_pointer_storage); | |
129 | if (ret == 0) | |
130 | { | |
131 | TEST_VERIFY (*result_pointer_storage != NULL); | |
132 | TEST_VERIFY (i < array_length (inputs)); | |
133 | if (*result_pointer_storage != NULL | |
134 | && i < array_length (inputs)) | |
135 | { | |
136 | char * actual = format_ent (*result_pointer_storage); | |
137 | TEST_COMPARE_STRING (inputs[i].expected, actual); | |
138 | free (actual); | |
139 | ++i; | |
140 | } | |
141 | else | |
142 | break; | |
143 | } | |
144 | else | |
145 | { | |
146 | TEST_VERIFY (*result_pointer_storage == NULL); | |
147 | TEST_COMPARE (ret, errno); | |
148 | ||
149 | if (ret == ENOENT) | |
150 | { | |
151 | TEST_COMPARE (i, array_length (inputs)); | |
152 | free (result_pointer_storage); | |
153 | free (buffer); | |
154 | free (result_storage); | |
155 | break; | |
156 | } | |
157 | else if (ret == ERANGE) | |
158 | { | |
159 | resized = true; | |
160 | ++buffer_size; | |
161 | } | |
162 | else | |
163 | FAIL_EXIT1 ("read failure: %m"); | |
164 | } | |
165 | ||
166 | free (result_pointer_storage); | |
167 | free (buffer); | |
168 | free (result_storage); | |
169 | } | |
170 | ||
00bc6830 | 171 | xfclose (fp); |
2add4235 FW |
172 | return resized; |
173 | } | |
174 | ||
175 | static int | |
176 | do_test (void) | |
177 | { | |
178 | char *path = create_test_file (); | |
179 | ||
180 | for (size_t buffer_size = 3; ; ++buffer_size) | |
181 | { | |
182 | bool resized = run_test (path, buffer_size); | |
183 | if (!resized) | |
184 | break; | |
185 | } | |
186 | ||
187 | free (path); | |
188 | ||
189 | return 0; | |
190 | } | |
191 | ||
192 | #include <support/test-driver.c> |