Skip to content

Commit c1083bb

Browse files
committed
[analyzer] Fix crash on compound literals with bitfields in unions
1 parent 9d3dd8e commit c1083bb

File tree

3 files changed

+103
-1
lines changed

3 files changed

+103
-1
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,9 @@ New features
227227
Crash and bug fixes
228228
^^^^^^^^^^^^^^^^^^^
229229

230+
- Fixed a crash when analyzing default bindings as compound literals in
231+
designated initializers for bitfields in unions. (#GH146050)
232+
230233
Improvements
231234
^^^^^^^^^^^^
232235

clang/lib/StaticAnalyzer/Core/RegionStore.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2187,7 +2187,10 @@ std::optional<SVal> RegionStoreManager::getBindingForDerivedDefaultValue(
21872187

21882188
// Lazy bindings are usually handled through getExistingLazyBinding().
21892189
// We should unify these two code paths at some point.
2190-
if (isa<nonloc::LazyCompoundVal, nonloc::CompoundVal>(val))
2190+
// 'nonloc::ConcreteInt' values can arise from compound literals in
2191+
// designated initializers for bitfields in unions.
2192+
if (isa<nonloc::LazyCompoundVal, nonloc::CompoundVal, nonloc::ConcreteInt>(
2193+
val))
21912194
return val;
21922195

21932196
llvm_unreachable("Unknown default value");

clang/test/Analysis/fields.c

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,102 @@ void testBitfields(void) {
113113
}
114114

115115

116+
struct BitfieldUnion {
117+
union {
118+
struct {
119+
unsigned int addr : 22;
120+
unsigned int vf : 1;
121+
};
122+
unsigned int raw;
123+
};
124+
};
125+
126+
struct BitfieldUnion processBitfieldUnion(struct BitfieldUnion r) {
127+
struct BitfieldUnion result = r;
128+
result.addr += 1;
129+
return result;
130+
}
131+
132+
void testBitfieldUnionCompoundLiteral(void) {
133+
struct BitfieldUnion r1 = processBitfieldUnion((struct BitfieldUnion){.addr = 100, .vf = 1});
134+
clang_analyzer_eval(r1.addr == 101); // expected-warning{{TRUE}}
135+
clang_analyzer_eval(r1.vf == 1); // expected-warning{{UNKNOWN}}
136+
137+
struct BitfieldUnion r2 = processBitfieldUnion((struct BitfieldUnion){.addr = 1});
138+
clang_analyzer_eval(r2.addr == 2); // expected-warning{{TRUE}}
139+
clang_analyzer_eval(r2.vf); // expected-warning{{UNKNOWN}}
140+
}
141+
142+
struct NestedBitfields {
143+
struct {
144+
unsigned x : 16;
145+
unsigned y : 16;
146+
} inner;
147+
};
148+
149+
struct NestedBitfields processNestedBitfields(struct NestedBitfields n) {
150+
struct NestedBitfields tmp = n;
151+
tmp.inner.x += 1;
152+
return tmp;
153+
}
154+
155+
void testNestedBitfields(void) {
156+
struct NestedBitfields n1 = processNestedBitfields((struct NestedBitfields){.inner.x = 1});
157+
clang_analyzer_eval(n1.inner.x == 2); // expected-warning{{TRUE}}
158+
clang_analyzer_eval(n1.inner.y == 0); // expected-warning{{TRUE}}
159+
160+
struct NestedBitfields n2 = processNestedBitfields((struct NestedBitfields){{200, 300}});
161+
clang_analyzer_eval(n2.inner.x == 201); // expected-warning{{TRUE}}
162+
clang_analyzer_eval(n2.inner.y == 300); // expected-warning{{TRUE}}
163+
}
164+
165+
struct UnionContainerBitfields {
166+
union {
167+
unsigned val;
168+
struct {
169+
unsigned x : 16;
170+
unsigned y : 16;
171+
};
172+
} u;
173+
};
174+
175+
struct UnionContainerBitfields processUnionContainer(struct UnionContainerBitfields c) {
176+
struct UnionContainerBitfields tmp = c;
177+
tmp.u.x += 1;
178+
return tmp;
179+
}
180+
181+
void testUnionContainerBitfields(void) {
182+
struct UnionContainerBitfields c1 = processUnionContainer((struct UnionContainerBitfields){.u.val = 100});
183+
clang_analyzer_eval(c1.u.x == 101); // expected-warning{{FALSE}} // expected-warning{{TRUE}}
184+
185+
struct UnionContainerBitfields c2 = processUnionContainer((struct UnionContainerBitfields){.u.x = 100});
186+
clang_analyzer_eval(c2.u.x == 101); // expected-warning{{TRUE}}
187+
}
188+
189+
struct MixedBitfields {
190+
unsigned char x;
191+
unsigned y : 12;
192+
unsigned z : 20;
193+
};
194+
195+
struct MixedBitfields processMixedBitfields(struct MixedBitfields m) {
196+
struct MixedBitfields tmp = m;
197+
tmp.y += 1;
198+
return tmp;
199+
}
200+
201+
void testMixedBitfields(void) {
202+
struct MixedBitfields m1 = processMixedBitfields((struct MixedBitfields){.x = 100, .y = 100});
203+
clang_analyzer_eval(m1.x == 100); // expected-warning{{TRUE}}
204+
clang_analyzer_eval(m1.y == 101); // expected-warning{{TRUE}}
205+
206+
struct MixedBitfields m2 = processMixedBitfields((struct MixedBitfields){.z = 100});
207+
clang_analyzer_eval(m2.y == 1); // expected-warning{{TRUE}}
208+
clang_analyzer_eval(m2.z == 100); // expected-warning{{TRUE}}
209+
}
210+
211+
116212
//-----------------------------------------------------------------------------
117213
// Incorrect behavior
118214
//-----------------------------------------------------------------------------

0 commit comments

Comments
 (0)