summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.rst30
-rw-r--r--Makefile3
-rw-r--r--libgcompat/ctype.c1
-rw-r--r--libgcompat/cxx_thread.c56
-rw-r--r--libgcompat/gnulib.c16
-rw-r--r--libgcompat/internal.c3
-rw-r--r--libgcompat/math.c13
-rw-r--r--libgcompat/readlink.c3
-rw-r--r--libgcompat/realpath.c51
-rw-r--r--libgcompat/resolv.c2
-rw-r--r--libgcompat/socket.c2
-rw-r--r--libgcompat/stdlib.c3
-rw-r--r--libgcompat/string.c9
-rw-r--r--libgcompat/unistd.c9
14 files changed, 177 insertions, 24 deletions
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index ee9851d..edc96f5 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -17,6 +17,17 @@ Build system
* Allow building against libucontext.
+ctype
+-----
+
+* Add __ctype_b.
+
+
+cxx_thread
+----------
+
+* Add __cxa_thread_atexit_impl.
+
math
----
@@ -24,6 +35,14 @@ math
* Add most __*_finite functions, courtesy of Elizabeth Myers.
+readlink/realpath
+-----------------
+
+* Intercept realpath as well as readlink.
+* Report EIO on /proc read failure.
+* Report ENOSYS on dlsym failure.
+
+
resolv
------
@@ -36,6 +55,12 @@ socket
* Add __poll_chk
+stdlib
+------
+
+* Add secure_getenv alias to __secure_getenv.
+
+
string
------
@@ -43,6 +68,11 @@ string
* Add memfrob.
* Add strfry.
+unistd
+------
+
+* Add __open_2/__open64_2.
+
malloc
------
diff --git a/Makefile b/Makefile
index 06af84f..934422f 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,8 @@
LIBGCOMPAT_INCLUDE = \
libgcompat/alias.h
LIBGCOMPAT_SRC = \
+ libgcompat/ctype.c \
+ libgcompat/cxx_thread.c \
libgcompat/dlfcn.c \
libgcompat/error.c \
libgcompat/execinfo.c \
@@ -14,6 +16,7 @@ LIBGCOMPAT_SRC = \
libgcompat/pthread.c \
libgcompat/pwd.c \
libgcompat/readlink.c \
+ libgcompat/realpath.c \
libgcompat/resolv.c \
libgcompat/resource.c \
libgcompat/setjmp.c \
diff --git a/libgcompat/ctype.c b/libgcompat/ctype.c
new file mode 100644
index 0000000..1ae9877
--- /dev/null
+++ b/libgcompat/ctype.c
@@ -0,0 +1 @@
+const unsigned short int *__ctype_b;
diff --git a/libgcompat/cxx_thread.c b/libgcompat/cxx_thread.c
new file mode 100644
index 0000000..105e4c5
--- /dev/null
+++ b/libgcompat/cxx_thread.c
@@ -0,0 +1,56 @@
+#include <pthread.h> /* NULL, pthread_{key,once,{get,set}specific} */
+#include <stdlib.h> /* malloc, free */
+
+#include "internal.h"
+
+struct dtor_node {
+ struct dtor_node *next;
+ void (*func)(void *);
+ void *obj;
+};
+
+static pthread_key_t key;
+static pthread_once_t once = PTHREAD_ONCE_INIT;
+
+static void run_dtors(void *head)
+{
+ struct dtor_node *next, *node = head;
+
+ while (node != NULL) {
+ next = node->next;
+ node->func(node->obj);
+ free(node);
+ node = next;
+ }
+}
+
+static void create_key(void)
+{
+ int res = pthread_key_create(&key, run_dtors);
+
+ GCOMPAT__assert_with_reason(res, "No key for thread_atexit list");
+}
+
+/**
+ * Register a destructor to run at thread exit.
+ *
+ * See
+ * https://sourceware.org/glibc/wiki/Destructor%20support%20for%20thread_local%20variables
+ */
+int __cxa_thread_atexit_impl(void (*func)(void *), void *obj, void *dso_symbol)
+{
+ struct dtor_node *node;
+
+ pthread_once(&once, create_key);
+
+ node = malloc(sizeof(*node));
+ GCOMPAT__assert_with_reason(node, "No memory for thread_atexit node");
+ node->next = pthread_getspecific(key);
+ node->func = func;
+ node->obj = obj;
+
+ int res = pthread_setspecific(key, node);
+ GCOMPAT__assert_with_reason(!res, "Cannot update thread_atexit list");
+
+ return 0;
+}
diff --git a/libgcompat/gnulib.c b/libgcompat/gnulib.c
index ccdec24..3f66963 100644
--- a/libgcompat/gnulib.c
+++ b/libgcompat/gnulib.c
@@ -1,16 +1,18 @@
#include <sys/select.h>
#include "internal.h"
-#define REASON_FD_SET_OVERFLOW \
- "Fault: Overflow in fd_set detected.\n" \
- "Description: This is caused by a programmer naively attempting to redefine FD_SETSIZE,\n" \
- " which is not allowed on POSIX platforms. The program must be either rebuilt\n" \
- " with the correct FD_SETSIZE definition, or preferably rewritten to avoid use\n" \
- " of select(2) in general. See also: poll(2).\n" \
+#define REASON_FD_SET_OVERFLOW \
+ "Fault: Overflow in fd_set detected.\n" \
+ "Description: This is caused by a programmer naively attempting to\n" \
+ " redefine FD_SETSIZE, which is not allowed on POSIX platforms.\n" \
+ " The program must either be rebuilt with the correct FD_SETSIZE\n" \
+ " definition, or else be rewritten to avoid use of select(2) in \n" \
+ " general. See also: poll(2).\n" \
" libgcompat believes FD_SETSIZE to be %zu.\n"
unsigned long __fdelt_chk(unsigned long size)
{
- GCOMPAT__assert_with_reason(size < FD_SETSIZE, REASON_FD_SET_OVERFLOW, FD_SETSIZE);
+ GCOMPAT__assert_with_reason(size < FD_SETSIZE, REASON_FD_SET_OVERFLOW,
+ FD_SETSIZE);
return size / (sizeof(unsigned long) << 3);
}
diff --git a/libgcompat/internal.c b/libgcompat/internal.c
index 441b3cc..450c5e4 100644
--- a/libgcompat/internal.c
+++ b/libgcompat/internal.c
@@ -1,8 +1,7 @@
-#include <stdio.h>
#include <stdarg.h>
+#include <stdio.h>
#include <stdlib.h>
-
void GCOMPAT__panic(const char *fmt, ...)
{
va_list va;
diff --git a/libgcompat/math.c b/libgcompat/math.c
index 83abbf4..793ff1a 100644
--- a/libgcompat/math.c
+++ b/libgcompat/math.c
@@ -1,8 +1,8 @@
-#define _GNU_SOURCE /* Extra maths functions */
-#include <math.h> /* Literally everything */
+#define _GNU_SOURCE /* Extra maths functions */
+#include <math.h> /* Literally everything */
-#include "alias.h" /* weak_alias */
-#include "internal.h" /* GCOMPAT__assert_with_reason */
+#include "alias.h" /* weak_alias */
+#include "internal.h" /* GCOMPAT__assert_with_reason */
/**
* Multiplies the first argument x by FLT_RADIX (probably 2) to the power of y.
@@ -14,7 +14,7 @@ long double scalbl(long double x, long double y)
* 1) Good Enough(TM)
* 2) scalbl is deprecated anyway
* */
- return scalblnl(x, (long int)y);
+ return scalblnl(x, (long int) y);
}
/*
@@ -144,7 +144,6 @@ int __isnan(double arg)
}
weak_alias(__isnan, isnan);
-
/**
* Test for a NaN.
*
@@ -290,7 +289,6 @@ long double __asinl_finite(long double x)
return res;
}
-
/**
* Returns the principal value of the arc tangent of x/y, expressed in radians.
*/
@@ -363,7 +361,6 @@ long double __atanhl_finite(long double x)
return res;
}
-
/**
* Returns the hyperbolic cosine of x.
*/
diff --git a/libgcompat/readlink.c b/libgcompat/readlink.c
index 63def96..9b3e2dd 100644
--- a/libgcompat/readlink.c
+++ b/libgcompat/readlink.c
@@ -1,4 +1,5 @@
#include <dlfcn.h>
+#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stddef.h>
@@ -18,6 +19,7 @@ ssize_t readlink(const char *path, char *buf, size_t len)
if (real_readlink == NULL) {
real_readlink = dlsym(RTLD_NEXT, "readlink");
if (real_readlink == NULL) {
+ errno = ENOSYS;
return -1;
}
}
@@ -78,6 +80,7 @@ ssize_t readlink(const char *path, char *buf, size_t len)
close(fd);
fail:
exe[0] = '\0';
+ errno = EIO;
return -1;
}
diff --git a/libgcompat/realpath.c b/libgcompat/realpath.c
new file mode 100644
index 0000000..ab68cc4
--- /dev/null
+++ b/libgcompat/realpath.c
@@ -0,0 +1,51 @@
+#include <dlfcn.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifndef LINKER
+#error LINKER must be defined
+#endif
+
+static char *(*real_realpath)(const char *restrict, char *restrict);
+
+char *realpath(const char *restrict path, char *restrict resolved)
+{
+ if (real_realpath == NULL) {
+ real_realpath = dlsym(RTLD_NEXT, "realpath");
+ if (real_realpath == NULL) {
+ errno = ENOSYS;
+ return NULL;
+ }
+ }
+
+ if (!strcmp(path, "/proc/self/exe")) {
+ char *fixed = resolved;
+
+ if (fixed == NULL) {
+ fixed = malloc(PATH_MAX);
+ if (fixed == NULL) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ }
+
+ /* If passed in, the buffer is at least PATH_MAX per POSIX. */
+ ssize_t written = readlink(path, fixed, PATH_MAX - 1);
+ if (written == -1) {
+ /* Free the buffer iff we allocated it. */
+ if (fixed != resolved)
+ free(fixed);
+ return NULL;
+ }
+ fixed[written] = '\0';
+
+ return fixed;
+ }
+
+ return real_realpath(path, resolved);
+}
diff --git a/libgcompat/resolv.c b/libgcompat/resolv.c
index f70d913..0b81d0c 100644
--- a/libgcompat/resolv.c
+++ b/libgcompat/resolv.c
@@ -42,7 +42,7 @@ int __res_nclose(res_state statp)
weak_alias(__res_nclose, res_nclose);
int __res_search(const char *dname, int class, int type, unsigned char *answer,
- int anslen)
+ int anslen)
{
return res_search(dname, class, type, answer, anslen);
}
diff --git a/libgcompat/socket.c b/libgcompat/socket.c
index 9919ee0..e56199e 100644
--- a/libgcompat/socket.c
+++ b/libgcompat/socket.c
@@ -1,6 +1,6 @@
#include <assert.h> /* assert */
+#include <poll.h> /* poll, pollfd, nfds_t */
#include <stddef.h> /* NULL */
-#include <poll.h> /* poll, pollfd, nfds_t */
#include <sys/socket.h> /* recv, recvfrom */
/**
diff --git a/libgcompat/stdlib.c b/libgcompat/stdlib.c
index a08f914..82f7602 100644
--- a/libgcompat/stdlib.c
+++ b/libgcompat/stdlib.c
@@ -5,6 +5,8 @@
#include <stdlib.h> /* getenv, realpath, strto* */
#include <unistd.h> /* get*id */
+#include "alias.h"
+
/**
* Resolve a pathname, with buffer overflow checking.
*
@@ -30,6 +32,7 @@ char *__secure_getenv(const char *name)
return getenv(name);
}
+weak_alias(__secure_getenv, secure_getenv);
/**
* Underlying function for strtod.
diff --git a/libgcompat/string.c b/libgcompat/string.c
index 9f1704b..f4e0620 100644
--- a/libgcompat/string.c
+++ b/libgcompat/string.c
@@ -2,10 +2,10 @@
#include <assert.h> /* assert */
#include <stddef.h> /* NULL, size_t */
#include <stdint.h> /* SIZE_MAX */
-#include <string.h> /* memcpy, strcpy, strncat, strndup */
#include <stdlib.h> /* rand_r */
-#include <unistd.h> /* getpid */
+#include <string.h> /* memcpy, strcpy, strncat, strndup */
#include <time.h> /* time */
+#include <unistd.h> /* getpid */
#include "alias.h" /* weak_alias */
@@ -189,8 +189,7 @@ size_t __strcspn_c2(const char *str, int bad, int bad2)
{
size_t length = 0;
const char *s = str;
- while(*s != bad && *s != bad2 && *s != '\0')
- {
+ while (*s != bad && *s != bad2 && *s != '\0') {
length++;
s++;
}
@@ -285,7 +284,7 @@ char *strfry(char *s)
if (!len)
return s;
- seed += time(NULL) ^ getpid() ^ (uintptr_t)s;
+ seed += time(NULL) ^ getpid() ^ (uintptr_t) s;
for (i = 0; i < len - 1; ++i) {
j = rand_r(&seed) % (len - i) + i;
diff --git a/libgcompat/unistd.c b/libgcompat/unistd.c
index e19ec8e..d2f3097 100644
--- a/libgcompat/unistd.c
+++ b/libgcompat/unistd.c
@@ -1,4 +1,5 @@
#include <assert.h> /* assert */
+#include <fcntl.h> /* O_CREAT */
#include <limits.h> /* NGROUPS_MAX */
#include <stddef.h> /* NULL, size_t */
#include <unistd.h> /* confstr, getcwd, getgroups, ... */
@@ -90,6 +91,14 @@ pid_t __getpgid(pid_t pid)
return getpgid(pid);
}
+int __open_2(const char *path, int oflag)
+{
+ assert(!(oflag & O_CREAT));
+
+ return open(path, oflag);
+}
+alias(__open_2, __open64_2);
+
/**
* Read from a file, with buffer overflow checking.
*