Skip to content

Commit 5e95571

Browse files
authored
[analyzer] Do not reason about locations passed as inline asm input (#103714)
If pointer is passed as input operand for inline assembly, it's possible that asm block will change memory behind this pointer. So if pointer is passed inside inline asm block, it's better to not guess and assume memory has unknown state. Without such change, we observed a lot of FP with hand-written `memcpy` and friends.
1 parent ed8cfb6 commit 5e95571

File tree

2 files changed

+39
-1
lines changed

2 files changed

+39
-1
lines changed

clang/lib/StaticAnalyzer/Core/ExprEngine.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3807,6 +3807,14 @@ void ExprEngine::VisitGCCAsmStmt(const GCCAsmStmt *A, ExplodedNode *Pred,
38073807
state = state->bindLoc(*LV, UnknownVal(), Pred->getLocationContext());
38083808
}
38093809

3810+
// Do not reason about locations passed inside inline assembly.
3811+
for (const Expr *I : A->inputs()) {
3812+
SVal X = state->getSVal(I, Pred->getLocationContext());
3813+
3814+
if (std::optional<Loc> LV = X.getAs<Loc>())
3815+
state = state->bindLoc(*LV, UnknownVal(), Pred->getLocationContext());
3816+
}
3817+
38103818
Bldr.generateNode(A, Pred, state);
38113819
}
38123820

clang/test/Analysis/asm.cpp

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
// RUN: %clang_analyze_cc1 -analyzer-checker debug.ExprInspection -fheinous-gnu-extensions -w %s -verify
1+
// RUN: %clang_analyze_cc1 -triple=x86_64-unknown-unknown \
2+
// RUN: -analyzer-checker debug.ExprInspection,core -fheinous-gnu-extensions -w %s -verify
23

34
int clang_analyzer_eval(int);
45

@@ -10,3 +11,32 @@ void testRValueOutput() {
1011
clang_analyzer_eval(global == 1); // expected-warning{{UNKNOWN}}
1112
clang_analyzer_eval(ref == 1); // expected-warning{{UNKNOWN}}
1213
}
14+
15+
void *MyMemcpy(void *d, const void *s, const int n) {
16+
asm volatile (
17+
"cld\n rep movsb\n"
18+
:: "S" (s), "D" (d), "c" (n) : "memory"
19+
);
20+
return d;
21+
}
22+
23+
void testInlineAsmMemcpy(void)
24+
{
25+
int a, b = 10, c;
26+
MyMemcpy(&a, &b, sizeof(b));
27+
c = a; // no-warning
28+
}
29+
30+
void testInlineAsmMemcpyArray(void)
31+
{
32+
int a[10], b[10] = {}, c;
33+
MyMemcpy(&a, &b, sizeof(b));
34+
c = a[8]; // no-warning
35+
}
36+
37+
void testInlineAsmMemcpyUninit(void)
38+
{
39+
int a[10], b[10] = {}, c;
40+
MyMemcpy(&a[1], &b[1], sizeof(b) - sizeof(b[1]));
41+
c = a[0]; // expected-warning{{Assigned value is garbage or undefined}}
42+
}

0 commit comments

Comments
 (0)