17558fa28d2e33e597a5ec6d312d41ca09971ad8
[platform/upstream/glibc.git] / gshadow / tst-fgetsgent_r.c
1 /* Test for fgetsgent_r and buffer sizes.
2    Copyright (C) 2020-2023 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);
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
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 (path);
188
189   return 0;
190 }
191
192 #include <support/test-driver.c>