about summary refs log tree commit diff homepage
path: root/test/Feature/VarArgByValOld.c
diff options
context:
space:
mode:
Diffstat (limited to 'test/Feature/VarArgByValOld.c')
-rw-r--r--test/Feature/VarArgByValOld.c131
1 files changed, 131 insertions, 0 deletions
diff --git a/test/Feature/VarArgByValOld.c b/test/Feature/VarArgByValOld.c
new file mode 100644
index 00000000..011046d8
--- /dev/null
+++ b/test/Feature/VarArgByValOld.c
@@ -0,0 +1,131 @@
+// REQUIRES: lt-llvm-15.0
+/* This test checks that KLEE correctly handles variadic arguments with the
+   byval attribute */
+
+// RUN: %clang %s -emit-llvm %O0opt -c -g -o %t1.bc
+// RUN: rm -rf %t.klee-out
+// RUN: %klee --exit-on-error --output-dir=%t.klee-out %t1.bc
+// RUN: FileCheck %s --input-file=%t.klee-out/assembly.ll
+//
+// TODO: Make noundef unconditional when LLVM 14 is the oldest supported version.
+// CHECK: @test1({{.*}}, i32 {{(noundef )?}}-1, %struct.foo* {{(noundef )?}}byval{{.*}} %struct.bar* {{(noundef )?}}byval
+// CHECK: @test2({{.*}}, %struct.foo* {{(noundef )?}}byval{{.*}} %struct.bar* {{(noundef )?}}byval
+#include <assert.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+struct foo {
+  char f1;
+  long long f2;
+  long long f3;
+  char f4;
+  long f5;
+  int f6;
+  char f7;
+};
+
+struct bar {
+  long long int f1;
+  char f2;
+  long long f3;
+  char f4;
+  long f5;
+};
+
+struct foo test1(int x, ...) {
+  va_list ap;
+  va_start(ap, x);
+  assert(x == -1);
+
+  struct foo f = va_arg(ap, struct foo);
+  assert(f.f1 == 1);
+  assert(f.f2 == 2);
+  assert(f.f3 == 3);
+  assert(f.f4 == 4);
+  assert(f.f5 == 5);
+  assert(f.f6 == 6);
+  assert(f.f7 == 7);
+
+  struct bar b = va_arg(ap, struct bar);
+  assert(b.f1 == 11);
+  assert(b.f2 == 12);
+  assert(b.f3 == 13);
+  assert(b.f4 == 14);
+  assert(b.f5 == 15);
+
+  va_end(ap);
+
+  f.f1++;
+  return f;
+}
+
+struct foo test2(int x, long long int l, ...) {
+  va_list ap;
+  va_start(ap, l);
+  assert(x == 10);
+  assert(l == 1000);
+
+  int i = va_arg(ap, int);
+  assert(i == 10);
+
+  struct foo f = va_arg(ap, struct foo);
+  assert(f.f1 == 1);
+  assert(f.f2 == 2);
+  assert(f.f3 == 3);
+  assert(f.f4 == 4);
+  assert(f.f5 == 5);
+  assert(f.f6 == 6);
+  assert(f.f7 == 7);
+
+  l = va_arg(ap, long long int);
+  assert(l == 1000);
+
+  struct bar b = va_arg(ap, struct bar);
+  assert(b.f1 == 11);
+  assert(b.f2 == 12);
+  assert(b.f3 == 13);
+  assert(b.f4 == 14);
+  assert(b.f5 == 15);
+
+  f = va_arg(ap, struct foo);
+  assert(f.f1 == 10);
+  assert(f.f2 == 20);
+  assert(f.f3 == 30);
+  assert(f.f4 == 40);
+  assert(f.f5 == 50);
+  assert(f.f6 == 60);
+  assert(f.f7 == 70);
+
+  b = va_arg(ap, struct bar);
+  assert(b.f1 == 1);
+  assert(b.f2 == 3);
+  assert(b.f3 == 5);
+  assert(b.f4 == 7);
+  assert(b.f5 == 9);
+
+  va_end(ap);
+
+  f.f1++;
+  return f;
+}
+
+int main() {
+  struct foo f = {1, 2, 3, 4, 5, 6, 7};
+  struct bar b = {11, 12, 13, 14, 15};
+  struct foo res = test1(-1, f, b);
+  assert(res.f1 == 2);
+  assert(res.f2 == 2);
+  assert(res.f3 == 3);
+  assert(res.f4 == 4);
+  assert(res.f5 == 5);
+  assert(res.f6 == 6);
+  assert(res.f7 == 7);
+  // check that f was not modified, as it's passed by value
+  assert(f.f1 == 1);
+
+  int i = 10;
+  long long int l = 1000;
+  struct foo f2 = {10, 20, 30, 40, 50, 60, 70};
+  struct bar b2 = {1, 3, 5, 7, 9};
+  test2(i, l, i, f, l, b, f2, b2);
+}