about summary refs log tree commit diff homepage
path: root/test/Feature/VarArgByValOld.c
blob: 011046d8350c1639240d1cccc50cd8d42fa84bb9 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
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);
}