Skip to content

Commit 8dd2846

Browse files
[analyzer] Harden RegionStoreManager::bindArray (#153177)
Fixes #147686 by handling symbolic values similarly to bindStruct and handling constant values. The latter is actually more of a workaround: bindArray should not have to deal with such constants. CPP-6688
1 parent dbf44c2 commit 8dd2846

File tree

2 files changed

+56
-2
lines changed

2 files changed

+56
-2
lines changed

clang/lib/StaticAnalyzer/Core/RegionStore.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2658,14 +2658,20 @@ RegionStoreManager::bindArray(LimitedRegionBindingsConstRef B,
26582658
return bindAggregate(B, R, V);
26592659
}
26602660

2661-
// Handle lazy compound values.
2661+
// FIXME Single value constant should have been handled before this call to
2662+
// bindArray. This is only a hotfix to not crash.
2663+
if (Init.isConstant())
2664+
return bindAggregate(B, R, Init);
2665+
26622666
if (std::optional LCV = Init.getAs<nonloc::LazyCompoundVal>()) {
26632667
if (std::optional NewB = tryBindSmallArray(B, R, AT, *LCV))
26642668
return *NewB;
2665-
26662669
return bindAggregate(B, R, Init);
26672670
}
26682671

2672+
if (isa<nonloc::SymbolVal>(Init))
2673+
return bindAggregate(B, R, Init);
2674+
26692675
if (Init.isUnknown())
26702676
return bindAggregate(B, R, UnknownVal());
26712677

clang/test/Analysis/initializer.cpp

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -610,3 +610,51 @@ void top() {
610610
consume(parseMatchComponent());
611611
}
612612
} // namespace elementwise_copy_small_array_from_post_initializer_of_cctor
613+
614+
namespace gh147686 {
615+
// The problem reported in https://github.com/llvm/llvm-project/issues/147686
616+
// is sensitive to the initializer form: using parenthesis to initialize m_ptr
617+
// resulted in crashes when analyzing *m_ptr = '\0'; but using braces is fine.
618+
619+
struct A {
620+
A() : m_ptr(m_buf) { *m_ptr = '\0'; } // no-crash
621+
A(int overload) : m_ptr{m_buf} { *m_ptr = '\0'; }
622+
A(char src) : m_ptr(m_buf) { *m_ptr = src; } // no-crash
623+
A(char src, int overload) : m_ptr{m_buf} { *m_ptr = src; }
624+
char m_buf[64] = {0};
625+
char * m_ptr;
626+
};
627+
628+
void test1() {
629+
A a;
630+
clang_analyzer_eval(a.m_buf[0] == 0); // expected-warning{{TRUE}}
631+
// FIXME The next eval should result in TRUE.
632+
clang_analyzer_eval(*a.m_ptr == 0); // expected-warning{{UNKNOWN}}
633+
}
634+
635+
void test2() {
636+
A a(314);
637+
clang_analyzer_eval(a.m_buf[0] == 0); // expected-warning{{TRUE}}
638+
clang_analyzer_eval(*a.m_ptr == 0); // expected-warning{{TRUE}}
639+
}
640+
641+
void test3() {
642+
A a(0);
643+
clang_analyzer_eval(a.m_buf[0] == 0); // expected-warning{{TRUE}}
644+
clang_analyzer_eval(*a.m_ptr == 0); // expected-warning{{TRUE}}
645+
}
646+
647+
void test3Bis(char arg) {
648+
A a(arg);
649+
// FIXME This test should behave like test3.
650+
clang_analyzer_eval(a.m_buf[0] == arg); // expected-warning{{FALSE}} // expected-warning{{TRUE}}
651+
clang_analyzer_eval(*a.m_ptr == arg); // expected-warning{{UNKNOWN}}
652+
}
653+
654+
void test4(char arg) {
655+
A a(arg, 314);
656+
clang_analyzer_eval(a.m_buf[0] == arg); // expected-warning{{TRUE}}
657+
clang_analyzer_eval(*a.m_ptr == arg); // expected-warning{{TRUE}}
658+
}
659+
660+
} // namespace gh147686

0 commit comments

Comments
 (0)