Fix libnldbl_nonshared.a references to internal libm symbols (bug 23735).
[glibc.git] / libio / tst-vtables-common.c
blob5e3101206919fa1b8c414a560fcdb458a9854058
1 /* Test for libio vtables and their validation. Common code.
2 Copyright (C) 2018 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
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.
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.
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 <http://www.gnu.org/licenses/>. */
19 /* This test provides some coverage for how various stdio functions
20 use the vtables in FILE * objects. The focus is mostly on which
21 functions call which methods, not so much on validating data
22 processing. An initial series of tests check that custom vtables
23 do not work without activation through _IO_init.
25 Note: libio vtables are deprecated feature. Do not use this test
26 as a documentation source for writing custom vtables. See
27 fopencookie for a different way of creating custom stdio
28 streams. */
30 #include <stdbool.h>
31 #include <string.h>
32 #include <support/capture_subprocess.h>
33 #include <support/check.h>
34 #include <support/namespace.h>
35 #include <support/support.h>
36 #include <support/test-driver.h>
37 #include <support/xunistd.h>
39 #include "libioP.h"
41 /* Data shared between the test subprocess and the test driver in the
42 parent. Note that *shared is reset at the start of the check_call
43 function. */
44 struct shared
46 /* Expected file pointer for method calls. */
47 FILE *fp;
49 /* If true, assume that a call to _IO_init is needed to enable
50 custom vtables. */
51 bool initially_disabled;
53 /* Requested return value for the methods which have one. */
54 int return_value;
56 /* A value (usually a character) recorded by some of the methods
57 below. */
58 int value;
60 /* Likewise, for some data. */
61 char buffer[16];
62 size_t buffer_length;
64 /* Total number of method calls. */
65 unsigned int calls;
67 /* Individual method call counts. */
68 unsigned int calls_finish;
69 unsigned int calls_overflow;
70 unsigned int calls_underflow;
71 unsigned int calls_uflow;
72 unsigned int calls_pbackfail;
73 unsigned int calls_xsputn;
74 unsigned int calls_xsgetn;
75 unsigned int calls_seekoff;
76 unsigned int calls_seekpos;
77 unsigned int calls_setbuf;
78 unsigned int calls_sync;
79 unsigned int calls_doallocate;
80 unsigned int calls_read;
81 unsigned int calls_write;
82 unsigned int calls_seek;
83 unsigned int calls_close;
84 unsigned int calls_stat;
85 unsigned int calls_showmanyc;
86 unsigned int calls_imbue;
87 } *shared;
89 /* Method implementations which increment the counters in *shared. */
91 static void
92 log_method (FILE *fp, const char *name)
94 if (test_verbose > 0)
95 printf ("info: %s (%p) called\n", name, fp);
98 static void
99 method_finish (FILE *fp, int dummy)
101 log_method (fp, __func__);
102 TEST_VERIFY (fp == shared->fp);
103 ++shared->calls;
104 ++shared->calls_finish;
107 static int
108 method_overflow (FILE *fp, int ch)
110 log_method (fp, __func__);
111 TEST_VERIFY (fp == shared->fp);
112 ++shared->calls;
113 ++shared->calls_overflow;
114 shared->value = ch;
115 return shared->return_value;
118 static int
119 method_underflow (FILE *fp)
121 log_method (fp, __func__);
122 TEST_VERIFY (fp == shared->fp);
123 ++shared->calls;
124 ++shared->calls_underflow;
125 return shared->return_value;
128 static int
129 method_uflow (FILE *fp)
131 log_method (fp, __func__);
132 TEST_VERIFY (fp == shared->fp);
133 ++shared->calls;
134 ++shared->calls_uflow;
135 return shared->return_value;
138 static int
139 method_pbackfail (FILE *fp, int ch)
141 log_method (fp, __func__);
142 TEST_VERIFY (fp == shared->fp);
143 ++shared->calls;
144 ++shared->calls_pbackfail;
145 shared->value = ch;
146 return shared->return_value;
149 static size_t
150 method_xsputn (FILE *fp, const void *data, size_t n)
152 log_method (fp, __func__);
153 TEST_VERIFY (fp == shared->fp);
154 ++shared->calls;
155 ++shared->calls_xsputn;
157 size_t to_copy = n;
158 if (n > sizeof (shared->buffer))
159 to_copy = sizeof (shared->buffer);
160 memcpy (shared->buffer, data, to_copy);
161 shared->buffer_length = to_copy;
162 return to_copy;
165 static size_t
166 method_xsgetn (FILE *fp, void *data, size_t n)
168 log_method (fp, __func__);
169 TEST_VERIFY (fp == shared->fp);
170 ++shared->calls;
171 ++shared->calls_xsgetn;
172 return 0;
175 static off64_t
176 method_seekoff (FILE *fp, off64_t offset, int dir, int mode)
178 log_method (fp, __func__);
179 TEST_VERIFY (fp == shared->fp);
180 ++shared->calls;
181 ++shared->calls_seekoff;
182 return shared->return_value;
185 static off64_t
186 method_seekpos (FILE *fp, off64_t offset, int mode)
188 log_method (fp, __func__);
189 TEST_VERIFY (fp == shared->fp);
190 ++shared->calls;
191 ++shared->calls_seekpos;
192 return shared->return_value;
195 static FILE *
196 method_setbuf (FILE *fp, char *buffer, ssize_t length)
198 log_method (fp, __func__);
199 TEST_VERIFY (fp == shared->fp);
200 ++shared->calls;
201 ++shared->calls_setbuf;
202 return fp;
205 static int
206 method_sync (FILE *fp)
208 log_method (fp, __func__);
209 TEST_VERIFY (fp == shared->fp);
210 ++shared->calls;
211 ++shared->calls_sync;
212 return shared->return_value;
215 static int
216 method_doallocate (FILE *fp)
218 log_method (fp, __func__);
219 TEST_VERIFY (fp == shared->fp);
220 ++shared->calls;
221 ++shared->calls_doallocate;
222 return shared->return_value;
225 static ssize_t
226 method_read (FILE *fp, void *data, ssize_t length)
228 log_method (fp, __func__);
229 TEST_VERIFY (fp == shared->fp);
230 ++shared->calls;
231 ++shared->calls_read;
232 return shared->return_value;
235 static ssize_t
236 method_write (FILE *fp, const void *data, ssize_t length)
238 log_method (fp, __func__);
239 TEST_VERIFY (fp == shared->fp);
240 ++shared->calls;
241 ++shared->calls_write;
242 return shared->return_value;
245 static off64_t
246 method_seek (FILE *fp, off64_t offset, int mode)
248 log_method (fp, __func__);
249 TEST_VERIFY (fp == shared->fp);
250 ++shared->calls;
251 ++shared->calls_seek;
252 return shared->return_value;
255 static int
256 method_close (FILE *fp)
258 log_method (fp, __func__);
259 TEST_VERIFY (fp == shared->fp);
260 ++shared->calls;
261 ++shared->calls_close;
262 return shared->return_value;
265 static int
266 method_stat (FILE *fp, void *buffer)
268 log_method (fp, __func__);
269 TEST_VERIFY (fp == shared->fp);
270 ++shared->calls;
271 ++shared->calls_stat;
272 return shared->return_value;
275 static int
276 method_showmanyc (FILE *fp)
278 log_method (fp, __func__);
279 TEST_VERIFY (fp == shared->fp);
280 ++shared->calls;
281 ++shared->calls_showmanyc;
282 return shared->return_value;
285 static void
286 method_imbue (FILE *fp, void *locale)
288 log_method (fp, __func__);
289 TEST_VERIFY (fp == shared->fp);
290 ++shared->calls;
291 ++shared->calls_imbue;
294 /* Our custom vtable. */
296 static const struct _IO_jump_t jumps =
298 JUMP_INIT_DUMMY,
299 JUMP_INIT (finish, method_finish),
300 JUMP_INIT (overflow, method_overflow),
301 JUMP_INIT (underflow, method_underflow),
302 JUMP_INIT (uflow, method_uflow),
303 JUMP_INIT (pbackfail, method_pbackfail),
304 JUMP_INIT (xsputn, method_xsputn),
305 JUMP_INIT (xsgetn, method_xsgetn),
306 JUMP_INIT (seekoff, method_seekoff),
307 JUMP_INIT (seekpos, method_seekpos),
308 JUMP_INIT (setbuf, method_setbuf),
309 JUMP_INIT (sync, method_sync),
310 JUMP_INIT (doallocate, method_doallocate),
311 JUMP_INIT (read, method_read),
312 JUMP_INIT (write, method_write),
313 JUMP_INIT (seek, method_seek),
314 JUMP_INIT (close, method_close),
315 JUMP_INIT (stat, method_stat),
316 JUMP_INIT (showmanyc, method_showmanyc),
317 JUMP_INIT (imbue, method_imbue)
320 /* Our file implementation. */
322 struct my_file
324 FILE f;
325 const struct _IO_jump_t *vtable;
328 struct my_file
329 my_file_create (void)
331 return (struct my_file)
333 /* Disable locking, so that we do not have to set up a lock
334 pointer. */
335 .f._flags = _IO_USER_LOCK,
337 /* Copy the offset from the an initialized handle, instead of
338 figuring it out from scratch. */
339 .f._vtable_offset = stdin->_vtable_offset,
341 .vtable = &jumps,
345 /* Initial tests which do not enable vtable compatibility. */
347 /* Inhibit GCC optimization of fprintf. */
348 typedef int (*fprintf_type) (FILE *, const char *, ...);
349 static const volatile fprintf_type fprintf_ptr = &fprintf;
351 static void
352 without_compatibility_fprintf (void *closure)
354 /* This call should abort. */
355 fprintf_ptr (shared->fp, " ");
356 _exit (1);
359 static void
360 without_compatibility_fputc (void *closure)
362 /* This call should abort. */
363 fputc (' ', shared->fp);
364 _exit (1);
367 static void
368 without_compatibility_fgetc (void *closure)
370 /* This call should abort. */
371 fgetc (shared->fp);
372 _exit (1);
375 static void
376 without_compatibility_fflush (void *closure)
378 /* This call should abort. */
379 fflush (shared->fp);
380 _exit (1);
383 /* Exit status after abnormal termination. */
384 static int termination_status;
386 static void
387 init_termination_status (void)
389 pid_t pid = xfork ();
390 if (pid == 0)
391 abort ();
392 xwaitpid (pid, &termination_status, 0);
394 TEST_VERIFY (WIFSIGNALED (termination_status));
395 TEST_COMPARE (WTERMSIG (termination_status), SIGABRT);
398 static void
399 check_for_termination (const char *name, void (*callback) (void *))
401 struct my_file file = my_file_create ();
402 shared->fp = &file.f;
403 shared->return_value = -1;
404 shared->calls = 0;
405 struct support_capture_subprocess proc
406 = support_capture_subprocess (callback, NULL);
407 support_capture_subprocess_check (&proc, name, termination_status,
408 sc_allow_stderr);
409 const char *message
410 = "Fatal error: glibc detected an invalid stdio handle\n";
411 TEST_COMPARE_BLOB (proc.err.buffer, proc.err.length,
412 message, strlen (message));
413 TEST_COMPARE (shared->calls, 0);
414 support_capture_subprocess_free (&proc);
417 /* The test with vtable validation disabled. */
419 /* This function does not have a prototype in libioP.h to prevent
420 accidental use from within the library (which would disable vtable
421 verification). */
422 void _IO_init (FILE *fp, int flags);
424 static void
425 with_compatibility_fprintf (void *closure)
427 TEST_COMPARE (fprintf_ptr (shared->fp, "A%sCD", "B"), 4);
428 TEST_COMPARE (shared->calls, 3);
429 TEST_COMPARE (shared->calls_xsputn, 3);
430 TEST_COMPARE_BLOB (shared->buffer, shared->buffer_length,
431 "CD", 2);
434 static void
435 with_compatibility_fputc (void *closure)
437 shared->return_value = '@';
438 TEST_COMPARE (fputc ('@', shared->fp), '@');
439 TEST_COMPARE (shared->calls, 1);
440 TEST_COMPARE (shared->calls_overflow, 1);
441 TEST_COMPARE (shared->value, '@');
444 static void
445 with_compatibility_fgetc (void *closure)
447 shared->return_value = 'X';
448 TEST_COMPARE (fgetc (shared->fp), 'X');
449 TEST_COMPARE (shared->calls, 1);
450 TEST_COMPARE (shared->calls_uflow, 1);
453 static void
454 with_compatibility_fflush (void *closure)
456 TEST_COMPARE (fflush (shared->fp), 0);
457 TEST_COMPARE (shared->calls, 1);
458 TEST_COMPARE (shared->calls_sync, 1);
461 /* Call CALLBACK in a subprocess, after setting up a custom file
462 object and updating shared->fp. */
463 static void
464 check_call (const char *name, void (*callback) (void *),
465 bool initially_disabled)
467 *shared = (struct shared)
469 .initially_disabled = initially_disabled,
472 /* Set up a custom file object. */
473 struct my_file file = my_file_create ();
474 shared->fp = &file.f;
475 if (shared->initially_disabled)
476 _IO_init (shared->fp, file.f._flags);
478 if (test_verbose > 0)
479 printf ("info: calling test %s\n", name);
480 support_isolate_in_subprocess (callback, NULL);
483 /* Run the tests. INITIALLY_DISABLED indicates whether custom vtables
484 are disabled when the test starts. */
485 static int
486 run_tests (bool initially_disabled)
488 /* The test relies on fatal error messages being printed to standard
489 error. */
490 setenv ("LIBC_FATAL_STDERR_", "1", 1);
492 shared = support_shared_allocate (sizeof (*shared));
493 shared->initially_disabled = initially_disabled;
494 init_termination_status ();
496 if (initially_disabled)
498 check_for_termination ("fprintf", without_compatibility_fprintf);
499 check_for_termination ("fputc", without_compatibility_fputc);
500 check_for_termination ("fgetc", without_compatibility_fgetc);
501 check_for_termination ("fflush", without_compatibility_fflush);
504 check_call ("fprintf", with_compatibility_fprintf, initially_disabled);
505 check_call ("fputc", with_compatibility_fputc, initially_disabled);
506 check_call ("fgetc", with_compatibility_fgetc, initially_disabled);
507 check_call ("fflush", with_compatibility_fflush, initially_disabled);
509 support_shared_free (shared);
510 shared = NULL;
512 return 0;