#define _GNU_SOURCE #include <stdarg.h> #include <stddef.h> #include <string.h> #include <stdio.h> #include <wchar.h> #include <stdlib.h> #include <pthread.h> /* glibc fortified _chk functions -- just call the non-checked version */ void *__memcpy_chk(void *dest, const void *src, size_t n, size_t destlen) { (void)destlen; return memcpy(dest, src, n); } size_t __mbsrtowcs_chk(wchar_t *dest, const char **src, size_t n, size_t destlen) { (void)destlen; return mbsrtowcs(dest, src, n, NULL); } int __vsnprintf_chk(char *s, size_t n, int flags, size_t slen, const char *fmt, va_list ap) { (void)flags; (void)slen; return vsnprintf(s, n, fmt, ap); } /* LFS64 large-file aliases. * Use fileno+lseek instead of fseeko/ftello so we only depend on * low-level syscall wrappers (available in both glibc and musl). */ #include <unistd.h> #include <stdint.h> #undef fseeko64 #undef ftello64 int fseeko64(FILE *stream, off_t offset, int whence) { int fd = fileno(stream); if (fd < 0) return -1; return lseek(fd, offset, whence) == (off_t)-1 ? -1 : 0; } off_t ftello64(FILE *stream) { int fd = fileno(stream); if (fd < 0) return -1; return lseek(fd, 0, SEEK_CUR); } /* glibc internal singleton: always single-threaded in our static binary */ int __libc_single_threaded = 1; /* __cxa_thread_atexit_impl -- thread-local destructors */ struct cxa_atexit_entry { void (*dtor)(void *); void *obj; struct cxa_atexit_entry *next; }; static __thread struct cxa_atexit_entry *atexit_list = NULL; static void run_cxa_dtors(void *unused) { (void)unused; struct cxa_atexit_entry *e = atexit_list; while (e) { struct cxa_atexit_entry *next = e->next; e->dtor(e->obj); free(e); e = next; } atexit_list = NULL; } static pthread_once_t dtor_key_once = PTHREAD_ONCE_INIT; static pthread_key_t dtor_key; static void make_dtor_key(void) { pthread_key_create(&dtor_key, run_cxa_dtors); } /* C23 strtoul/strtoll (glibc 2.38+ provides __isoc23_*; musl lacks it) */ unsigned long __isoc23_strtoul(const char *nptr, char **endptr, int base) { return strtoul(nptr, endptr, base); } long long __isoc23_strtoll(const char *nptr, char **endptr, int base) { return strtoll(nptr, endptr, base); } /* wmemset fortified */ wchar_t *__wmemset_chk(wchar_t *s, wchar_t c, size_t n, size_t destlen) { (void)destlen; return wmemset(s, c, n); } /* Additional fortified functions from glibc's libstdc++.a */ int __fprintf_chk(FILE *stream, int flag, const char *format, ...) { (void)flag; int r; va_list ap; va_start(ap, format); r = vfprintf(stream, format, ap); va_end(ap); return r; } int __snprintf_chk(char *s, size_t n, int flag, size_t slen, const char *format, ...) { (void)flag; (void)slen; int r; va_list ap; va_start(ap, format); r = vsnprintf(s, n, format, ap); va_end(ap); return r; } int __sprintf_chk(char *s, int flag, size_t slen, const char *format, ...) { (void)flag; (void)slen; int r; va_list ap; va_start(ap, format); r = vsnprintf(s, SIZE_MAX, format, ap); va_end(ap); return r; } /* More fortified string functions */ char *__strncpy_chk(char *dest, const char *src, size_t n, size_t destlen) { (void)destlen; return strncpy(dest, src, n); } void *__memmove_chk(void *dest, const void *src, size_t n, size_t destlen) { (void)destlen; return memmove(dest, src, n); } void *__memset_chk(void *s, int c, size_t n, size_t destlen) { (void)destlen; return memset(s, c, n); } int __cxa_thread_atexit_impl(void (*dtor)(void *), void *obj, void *dso_handle) { (void)dso_handle; struct cxa_atexit_entry *e = malloc(sizeof(*e)); if (!e) return -1; e->dtor = dtor; e->obj = obj; e->next = atexit_list; atexit_list = e; pthread_once(&dtor_key_once, make_dtor_key); pthread_setspecific(dtor_key, (void *)1); return 0; }