Skip to content
Merged
10 changes: 8 additions & 2 deletions clang/lib/StaticAnalyzer/Core/RegionStore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2658,14 +2658,20 @@ RegionStoreManager::bindArray(LimitedRegionBindingsConstRef B,
return bindAggregate(B, R, V);
}

// Handle lazy compound values.
// FIXME Single value constant should have been handled before this call to
// bindArray. This is only a hotfix to not crash.
if (Init.isConstant())
return bindAggregate(B, R, Init);

if (std::optional LCV = Init.getAs<nonloc::LazyCompoundVal>()) {
if (std::optional NewB = tryBindSmallArray(B, R, AT, *LCV))
return *NewB;

return bindAggregate(B, R, Init);
}

if (isa<nonloc::SymbolVal>(Init))
return bindAggregate(B, R, Init);

if (Init.isUnknown())
return bindAggregate(B, R, UnknownVal());

Expand Down
48 changes: 48 additions & 0 deletions clang/test/Analysis/initializer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -610,3 +610,51 @@ void top() {
consume(parseMatchComponent());
}
} // namespace elementwise_copy_small_array_from_post_initializer_of_cctor

namespace gh147686 {
// The problem reported in https://github.com/llvm/llvm-project/issues/147686
// is sensitive to the initializer form: using parenthesis to initialize m_ptr
// resulted in crashes when analyzing *m_ptr = '\0'; but using braces is fine.

struct A {
A() : m_ptr(m_buf) { *m_ptr = '\0'; } // no-crash
A(int overload) : m_ptr{m_buf} { *m_ptr = '\0'; }
A(char src) : m_ptr(m_buf) { *m_ptr = src; } // no-crash
A(char src, int overload) : m_ptr{m_buf} { *m_ptr = src; }
char m_buf[64] = {0};
char * m_ptr;
};

void test1() {
A a;
clang_analyzer_eval(a.m_buf[0] == 0); // expected-warning{{TRUE}}
// FIXME The next eval should result in TRUE.
clang_analyzer_eval(*a.m_ptr == 0); // expected-warning{{UNKNOWN}}
}

void test2() {
A a(314);
clang_analyzer_eval(a.m_buf[0] == 0); // expected-warning{{TRUE}}
clang_analyzer_eval(*a.m_ptr == 0); // expected-warning{{TRUE}}
}

void test3() {
A a(0);
clang_analyzer_eval(a.m_buf[0] == 0); // expected-warning{{TRUE}}
clang_analyzer_eval(*a.m_ptr == 0); // expected-warning{{TRUE}}
}

void test3Bis(char arg) {
A a(arg);
// FIXME This test should behave like test3.
clang_analyzer_eval(a.m_buf[0] == arg); // expected-warning{{FALSE}} // expected-warning{{TRUE}}
clang_analyzer_eval(*a.m_ptr == arg); // expected-warning{{UNKNOWN}}
}

void test4(char arg) {
A a(arg, 314);
clang_analyzer_eval(a.m_buf[0] == arg); // expected-warning{{TRUE}}
clang_analyzer_eval(*a.m_ptr == arg); // expected-warning{{TRUE}}
}

} // namespace gh147686