aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMattias Andrée <m@maandree.se>2026-05-12 21:22:54 +0200
committerMattias Andrée <m@maandree.se>2026-05-12 21:22:54 +0200
commitfc0b70a60407e1e65610712a702f8286db3a328c (patch)
tree05f42c75245c1160c4bf7a7d391de7a16b109c83
parentMisc (diff)
downloadlibrecrypt-fc0b70a60407e1e65610712a702f8286db3a328c.tar.gz
librecrypt-fc0b70a60407e1e65610712a702f8286db3a328c.tar.bz2
librecrypt-fc0b70a60407e1e65610712a702f8286db3a328c.tar.xz
Work on test code
Signed-off-by: Mattias Andrée <m@maandree.se>
Diffstat (limited to '')
-rw-r--r--Makefile5
-rw-r--r--common.h6
-rw-r--r--config-coverage-gcc.mk6
-rw-r--r--librecrypt_check_settings_.c23
-rw-r--r--librecrypt_hash_.c4
-rw-r--r--librecrypt_rng_.c312
-rw-r--r--librecrypt_test_supported.c2
-rw-r--r--libtest/alloc.c124
-rw-r--r--libtest/alloc_have_custom.c14
-rw-r--r--libtest/common.h4
-rw-r--r--libtest/config.mk2
-rw-r--r--libtest/globals.c3
-rw-r--r--libtest/libtest.h19
-rw-r--r--libtest/mmap.c12
14 files changed, 454 insertions, 82 deletions
diff --git a/Makefile b/Makefile
index 68d3e4b..5f41657 100644
--- a/Makefile
+++ b/Makefile
@@ -42,8 +42,8 @@ OBJ_PUBLIC =\
OBJ_PRIVATE =\
librecrypt_algorithms_.o\
- librecrypt_hash_.o\
librecrypt_rng_.o\
+ librecrypt_hash_.o\
librecrypt_fill_with_random_.o\
librecrypt_find_first_algorithm_.o\
librecrypt_check_settings_.o\
@@ -91,7 +91,7 @@ $(TEST): $(HDR) librecrypt.a libtest/libtest.a libtest/libtest.h
$(CC) -fPIC -c -o $@ $< $(ALL_CFLAGS) $(COV_CFLAGS) $(ALL_CPPFLAGS) $(COV_CPPFLAGS)
.c.to:
- $(CC) -DTEST -c -o $@ $< $(ALL_CFLAGS) $(ALL_CPPFLAGS)
+ $(CC) -DTEST -c -o $@ $< $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(COV_CPPFLAGS)
.to.t:
$(CC) -o $@ $< librecrypt.a libtest/libtest.a $(G) $(ALL_LDFLAGS) $(TEST_LDFLAGS) $(COV_LDFLAGS)
@@ -141,6 +141,7 @@ uninstall:
-cd -- "$(DESTDIR)$(MANPREFIX)/man7/" && rm -f -- $(MAN7)
clean:
+ +cd libtest && $(MAKE) clean
-rm -f -- *.o *.a *.lo *.su *.so *.so.* *.dll *.dylib
-rm -f -- *.gch *.gcov *.gcno *.gcda *.$(LIBEXT)
-rm -f -- *.to *.t
diff --git a/common.h b/common.h
index c6bea51..6c44769 100644
--- a/common.h
+++ b/common.h
@@ -45,6 +45,11 @@
#endif
+#if defined(POSIX_CLOSE_RESTART) && !defined(__linux__)
+# define close(fd) posix_close(fd, 0)
+#endif
+
+
/**
* Used for literal commas in macro calls
*/
@@ -447,6 +452,7 @@ int librecrypt_check_settings_(const char *settings, size_t len, const char *fmt
# endif
# include <sys/resource.h>
# include <sys/types.h>
+# include <sys/uio.h>
# include <sys/wait.h>
# include <setjmp.h>
# include <signal.h>
diff --git a/config-coverage-gcc.mk b/config-coverage-gcc.mk
index c487b3a..6578f68 100644
--- a/config-coverage-gcc.mk
+++ b/config-coverage-gcc.mk
@@ -4,9 +4,9 @@ include $(CONFIGFILE_PROPER)
CC = $(CC_PREFIX)gcc -std=c99
GCOV = gcov
-CFLAGS = -g -O0
-COV_CFLAGS = --coverage
-COV_LDFLAGS = --coverage
+COV_CPPFLAGS = -DCOVERAGE_TEST
+COV_CFLAGS = --coverage -g -O0
+COV_LDFLAGS = --coverage -g -O0
G =
diff --git a/librecrypt_check_settings_.c b/librecrypt_check_settings_.c
index 16fbe7f..2c544b2 100644
--- a/librecrypt_check_settings_.c
+++ b/librecrypt_check_settings_.c
@@ -178,12 +178,16 @@ librecrypt_check_settings_(const char *settings, size_t len, const char *fmt, ..
while (*fmt) {
if (*fmt != '%') {
/* Normal literal character */
- if (i == len || settings[i++] != *fmt++)
+ if (i == len)
+ return 0;
+ if (settings[i++] != *fmt++)
return 0;
} else if (fmt[1u] == '%') {
/* '%'-escaped literal '%' ("%%") */
- if (i == len || settings[i++] != '%')
+ if (i == len)
+ return 0;
+ if (settings[i++] != '%')
return 0;
fmt = &fmt[2u];
@@ -238,12 +242,14 @@ librecrypt_check_settings_(const char *settings, size_t len, const char *fmt, ..
if (!str)
return 0;
n = strlen(str);
- if (n <= len - i && !strncmp(&settings[i], str, n)) {
- if (strout)
- *strout = str;
- i += n;
- break;
- }
+ if (n > len - i)
+ continue;
+ if (strncmp(&settings[i], str, n))
+ continue;
+ if (strout)
+ *strout = str;
+ i += n;
+ break;
}
while ((str = va_arg(args, const char *)));
goto outable_done;
@@ -647,6 +653,7 @@ main(void)
EXPECT(librecrypt_check_settings_("%", 1u, "%%") == 1);
EXPECT(librecrypt_check_settings_("%", 0u, "%%") == 0);
+ EXPECT(librecrypt_check_settings_("x", 1u, "%%") == 0);
EXPECT(librecrypt_check_settings_("hello", 5u, "%*") == 1);
EXPECT(librecrypt_check_settings_("hello$world", 11u, "%*$world") == 1);
diff --git a/librecrypt_hash_.c b/librecrypt_hash_.c
index c66d4be..dc32df1 100644
--- a/librecrypt_hash_.c
+++ b/librecrypt_hash_.c
@@ -68,8 +68,10 @@ librecrypt_hash_(char *restrict out_buffer, size_t size, const char *phrase, siz
/* Generate the salts */
r_len = librecrypt_realise_salts(out_buffer, size, settings, rng, NULL);
if (r_len < 0) {
- if (errno == ERANGE)
+ if (errno == ERANGE) {
errno = ENOMEM;
+ return -1;
+ }
return -1;
} else if ((size_t)r_len >= size) {
settings_scratch = malloc((size_t)r_len + 1u);
diff --git a/librecrypt_rng_.c b/librecrypt_rng_.c
index 3f9b9eb..f9a6cc7 100644
--- a/librecrypt_rng_.c
+++ b/librecrypt_rng_.c
@@ -96,7 +96,7 @@ librecrypt_rng_(void *out, size_t n, void *user)
/* /dev/urandom cannot be exhausted, your system
* has been compromised if this happens */
/* TODO we should probably warn the user */
- abort();
+ abort(); /* $covered$ */
}
}
@@ -128,16 +128,16 @@ no_urandom:
* allocation. A few bit's are always 0, but that's not
* a big deal. */
random_ptr = mmap(NULL, 1u, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_UNINITIALIZED, -1, 0);
- if (random_ptr != MAP_FAILED) {
+ if (random_ptr == MAP_FAILED) {
+ random_ptr = malloc(1u); /* NULL is OK (MAP_FAILED was actually also OK) */
+ random_addr = (uintptr_t)random_ptr;
+ state ^= (unsigned int)random_addr;
+ free(random_ptr);
+ } else {
random_addr = (uintptr_t)random_ptr;
state ^= (unsigned int)random_addr;
munmap(random_ptr, 1u);
- goto have_initial_seed; /* just using goto to simplify the #if'ing */
}
- random_ptr = malloc(1u); /* NULL is OK (MAP_FAILED was actually also OK) */
- random_addr = (uintptr_t)random_ptr;
- state ^= (unsigned int)random_addr;
- free(random_ptr);
have_initial_seed:
/* and always do a time-based reseed in case of multithreading,
@@ -175,6 +175,7 @@ int
(open)(const char *path, int flags, ...)
{
mode_t mode = 0;
+ va_list args;
open_calls += 1u;
@@ -186,7 +187,6 @@ int
}
if ((flags & O_CREAT) || (flags & O_TMPFILE) == O_TMPFILE) {
- va_list args;
va_start(args, flags);
mode = va_arg(args, mode_t);
va_end(args);
@@ -196,6 +196,143 @@ int
}
+static int read_error = 0;
+static size_t read_max_return = SIZE_MAX;
+
+ssize_t
+(read)(int fd, void *buf, size_t n)
+{
+ struct iovec iov;
+
+ if (n > read_max_return)
+ n = read_max_return;
+
+ if (read_error) {
+ errno = read_error;
+ if (read_error == EINTR)
+ read_error = 0;
+ return -1;
+ }
+
+ iov.iov_base = buf;
+ iov.iov_len = n;
+ return readv(fd, &iov, 1);
+}
+
+
+static int clock_gettime_error = 0;
+
+int
+(clock_gettime)(clockid_t clockid, struct timespec *tp)
+{
+ (void) clockid;
+
+ if (clock_gettime_error) {
+ errno = clock_gettime_error;
+ return -1;
+ }
+
+ memset(tp, 0, sizeof(*tp));
+ return 0;
+}
+
+
+#if defined(__linux__) && defined(AT_RANDOM)
+static int getauxval_error = 0;
+
+unsigned long
+(getauxval)(unsigned long type)
+{
+ /* We don't want to read from after the first NULL
+ * in the environment variable list provided by the
+ * kernel, because (1) this function may be executed
+ * before `main` so we cannot copy the auxiliary
+ * vector in `main` and use that, (2) if this function
+ * is executed before `main`, we don't know if
+ * environ(3) has been set up by libc, and (3) we
+ * cannot know if environ(3) is it's original pointer
+ * without addition elements when this function is
+ * executed. Therefore we use /proc/self/auxv instead. */
+
+ size_t saved_open_calls = open_calls;
+ int saved_open_error = open_error;
+ int saved_read_error = read_error;
+ size_t saved_read_max_return = read_max_return;
+ size_t *aux;
+ unsigned char buf[2u * sizeof(*aux)];
+ size_t off;
+ ssize_t r;
+ int fd;
+ unsigned long ret = 0u;
+
+ if (getauxval_error) {
+ errno = getauxval_error;
+ return 0;
+ }
+
+ open_error = 0;
+ read_error = 0;
+ read_max_return = SIZE_MAX;
+
+ fd = open("/proc/self/auxv", O_RDONLY);
+
+ if (fd < 0) {
+ errno = ENOENT;
+ goto out;
+ }
+
+ aux = (unsigned long *)buf;
+ for (off = 0u;;) {
+ r = read(fd, &buf[off], sizeof(buf) - off);
+ if (r <= 0) {
+ if (r && errno == EINTR)
+ continue;
+ errno = ENOENT;
+ goto out_close;
+ }
+ off += (size_t)r;
+ if (off < sizeof(buf))
+ continue;
+ off = 0u;
+ if (aux[0] == type)
+ break;
+ }
+
+ ret = aux[1];
+out_close:
+ close(fd);
+out:
+ open_calls = saved_open_calls;
+ open_error = saved_open_error;
+ read_error = saved_read_error;
+ read_max_return = saved_read_max_return;
+ return ret;
+}
+#endif
+
+
+static size_t rand_r_calls = 0u;
+static int rand_r_clean_seed = 0;
+
+int
+(rand_r)(unsigned int *seedp)
+{
+ int ret;
+
+ rand_r_calls += 1u;
+
+ if (*seedp)
+ srand(*seedp);
+ ret = rand();
+
+ *seedp = (unsigned int)ret;
+ if (rand_r_clean_seed)
+ *seedp = 0u;
+
+ return ret;
+}
+
+
static volatile size_t beyond_ssize_max = (size_t)SSIZE_MAX + 1u;
static void
@@ -225,8 +362,6 @@ test_oversized(void)
int
main(void)
{
- /* TODO test failure cases */
-
unsigned char buf1[1024u];
unsigned char buf2[sizeof(buf1)];
ssize_t n1, n2;
@@ -237,14 +372,26 @@ main(void)
open_calls = 0u;
+#define CHECK1()\
+ do {\
+ n1 = librecrypt_rng_(buf1, sizeof(buf1), NULL);\
+ EXPECT(n1 >= 128 && (size_t)n1 <= sizeof(buf1));\
+ EXPECT(memcmp(buf1, buf2, (size_t)(n1 < n2 ? n1 : n2)));\
+ } while (0)
+
+#define CHECK2()\
+ do {\
+ n1 = librecrypt_rng_(buf1, sizeof(buf1), NULL);\
+ n2 = librecrypt_rng_(buf2, sizeof(buf2), &user);\
+ EXPECT(n1 >= 128 && (size_t)n1 <= sizeof(buf1));\
+ EXPECT(n2 >= 128 && (size_t)n2 <= sizeof(buf2));\
+ EXPECT(memcmp(buf1, buf2, (size_t)(n1 < n2 ? n1 : n2)));\
+ } while (0)
+
/* TODO Test with output pattern (useful for other tests) */
/* Check that output is random */
- n1 = librecrypt_rng_(buf1, sizeof(buf1), NULL);
- n2 = librecrypt_rng_(buf2, sizeof(buf2), &user);
- EXPECT(n1 >= 128 && (size_t)n1 <= sizeof(buf1));
- EXPECT(n2 >= 128 && (size_t)n2 <= sizeof(buf2));
- EXPECT(memcmp(buf1, buf2, (size_t)(n1 < n2 ? n1 : n2)));
+ CHECK2();
#if defined(__linux__)
libtest_getentropy_calls = 0u;
@@ -252,9 +399,7 @@ main(void)
/* Check with short getrandom(3) */
errno = 0;
libtest_getrandom_max_return = 1u;
- n1 = librecrypt_rng_(buf1, sizeof(buf1), NULL);
- EXPECT(n1 >= 128 && (size_t)n1 <= sizeof(buf1));
- EXPECT(memcmp(buf1, buf2, (size_t)(n1 < n2 ? n1 : n2)));
+ CHECK1();
libtest_getrandom_max_return = SIZE_MAX;
EXPECT(libtest_getentropy_calls == 0u);
EXPECT(errno == 0);
@@ -262,9 +407,7 @@ main(void)
/* Check with getrandom(3) with EINTR */
errno = 0;
libtest_getrandom_error = EINTR;
- n1 = librecrypt_rng_(buf1, sizeof(buf1), NULL);
- EXPECT(n1 >= 128 && (size_t)n1 <= sizeof(buf1));
- EXPECT(memcmp(buf1, buf2, (size_t)(n1 < n2 ? n1 : n2)));
+ CHECK1();
assert(!libtest_getrandom_error);
EXPECT(libtest_getentropy_calls == 0u);
EXPECT(errno == EINTR);
@@ -272,9 +415,7 @@ main(void)
/* Check with getrandom(3) with ENOSYS */
errno = 0;
libtest_getrandom_error = ENOSYS;
- n1 = librecrypt_rng_(buf1, sizeof(buf1), NULL);
- EXPECT(n1 >= 128 && (size_t)n1 <= sizeof(buf1));
- EXPECT(memcmp(buf1, buf2, (size_t)(n1 < n2 ? n1 : n2)));
+ CHECK1();
assert(libtest_getrandom_error == ENOSYS);
EXPECT(libtest_getentropy_calls > 0u);
libtest_getentropy_calls = 0u;
@@ -283,9 +424,7 @@ main(void)
/* Check with getrandom(3) other error */
errno = 0;
libtest_getrandom_error = EDOM;
- n1 = librecrypt_rng_(buf1, sizeof(buf1), NULL);
- EXPECT(n1 >= 128 && (size_t)n1 <= sizeof(buf1));
- EXPECT(memcmp(buf1, buf2, (size_t)(n1 < n2 ? n1 : n2)));
+ CHECK1();
assert(libtest_getrandom_error == EDOM);
EXPECT(libtest_getentropy_calls > 0u);
libtest_getentropy_calls = 0u;
@@ -295,9 +434,7 @@ main(void)
/* Check with getrandom(3) zero return */
errno = 0;
libtest_getrandom_max_return = 0u;
- n1 = librecrypt_rng_(buf1, sizeof(buf1), NULL);
- EXPECT(n1 >= 128 && (size_t)n1 <= sizeof(buf1));
- EXPECT(memcmp(buf1, buf2, (size_t)(n1 < n2 ? n1 : n2)));
+ CHECK1();
libtest_getrandom_max_return = SIZE_MAX;
EXPECT(libtest_getentropy_calls > 0u);
libtest_getentropy_calls = 0u;
@@ -310,9 +447,7 @@ main(void)
/* Check with getentropy(3) with EINTR */
errno = 0;
libtest_getentropy_error = EINTR;
- n1 = librecrypt_rng_(buf1, sizeof(buf1), NULL);
- EXPECT(n1 >= 128 && (size_t)n1 <= sizeof(buf1));
- EXPECT(memcmp(buf1, buf2, (size_t)(n1 < n2 ? n1 : n2)));
+ CHECK1();
assert(!libtest_getentropy_error);
EXPECT(libtest_getentropy_calls > 0u);
libtest_getentropy_calls = 0u;
@@ -321,9 +456,7 @@ main(void)
/* Check with getentropy(3) with ENOSYS */
errno = 0;
libtest_getentropy_error = ENOSYS;
- n1 = librecrypt_rng_(buf1, sizeof(buf1), NULL);
- EXPECT(n1 >= 128 && (size_t)n1 <= sizeof(buf1));
- EXPECT(memcmp(buf1, buf2, (size_t)(n1 < n2 ? n1 : n2)));
+ CHECK1();
assert(libtest_getentropy_error == ENOSYS);
EXPECT(libtest_getentropy_calls > 0u);
libtest_getentropy_calls = 0u;
@@ -332,9 +465,7 @@ main(void)
/* Check with getentropy(3) other error */
errno = 0;
libtest_getentropy_error = EDOM;
- n1 = librecrypt_rng_(buf1, sizeof(buf1), NULL);
- EXPECT(n1 >= 128 && (size_t)n1 <= sizeof(buf1));
- EXPECT(memcmp(buf1, buf2, (size_t)(n1 < n2 ? n1 : n2)));
+ CHECK1();
assert(libtest_getentropy_error == EDOM);
EXPECT(libtest_getentropy_calls > 0u);
libtest_getentropy_calls = 0u;
@@ -345,54 +476,108 @@ main(void)
assert(open_calls > 0u);
open_calls = 0u;
errno = 0;
- n1 = librecrypt_rng_(buf1, sizeof(buf1), NULL);
- n2 = librecrypt_rng_(buf2, sizeof(buf2), &user);
- EXPECT(n1 >= 128 && (size_t)n1 <= sizeof(buf1));
- EXPECT(n2 >= 128 && (size_t)n2 <= sizeof(buf2));
- EXPECT(memcmp(buf1, buf2, (size_t)(n1 < n2 ? n1 : n2)));
+ CHECK2();
EXPECT(libtest_getentropy_calls > 0u);
libtest_getentropy_calls = 0u;
EXPECT(errno == 0);
libtest_getentropy_real = 1;
EXPECT(open_calls == 0u);
- /* TODO Check with getentropy(3) with small buffer */
+ /* Check with getentropy(3) with small buffer */
+ n1 = librecrypt_rng_(buf1, 64u, NULL);
+ EXPECT(n1 == 64u);
+ EXPECT(memcmp(buf1, buf2, (size_t)(n1 < n2 ? n1 : n2)));
/* Don't use getentropy(3) for reminder of the test */
libtest_getentropy_error = ENOSYS;
/* Check with urandom(4) */
+ rand_r_calls = 0;
errno = 0;
- n1 = librecrypt_rng_(buf1, sizeof(buf1), NULL);
- n2 = librecrypt_rng_(buf2, sizeof(buf2), &user);
- EXPECT(n1 >= 128 && (size_t)n1 <= sizeof(buf1));
- EXPECT(n2 >= 128 && (size_t)n2 <= sizeof(buf2));
- EXPECT(memcmp(buf1, buf2, (size_t)(n1 < n2 ? n1 : n2)));
+ CHECK2();
EXPECT(errno == 0);
- /* TODO check that rand(3) was not called */
+ EXPECT(rand_r_calls == 0u);
/* Check with urandom(4) not available */
open_calls = 0;
open_error = ENOENT;
- n1 = librecrypt_rng_(buf1, sizeof(buf1), NULL);
- n2 = librecrypt_rng_(buf2, sizeof(buf2), &user);
- EXPECT(n1 >= 128 && (size_t)n1 <= sizeof(buf1));
- EXPECT(n2 >= 128 && (size_t)n2 <= sizeof(buf2));
- EXPECT(memcmp(buf1, buf2, (size_t)(n1 < n2 ? n1 : n2)));
+ CHECK2();
assert(open_error == ENOENT);
open_error = 0;
EXPECT(open_calls > 0u);
- /* TODO Check with urandom(4) read(3) EINTR */
- /* TODO Check with urandom(4) read(3) EIO */
- /* TODO Check with urandom(4) read(3) exhaustion */
+ /* Check with urandom(4) read(3) failure */
+ read_error = EBADF;
+ errno = 0;
+ CHECK1();
+ EXPECT(errno == 0);
+ assert(read_error == EBADF);
+ read_error = 0;
+
+ /* Check with urandom(4) read(3) EINTR */
+ read_error = EINTR;
+ errno = 0;
+ CHECK1();
+ EXPECT(errno == EINTR);
+ assert(read_error == 0);
+
+ /* Check with urandom(4) short read(3) */
+ read_max_return = 1u;
+ CHECK1();
+ assert(read_max_return == 1u);
+ read_max_return = SIZE_MAX;
+
+ /* Check with urandom(4) read(3) exhaustion */
+ read_max_return = 0u;
+ EXPECT_ABORT(n1 = librecrypt_rng_(buf1, sizeof(buf1), NULL));
+ read_max_return = SIZE_MAX;
/* Don't use urandom(4) for reminder of the test */
open_error = ENOENT;
- /* TODO Check with rand(3) */
- /* TODO Check with mmap(3) failure */
- /* TODO Check with clock_gettime(3) failure */
+ rand_r_clean_seed = 1;
+
+ /* Check with rand(3) */
+ rand_r_calls = 0u;
+ errno = 0;
+ CHECK2();
+ EXPECT(errno == 0);
+ assert(rand_r_calls > 0u);
+
+#if defined(__linux__) && defined(AT_RANDOM)
+ getauxval_error = ENOENT;
+
+ /* Check with getauxval(3) failure */
+ assert(getauxval(AT_RANDOM) == 0u);
+ assert(getauxval_error == ENOENT);
+ errno = 0;
+ CHECK1();
+ EXPECT(errno == 0);
+#endif
+
+ /* Check with mmap(3) failure */
+ if (libtest_have_custom_mmap()) {
+ libtest_set_alloc_failure_in(1u);
+ errno = 0;
+ CHECK1();
+ EXPECT(errno == 0);
+ assert(libtest_get_alloc_failure_in() == 0u);
+ }
+
+#if defined(__linux__) && defined(AT_RANDOM)
+ getauxval_error = 0;
+#endif
+
+ /* Check with clock_gettime(3) failure */
+ clock_gettime_error = EDOM;
+ errno = 0;
+ CHECK1();
+ EXPECT(errno == 0);
+ EXPECT(clock_gettime_error == EDOM);
+ clock_gettime_error = 0;
+
+ assert(rand_r_clean_seed == 1);
+ rand_r_clean_seed = 0;
/* Check zero-request */
errno = 0;
@@ -401,6 +586,9 @@ main(void)
test_oversized();
+ /* So that gcov can report coverage */
+ open_error = 0;
+
STOP_RESOURCE_TEST();
return 0;
}
diff --git a/librecrypt_test_supported.c b/librecrypt_test_supported.c
index 520ab68..db9f302 100644
--- a/librecrypt_test_supported.c
+++ b/librecrypt_test_supported.c
@@ -9,7 +9,7 @@ librecrypt_test_supported(const char *phrase, size_t len, int text, const char *
const struct algorithm *algo;
size_t n;
- /* For each chained algorithm*/
+ /* For each chained algorithm */
for (;;) {
/* Measure until next '>' */
for (n = 0u; settings[n]; n++)
diff --git a/libtest/alloc.c b/libtest/alloc.c
index 7752091..f89ba94 100644
--- a/libtest/alloc.c
+++ b/libtest/alloc.c
@@ -427,6 +427,121 @@ void *
}
+int
+libtest_check_custom_mmap(void)
+{
+ static _Thread_local int in_check_custom_mmap = 0;
+ char *volatile test_dummy = NULL;
+
+ if (in_check_custom_mmap)
+ return libtest_mmap_is_custom;
+ in_check_custom_mmap = 1;
+
+ if (libtest_mmap_is_custom >= 0 &&
+ libtest_mremap_is_custom >= 0 &&
+ libtest_munmap_is_custom >= 0) {
+ if (libtest_mmap_is_custom & libtest_mremap_is_custom & libtest_munmap_is_custom)
+ goto custom;
+ goto real_deallocated;
+ }
+
+ test_dummy = mmap(NULL, 1u, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ assert(test_dummy != MAP_FAILED);
+ assert(test_dummy != NULL);
+ *test_dummy = 0;
+
+ if (libtest_mmap_is_custom == 0)
+ goto real;
+
+ if (libtest_mremap_is_custom < 0) {
+ test_dummy = mremap(test_dummy, 1u, 1u, MREMAP_MAYMOVE);
+ assert(test_dummy != MAP_FAILED);
+ assert(test_dummy != NULL);
+ }
+ if (libtest_mremap_is_custom == 0)
+ goto real;
+
+ if (libtest_munmap_is_custom < 0)
+ assert(!munmap(test_dummy, 1u));
+ if (libtest_munmap_is_custom == 0)
+ goto real_deallocated;
+
+custom:
+ in_check_custom_mmap = 0;
+ return 1;
+
+real:
+ assert(!munmap(test_dummy, 1u));
+real_deallocated:
+ in_check_custom_mmap = 0;
+ libtest_mmap_is_custom = 0;
+ libtest_mremap_is_custom = 0;
+ libtest_munmap_is_custom = 0;
+ return 0;
+}
+
+
+void *
+(mmap)(void *addr, size_t len, int prot, int flags, int fd, off_t off)
+{
+ /* TODO implement tracking */
+
+ libtest_mmap_is_custom = 1;
+ if (!libtest_check_custom_mmap())
+ goto real;
+
+ if (!libtest_malloc_internal_usage) {
+ if (libtest_malloc_fail_in && !--libtest_malloc_fail_in) {
+ errno = ENOMEM;
+ return MAP_FAILED;
+ }
+ }
+
+real:
+ return libtest_real_mmap(addr, len, prot, flags, fd, off);
+}
+
+
+int
+(munmap)(void *addr, size_t len)
+{
+ libtest_munmap_is_custom = 1;
+ if (!libtest_check_custom_mmap())
+ goto real;
+
+real:
+ return libtest_real_munmap(addr, len);
+}
+
+
+void *
+(mremap)(void *old_addr, size_t old_len, size_t new_len, int flags, ...)
+{
+ va_list args;
+ void *new_addr = NULL;
+
+ if (flags & MREMAP_FIXED) {
+ va_start(args, flags);
+ new_addr = va_arg(args, void *);
+ va_end(args);
+ }
+
+ libtest_mremap_is_custom = 1;
+ if (!libtest_check_custom_mmap())
+ goto real;
+
+ if (!libtest_malloc_internal_usage) {
+ if (libtest_malloc_fail_in && !--libtest_malloc_fail_in) {
+ errno = ENOMEM;
+ return MAP_FAILED;
+ }
+ }
+
+real:
+ return libtest_real_mremap(old_addr, old_len, new_len, flags, new_addr);
+}
+
#else
@@ -454,6 +569,9 @@ char *(strndup)(const char *s, size_t n);
wchar_t *(wcsdup)(const wchar_t *s);
wchar_t *(wcsndup)(const wchar_t *s, size_t n);
void *(memdup)(const void *s, size_t n);
+void *(mmap)(void *addr, size_t len, int prot, int flags, int fd, off_t off);
+int (munmap)(void *addr, size_t len);
+void *(mremap)(void *old_addr, size_t old_len, size_t new_len, int flags, ...);
static void
@@ -599,6 +717,8 @@ check(int use_free)
free(p);
else
free_aligned_sized(p, sizeof(void *), 11u);
+
+ /* TODO mmap, munmap, mremap */
}
@@ -696,6 +816,8 @@ check_successfuls(void)
assert(GET_MEMINFO(w)->requested_alloc_size == 3u * sizeof(wchar_t));
EXPECT(!memcmp(w, (wchar_t[]){11, 22, 0}, 3u * sizeof(wchar_t)));
free(w);
+
+ /* TODO mmap, munmap, mremap */
}
@@ -802,6 +924,8 @@ check_failures(void)
EXPECT(!memdup("x", 1u));
EXPECT(errno == ENOMEM);
EXPECT(!libtest_get_alloc_failure_in());
+
+ /* TODO mmap, munmap, mremap */
}
diff --git a/libtest/alloc_have_custom.c b/libtest/alloc_have_custom.c
index 9c213bb..0800e5e 100644
--- a/libtest/alloc_have_custom.c
+++ b/libtest/alloc_have_custom.c
@@ -26,6 +26,9 @@ char *(strndup)(const char *s, size_t n);
wchar_t *(wcsdup)(const wchar_t *s);
wchar_t *(wcsndup)(const wchar_t *s, size_t n);
void *(memdup)(const void *s, size_t n);
+void *(mmap)(void *addr, size_t len, int prot, int flags, int fd, off_t off);
+int (munmap)(void *addr, size_t len);
+void *(mremap)(void *old_addr, size_t old_len, size_t new_len, int flags, ...);
#if defined(__GNUC__)
# pragma GCC diagnostic pop
@@ -210,6 +213,16 @@ libtest_have_custom_free_aligned_sized(void)
}
+int
+libtest_have_custom_mmap(void)
+{
+ static int r = -1;
+ if (r < 0)
+ r = libtest_check_custom_mmap();
+ return r;
+}
+
+
#else
@@ -243,6 +256,7 @@ main(void)
CHECK(libtest_have_custom_wcsdup);
CHECK(libtest_have_custom_wcsndup);
CHECK(libtest_have_custom_memdup);
+ CHECK(libtest_have_custom_mmap);
return 0;
}
diff --git a/libtest/common.h b/libtest/common.h
index b78b69d..8d22b5b 100644
--- a/libtest/common.h
+++ b/libtest/common.h
@@ -147,6 +147,9 @@ extern volatile int libtest_strndup_is_custom;
extern volatile int libtest_wcsdup_is_custom;
extern volatile int libtest_wcsndup_is_custom;
extern volatile int libtest_memdup_is_custom;
+extern volatile int libtest_mmap_is_custom;
+extern volatile int libtest_munmap_is_custom;
+extern volatile int libtest_mremap_is_custom;
extern struct meminfo libtest_allocs_head;
extern struct meminfo libtest_allocs_tail;
@@ -174,6 +177,7 @@ libtest_base_pointer(void *ptr)
HIDDEN size_t libtest_get_pagesize(void);
HIDDEN void *libtest_alloc(struct meminfo *);
HIDDEN void libtest_free(void *, enum libtest_zero_check);
+HIDDEN int libtest_check_custom_mmap(void);
#ifdef WITH_BACKTRACE
HIDDEN void libtest_print_backtrace(FILE *, const char *prefix, const char *indent,
diff --git a/libtest/config.mk b/libtest/config.mk
index aa20790..6dff8a9 100644
--- a/libtest/config.mk
+++ b/libtest/config.mk
@@ -1,5 +1,5 @@
WITH_BACKTRACE = true
-IMPLEMENT_MMAP = false
+IMPLEMENT_MMAP = true
TEST_CONFIGFILE = config_backtraces=$(WITH_BACKTRACE).mk
include $(TEST_INCLUDE_PREFIX)$(TEST_CONFIGFILE)
diff --git a/libtest/globals.c b/libtest/globals.c
index 430f037..cf8164e 100644
--- a/libtest/globals.c
+++ b/libtest/globals.c
@@ -21,6 +21,9 @@ volatile int libtest_strndup_is_custom = -1;
volatile int libtest_wcsdup_is_custom = -1;
volatile int libtest_wcsndup_is_custom = -1;
volatile int libtest_memdup_is_custom = -1;
+volatile int libtest_mmap_is_custom = -1;
+volatile int libtest_munmap_is_custom = -1;
+volatile int libtest_mremap_is_custom = -1;
struct meminfo libtest_allocs_head;
struct meminfo libtest_allocs_tail;
diff --git a/libtest/libtest.h b/libtest/libtest.h
index 41d1a41..9fa7e56 100644
--- a/libtest/libtest.h
+++ b/libtest/libtest.h
@@ -324,6 +324,25 @@ int libtest_have_custom_free_sized(void);
*/
int libtest_have_custom_free_aligned_sized(void);
+/**
+ * Test whether mmap(3), munmap(3), and mremap(3) has
+ * been overridden, allowing allocations to be tracked,
+ * and memory allocation failures to be injected
+ *
+ * Tools like valgrind(1) prevent resource allocation
+ * functions from being overridden as they may override
+ * such functions themselves in order to detect leaks
+ * and invalid memory access patterns
+ *
+ * @return 1 if all three overridden,
+ * 0 if none have been overridden
+ *
+ * The case that only some of the three functions have
+ * been overriden, those will redirect to the real
+ * implementation and identify as non-overridden
+ */
+int libtest_have_custom_mmap(void);
+
/**
* Print a stack trace, to standard error, provided
diff --git a/libtest/mmap.c b/libtest/mmap.c
index 62ef06e..c3b3067 100644
--- a/libtest/mmap.c
+++ b/libtest/mmap.c
@@ -24,6 +24,7 @@ void *
libtest_real_mmap(void *addr, size_t len, int prot, int flags, int fd, off_t off)
{
size_t pagesize = libtest_get_pagesize();
+ uintptr_t ret;
IF_MMAP2(assert(pagesize == 4096u));
if (off < 0 || off % (off_t)pagesize)
@@ -34,10 +35,11 @@ libtest_real_mmap(void *addr, size_t len, int prot, int flags, int fd, off_t off
goto einval;
#ifdef SYS_mmap2
- return (void *)syscall(SYS_mmap2, addr, len, prot, flags, fd, off);
+ ret = (uintptr_t)syscall(SYS_mmap2, addr, len, prot, flags, fd, off);
#else
- return (void *)syscall(SYS_mmap, addr, len, prot, flags, fd, off);
+ ret = (uintptr_t)syscall(SYS_mmap, addr, len, prot, flags, fd, off);
#endif
+ return (void *)ret;
einval:
errno = EINVAL;
@@ -48,7 +50,7 @@ einval:
int
libtest_real_munmap(void *addr, size_t len)
{
- return syscall(SYS_munmap, addr, len);
+ return (int)syscall(SYS_munmap, addr, len);
}
@@ -57,6 +59,7 @@ libtest_real_mremap(void *old_addr, size_t old_len, size_t new_len, int flags, .
{
va_list args;
void *new_addr = NULL;
+ uintptr_t ret;
if (flags & MREMAP_FIXED) {
va_start(args, flags);
@@ -64,7 +67,8 @@ libtest_real_mremap(void *old_addr, size_t old_len, size_t new_len, int flags, .
va_end(args);
}
- return (void *)syscall(SYS_mremap, old_addr, old_len, new_len, flags, new_addr);
+ ret = (uintptr_t)syscall(SYS_mremap, old_addr, old_len, new_len, flags, new_addr);
+ return (void *)ret;
}