diff --git a/testing/unreliable-libc/Makefile b/testing/unreliable-libc/Makefile new file mode 100644 index 000000000..4b1a9eb57 --- /dev/null +++ b/testing/unreliable-libc/Makefile @@ -0,0 +1,25 @@ +CC = gcc +CFLAGS = -Wall -Wextra -fPIC +LDFLAGS = -shared +TARGET = unreliable-libc.so +SRCS = file.c +OBJS = $(SRCS:.c=.o) + +.PHONY: all clean + +all: $(TARGET) + +$(TARGET): $(OBJS) + $(CC) $(LDFLAGS) -o $@ $^ -ldl + +%.o: %.c + $(CC) $(CFLAGS) -c $< -o $@ + +clean: + rm -f $(OBJS) $(TARGET) + +install: $(TARGET) + install -m 755 $(TARGET) /usr/local/lib + +uninstall: + rm -f /usr/local/lib/$(TARGET) diff --git a/testing/unreliable-libc/file.c b/testing/unreliable-libc/file.c new file mode 100644 index 000000000..88f09ad90 --- /dev/null +++ b/testing/unreliable-libc/file.c @@ -0,0 +1,91 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include + +static double probabilities[] = { + [ENOSPC] = 0.01, + [EIO] = 0.01, +}; + +static bool chance(double probability) +{ + double event = drand48(); + return event < probability; +} + +static bool inject_fault(int error) +{ + double probability = probabilities[error]; + if (chance(probability)) { + errno = error; + return true; + } + errno = 0; + return false; +} + +static ssize_t (*libc_pwrite) (int, const void *, size_t, off_t); + +ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset) +{ + if (libc_pwrite == NULL) { + libc_pwrite = dlsym(RTLD_NEXT, "pwrite"); + } + if (inject_fault(ENOSPC)) { + printf("%s: injecting fault NOSPC\n", __func__); + return -1; + } + if (inject_fault(EIO)) { + printf("%s: injecting fault EIO\n", __func__); + return -1; + } + return libc_pwrite(fd, buf, count, offset); +} + +static ssize_t (*libc_pwritev) (int, const struct iovec *, int, off_t); + +ssize_t pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset) +{ + if (libc_pwritev == NULL) { + libc_pwritev = dlsym(RTLD_NEXT, "pwritev"); + } + if (inject_fault(ENOSPC)) { + printf("%s: injecting fault NOSPC\n", __func__); + return -1; + } + if (inject_fault(EIO)) { + printf("%s: injecting fault EIO\n", __func__); + return -1; + } + return libc_pwritev(fd, iov, iovcnt, offset); +} + +static int (*libc_fsync) (int); + +int fsync(int fd) +{ + if (libc_fsync == NULL) { + libc_fsync = dlsym(RTLD_NEXT, "fsync"); + } + if (inject_fault(ENOSPC)) { + printf("%s: injecting fault NOSPC\n", __func__); + return -1; + } + if (inject_fault(EIO)) { + printf("%s: injecting fault EIO\n", __func__); + return -1; + } + return libc_fsync(fd); +} + +__attribute__((constructor)) +static void init(void) +{ + srand48(time(NULL)); +}