1 | /* Test for fgetsgent_r and buffer sizes. |
2 | Copyright (C) 2020-2022 Free Software Foundation, Inc. |
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: &stream); |
37 | TEST_COMPARE (putsgent (e, stream.out), 0); |
38 | xfclose_memstream (stream: &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 (base: "tst-fgetsgent_r-" , filename: &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, mode: "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 (n: sizeof (*result_storage)); |
123 | char *buffer = xmalloc (n: buffer_size); |
124 | struct sgrp **result_pointer_storage |
125 | = xmalloc (n: sizeof (*result_pointer_storage)); |
126 | |
127 | int ret = fgetsgent_r (stream: fp, result_buf: result_storage, buffer: buffer, buflen: buffer_size, |
128 | result: 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 (e: *result_pointer_storage); |
137 | TEST_COMPARE_STRING (inputs[i].expected, actual); |
138 | free (ptr: 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 (ptr: result_pointer_storage); |
153 | free (ptr: buffer); |
154 | free (ptr: 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 (ptr: result_pointer_storage); |
167 | free (ptr: buffer); |
168 | free (ptr: result_storage); |
169 | } |
170 | |
171 | xfclose (fp); |
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 (ptr: path); |
188 | |
189 | return 0; |
190 | } |
191 | |
192 | #include <support/test-driver.c> |
193 | |