summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorDaniel Kahn Gillmor <dkg@fifthhorseman.net>2021-03-05 21:32:12 -0500
committerDaniel Kahn Gillmor <dkg@fifthhorseman.net>2021-03-05 22:48:47 -0500
commit008d33fdf221211fa6b7ef9fe987c7e241648509 (patch)
tree3b804179d5a962c53600e7f81e78faff792b1e14 /test
parent5a0071f9524156aab9649e771d8f633a876f88ce (diff)
downloadlibfaketime-008d33fdf221211fa6b7ef9fe987c7e241648509.tar.gz
Test assumptions about variadic re-packing
This test uses the same style of re-packing variadic arguments through two layers of variadic calls, and compares that call chain against one direct variadic call. The outer function uses the same kind of re-packing used in src/libfaketime.c's syscall (leading to real_syscall), but the inner functions use different assumptions about the types of each argument. This is not an entirely comprehensive test, because we only define two different inner function signatures. If some particular syscall is breaking when intercepted, consider adding something like its expected function signature in test/variadic/inner.c, and invoke it in test/variadic/main.c. Note that we don't test any floating point types (those types are typically passed in registers in x86-64, not on the stack, and are also not used for any syscall that i'm aware of).
Diffstat (limited to 'test')
-rw-r--r--test/Makefile9
-rw-r--r--test/variadic/inner.c46
-rw-r--r--test/variadic/main.c70
-rw-r--r--test/variadic/outer.c21
4 files changed, 145 insertions, 1 deletions
diff --git a/test/Makefile b/test/Makefile
index 712c5cf..69eb6ad 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -33,6 +33,13 @@ functest:
randomtest: repeat_random
./randomtest.sh
+# ensure our variadic argument unpacking/repacking works as expected
+confirm_variadic_promotion: variadic_promotion
+ ./variadic_promotion
+variadic_promotion: variadic/main.o variadic/outer.o variadic/inner.o
+ ${CC} -o $@ ${CFLAGS} $^
+variadic/%.o: variadic/%.c
+ ${CC} -c -o $@ ${CFLAGS} $<
# run snippet tests
snippets: test_variable_data test_library_constructors
@@ -59,7 +66,7 @@ use_lib_%: _use_lib_test.c snippets/%.c lib%.so
## cleanup and metainformation
clean:
- @rm -f ${OBJ} timetest getrandom_test syscall_test $(foreach f,${TEST_SNIPPETS},use_lib_${f} lib${f}.so run_${f})
+ @rm -f ${OBJ} timetest getrandom_test syscall_test $(foreach f,${TEST_SNIPPETS},use_lib_${f} lib${f}.so run_${f}) variadic_promotion variadic/*.o
distclean: clean
@echo
diff --git a/test/variadic/inner.c b/test/variadic/inner.c
new file mode 100644
index 0000000..cc4426e
--- /dev/null
+++ b/test/variadic/inner.c
@@ -0,0 +1,46 @@
+
+#include <stdio.h>
+#include <wchar.h>
+#include <stdarg.h>
+#include <stddef.h>
+
+/* round 0: c, s, wc, i, wi */
+long inner0(char *out, ...) {
+ char c = 0;
+ short s = 0;
+ wchar_t wc = 0;
+ int i = 0;
+ wint_t wi = 0;
+
+ va_list ap;
+ va_start(ap, out);
+ c = va_arg(ap, int);
+ s = va_arg(ap, int);
+ wc = va_arg(ap, typeof(wc));
+ i = va_arg(ap, typeof(i));
+ wi = va_arg(ap, typeof(wi));
+ va_end(ap);
+
+ int ret = sprintf(out, "c: 0x%x s: 0x%x wc: 0x%lx i: 0x%x wi: 0x%x\n", c, s, (long)wc, i, wi);
+ return ret;
+}
+/* round 1: l, ll, ptr, pd, sz */
+long inner1(char *out, ...) {
+ long l = 0;
+ long long ll = 0;
+ void *ptr = NULL;
+ ptrdiff_t pd = 0;
+ size_t sz = 0;
+
+ va_list ap;
+ va_start(ap, out);
+ l = va_arg(ap, typeof(l));
+ ll = va_arg(ap, typeof(ll));
+ ptr = va_arg(ap, typeof(ptr));
+ pd = va_arg(ap, typeof(pd));
+ sz = va_arg(ap, typeof(sz));
+ va_end(ap);
+
+ int ret = sprintf(out, "l: 0x%lx ll: 0x%llx ptr: %p pd: 0x%tx sz: 0x%zx\n", l, ll, ptr, pd, sz);
+ return ret;
+}
diff --git a/test/variadic/main.c b/test/variadic/main.c
new file mode 100644
index 0000000..2ee276e
--- /dev/null
+++ b/test/variadic/main.c
@@ -0,0 +1,70 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stddef.h>
+#include <wchar.h>
+
+extern long outer(long num, char *out, ...);
+extern long inner0(char *out, ...);
+extern long inner1(char *out, ...);
+
+#define bufsize 2048
+
+static int compare_buffers(int round,
+ long ret_outer, long ret_inner,
+ const char* outer, const char* inner) {
+ int ret = 0;
+ if (ret_outer != ret_inner) {
+ printf("Round %d: return values differ (outer: %ld inner: %ld)\n", round, ret_outer, ret_inner);
+ ret++;
+ }
+ if (memcmp(outer, inner, bufsize)) {
+ printf("Round %d strings differ:\n - outer: %s\n - inner: %s\n", round, outer, inner);
+ ret++;
+ }
+ if (ret == 0)
+ printf("Round %d success: %s\n", round, outer);
+ return ret;
+}
+
+int main() {
+/* sizes of intrinsic types as reported by echo | cpp -dM | grep
+ SIZEOF, pruned to avoid floating point types. Should work with
+ both clang and gcc, not sure about other C preprocessors.
+
+ Note that we set bits in every high octet and every low octet to
+ see that they end up in the right spot.
+ */
+ char c = 0x03L;
+ short s = (0x04L << ((__SIZEOF_SHORT__ - 1) * 8)) + 0xff;
+ wchar_t wc = (0x05L << ((__SIZEOF_WCHAR_T__ - 1) * 8)) + 0xfe;
+ int i = (0x06L << ((__SIZEOF_INT__ - 1) * 8)) + 0xfd;
+ wint_t wi = (0x07L << ((__SIZEOF_WINT_T__ - 1) * 8)) + 0xfc;
+ long l = (0x08L << ((__SIZEOF_LONG__ - 1) * 8) ) + 0xfb;
+ long long ll = (0x09LL << ((__SIZEOF_LONG_LONG__ - 1) * 8)) + 0xfa;
+ void *ptr = (void*)((0x0aL << ((__SIZEOF_POINTER__ - 1) * 8)) + 0xf9);
+ ptrdiff_t pd = (0x0bL << ((__SIZEOF_PTRDIFF_T__ -1) * 8)) + 0xf9;
+ size_t sz = (0x0cL << ((__SIZEOF_SIZE_T__ - 1) * 8)) + 0xf8;
+
+ char *buf[2];
+ for (int j = 0; j < 2; j++)
+ buf[j] = malloc(bufsize);
+
+ int ret[2];
+ int errors = 0;
+
+#define reset_buffers(n) for (int j = 0; j < 2; j++) memset(buf[j], n, bufsize)
+#define check_buffers(n) errors += compare_buffers(n, ret[0], ret[1], buf[0], buf[1])
+
+ reset_buffers(0);
+ ret[0] = outer(0, buf[0], c, s, wc, i, wi);
+ ret[1] = inner0(buf[1], c, s, wc, i, wi);
+ check_buffers(0);
+
+ reset_buffers(1);
+ ret[0] = outer(1, buf[0], l, ll, ptr, pd, sz);
+ ret[1] = inner1(buf[1], l, ll, ptr, pd, sz);
+ check_buffers(1);
+
+ return (int)errors;
+}
diff --git a/test/variadic/outer.c b/test/variadic/outer.c
new file mode 100644
index 0000000..08f9dfb
--- /dev/null
+++ b/test/variadic/outer.c
@@ -0,0 +1,21 @@
+#include <stdarg.h>
+#include <time.h>
+#include "../../src/faketime_common.h"
+
+extern long inner0(char *out, ...);
+extern long inner1(char *out, ...);
+
+long outer(long num, char *out, ...) {
+ va_list ap;
+ va_start(ap, out);
+ variadic_promotion_t a[syscall_max_args];
+ for (int i = 0; i < syscall_max_args; i++)
+ a[i] = va_arg(ap, variadic_promotion_t);
+ va_end(ap);
+
+ if (num == 0)
+ return inner0(out, a[0], a[1], a[2], a[3], a[4], a[5]);
+ if (num == 1)
+ return inner1(out, a[0], a[1], a[2], a[3], a[4], a[5]);
+ else return -1;
+}