aboutsummaryrefslogtreecommitdiff
path: root/test/Analysis/unions.cpp
blob: f363ab81ae7259a98092b9ecc757fc1e637d207f (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
// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection %s -verify

extern void clang_analyzer_eval(bool);
extern "C" char *strdup(const char *s);

namespace PR14054_reduced {
  struct Definition;
  struct ParseNode {
    union {
      Definition *lexdef;
      ParseNode *data;
    } pn_u;
  };
  struct Definition : public ParseNode { };

  void CloneParseTree(ParseNode *opn, ParseNode *pn,  ParseNode *x) {
    // This used to cause an assertion failure because:
    // 1. The implicit operator= for unions assigns all members of the union,
    //    not just the active one (b/c there's no way to know which is active).
    // 2. RegionStore dutifully stored all the variants at the same offset;
    //    the last one won.
    // 3. We asked for the value of the first variant but got back a conjured
    //    symbol for the second variant.
    // 4. We ended up trying to add a base cast to a region of the wrong type.
    //
    // Now (at the time this test was added), we instead treat all variants of
    // a union as different offsets, but only allow one to be active at a time.
    *pn = *opn;
    x = pn->pn_u.lexdef->pn_u.lexdef;
  }
}

namespace PR14054_original {
  struct Definition;
  struct ParseNode {
    union {
      struct {
        union {};
        Definition *lexdef;
      } name;
      class {
        int *target;
        ParseNode *data;
      } xmlpi;
    } pn_u;
  };
  struct Definition : public ParseNode { };

  void CloneParseTree(ParseNode *opn, ParseNode *pn,  ParseNode *x) {
    pn->pn_u = opn->pn_u;
    x = pn->pn_u.name.lexdef->pn_u.name.lexdef;
  }
}

namespace PR17596 {
  union IntOrString {
    int i;
    char *s;
  };

  extern void process(IntOrString);

  void test() {
    IntOrString uu;
    uu.s = strdup("");
    process(uu);
  }

  void testPositive() {
    IntOrString uu;
    uu.s = strdup("");
  } // expected-warning{{leak}}

  void testCopy() {
    IntOrString uu;
    uu.i = 4;
    clang_analyzer_eval(uu.i == 4); // expected-warning{{TRUE}}

    IntOrString vv;
    vv.i = 5;
    uu = vv;
    // FIXME: Should be true.
    clang_analyzer_eval(uu.i == 5); // expected-warning{{UNKNOWN}}
  }

  void testInvalidation() {
    IntOrString uu;
    uu.s = strdup("");

    IntOrString vv;
    char str[] = "abc";
    vv.s = str;

    // FIXME: This is a leak of uu.s.
    uu = vv;
  }

  void testIndirectInvalidation() {
    IntOrString uu;
    char str[] = "abc";
    uu.s = str;

    clang_analyzer_eval(uu.s[0] == 'a'); // expected-warning{{TRUE}}

    process(uu);
    clang_analyzer_eval(uu.s[0] == 'a'); // expected-warning{{UNKNOWN}}
  }
}