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}