master
1/*
2 * Exercise complicating glibc symbols from C code. Complicating symbols
3 * are ones that have moved between glibc versions, or use floating point
4 * parameters, or have otherwise tripped up the Zig glibc compatibility
5 * code.
6 */
7#include <assert.h>
8#include <errno.h>
9#include <features.h>
10#include <fcntl.h>
11#include <math.h>
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
15#include <sys/auxv.h>
16#include <sys/stat.h>
17#include <unistd.h>
18
19/* errno is compilcated (thread-local, dynamically provided, etc). */
20static void check_errno()
21{
22 int invalid_fd = open("/doesnotexist", O_RDONLY);
23 assert(invalid_fd == -1);
24 assert(errno == ENOENT);
25}
26
27/* fstat has moved around in glibc (between libc_nonshared and libc) */
28static void check_fstat()
29{
30 int self_fd = open("/proc/self/exe", O_RDONLY);
31
32 struct stat statbuf = {0};
33 int rc = fstat(self_fd, &statbuf);
34
35 assert(rc == 0);
36
37 assert(statbuf.st_dev != 0);
38 assert(statbuf.st_ino != 0);
39 assert(statbuf.st_mode != 0);
40 assert(statbuf.st_size > 0);
41 assert(statbuf.st_blocks > 0);
42 assert(statbuf.st_ctim.tv_sec > 0);
43
44 close(self_fd);
45}
46
47/* Some targets have a complicated ABI for floats and doubles */
48static void check_fp_abi()
49{
50 // Picked "pow" as it takes and returns doubles
51 assert(pow(10.0, 10.0) == 10000000000.0);
52 assert(powf(10.0f, 10.0f) == 10000000000.0f);
53}
54
55/* strlcpy introduced in glibc 2.38 */
56static void check_strlcpy()
57{
58#if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 38) || (__GLIBC__ > 2)
59 char target[4] = {0};
60 strlcpy(target, "this is a source string", 4);
61
62 assert(strcmp(target, "thi") == 0);
63#endif
64}
65
66/* reallocarray introduced in glibc 2.26 */
67static void check_reallocarray()
68{
69#if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 26) || (__GLIBC__ > 2)
70 const size_t el_size = 32;
71 void* base = reallocarray(NULL, 10, el_size);
72 void* grown = reallocarray(base, 100, el_size);
73
74 assert(base != NULL);
75 assert(grown != NULL);
76
77 free(grown);
78#endif
79}
80
81/* getauxval introduced in glibc 2.16 */
82static void check_getauxval()
83{
84#if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 16) || (__GLIBC__ > 2)
85 int pgsz = getauxval(AT_PAGESZ);
86 assert(pgsz >= 4*1024);
87#endif
88}
89
90/* atexit() is part of libc_nonshared */
91static void force_exit_0()
92{
93 exit(0);
94}
95
96static void check_atexit()
97{
98 int rc = atexit(force_exit_0);
99 assert(rc == 0);
100}
101
102int main() {
103 int rc;
104
105 check_errno();
106 check_fstat();
107 check_fp_abi();
108 check_strlcpy();
109 check_reallocarray();
110 check_getauxval();
111 check_atexit();
112
113 exit(99); // exit code overridden by atexit handler
114}