Skip to content

Commit 0699295

Browse files
[-Wunsafe-buffer-usage] Add support for dependent values with deref
Before this change, we could only map ValueDecl to Expr to model dependent values. This change adds support for mapping ValueDecl with optional dereference to Expr. For example, this allows us to model dependent values with the following mapping: ``` count -> 42 *out_count -> 100 ``` Supporting dereference is necessary in order to check assignments to inout pointer and count in the future.
1 parent fdd38f8 commit 0699295

File tree

1 file changed

+45
-34
lines changed

1 file changed

+45
-34
lines changed

clang/lib/Analysis/UnsafeBufferUsage.cpp

Lines changed: 45 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include "clang/Lex/Preprocessor.h"
3030
#include "llvm/ADT/APInt.h"
3131
#include "llvm/ADT/APSInt.h"
32+
#include "llvm/ADT/PointerIntPair.h"
3233
#include "llvm/ADT/STLFunctionalExtras.h"
3334
#include "llvm/ADT/SmallSet.h"
3435
#include "llvm/ADT/SmallVector.h"
@@ -426,8 +427,9 @@ const Expr *findCountArg(const Expr *Count, const CallExpr *Call) {
426427
return Call->getArg(Index);
427428
}
428429

429-
// Mapping: dependent decl -> value.
430-
using DependentValuesTy = llvm::DenseMap<const ValueDecl *, const Expr *>;
430+
// Mapping: (DependentDecl, Deref) -> Value.
431+
using DeclDerefPair = llvm::PointerIntPair<const ValueDecl *, 1, bool>;
432+
using DependentValuesTy = llvm::DenseMap<DeclDerefPair, const Expr *>;
431433

432434
// Given the call expr, find the mapping from the dependent parameter to the
433435
// argument that is passed to that parameter.
@@ -445,7 +447,8 @@ getDependentValuesFromCall(const CountAttributedType *CAT,
445447
return std::nullopt;
446448

447449
const Expr *Arg = Call->getArg(Index);
448-
[[maybe_unused]] bool Inserted = Values.insert({PVD, Arg}).second;
450+
[[maybe_unused]] bool Inserted =
451+
Values.insert({{PVD, /*Deref=*/false}, Arg}).second;
449452
assert(Inserted);
450453
}
451454
return {std::move(Values)};
@@ -499,50 +502,57 @@ struct CompatibleCountExprVisitor
499502
const Expr *
500503
trySubstituteAndSimplify(const Expr *E, bool &hasBeenSubstituted,
501504
const DependentValuesTy *DependentValues) const {
505+
auto trySubstitute = [&](const ValueDecl *VD, bool Deref) -> const Expr * {
506+
if (hasBeenSubstituted || !DependentValues)
507+
return nullptr;
508+
auto It = DependentValues->find({VD, Deref});
509+
return It != DependentValues->end() ? It->second : nullptr;
510+
};
511+
502512
// Attempts to simplify `E`: if `E` has the form `*&e`, return `e`;
503513
// return `E` without change otherwise:
504-
auto trySimplifyDerefAddressof =
505-
[](const Expr *E,
506-
const DependentValuesTy
507-
*DependentValues, // Deref may need subsitution
508-
bool &hasBeenSubstituted) -> const Expr * {
514+
auto trySimplifyDeref = [&](const Expr *E) -> const Expr * {
509515
const auto *Deref = dyn_cast<UnaryOperator>(E->IgnoreParenImpCasts());
510516

511517
if (!Deref || Deref->getOpcode() != UO_Deref)
512518
return E;
513519

514520
const Expr *DerefOperand = Deref->getSubExpr()->IgnoreParenImpCasts();
515521

522+
// Just simplify `*&...`.
516523
if (const auto *UO = dyn_cast<UnaryOperator>(DerefOperand))
517524
if (UO->getOpcode() == UO_AddrOf)
518525
return UO->getSubExpr();
526+
519527
if (const auto *DRE = dyn_cast<DeclRefExpr>(DerefOperand)) {
520-
if (!DependentValues || hasBeenSubstituted)
521-
return E;
522-
523-
if (auto I = DependentValues->find(DRE->getDecl());
524-
I != DependentValues->end())
525-
if (const auto *UO = dyn_cast<UnaryOperator>(
526-
I->getSecond()->IgnoreParenImpCasts()))
527-
if (UO->getOpcode() == UO_AddrOf) {
528-
hasBeenSubstituted = true;
529-
return UO->getSubExpr();
530-
}
528+
// Substitute `*x`.
529+
if (const auto *Sub = trySubstitute(DRE->getDecl(), /*Deref=*/true)) {
530+
hasBeenSubstituted = true;
531+
return Sub;
532+
}
533+
534+
// Substitute `x` in `*x` if we have `x -> &...` in our mapping.
535+
if (const auto *Sub = trySubstitute(DRE->getDecl(), /*Deref=*/false)) {
536+
if (const auto *UO =
537+
dyn_cast<UnaryOperator>(Sub->IgnoreParenImpCasts());
538+
UO && UO->getOpcode() == UO_AddrOf) {
539+
hasBeenSubstituted = true;
540+
return UO->getSubExpr();
541+
}
542+
}
531543
}
544+
532545
return E;
533546
};
534547

535-
if (!hasBeenSubstituted && DependentValues) {
536-
if (const auto *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts())) {
537-
if (auto It = DependentValues->find(DRE->getDecl());
538-
It != DependentValues->end()) {
539-
hasBeenSubstituted = true;
540-
return trySimplifyDerefAddressof(It->second, nullptr,
541-
hasBeenSubstituted);
542-
}
548+
if (const auto *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts())) {
549+
if (const auto *Sub = trySubstitute(DRE->getDecl(), /*Deref=*/false)) {
550+
hasBeenSubstituted = true;
551+
return trySimplifyDeref(Sub);
543552
}
544553
}
545-
return trySimplifyDerefAddressof(E, DependentValues, hasBeenSubstituted);
554+
555+
return trySimplifyDeref(E);
546556
}
547557

548558
explicit CompatibleCountExprVisitor(
@@ -673,6 +683,13 @@ struct CompatibleCountExprVisitor
673683
bool hasOtherBeenSubstituted) {
674684
if (SelfUO->getOpcode() != UO_Deref)
675685
return false; // We don't support any other unary operator
686+
687+
const auto *SimplifiedSelf = trySubstituteAndSimplify(
688+
SelfUO, hasSelfBeenSubstituted, DependentValuesSelf);
689+
if (SimplifiedSelf != SelfUO)
690+
return Visit(SimplifiedSelf, Other, hasSelfBeenSubstituted,
691+
hasOtherBeenSubstituted);
692+
676693
Other = trySubstituteAndSimplify(Other, hasOtherBeenSubstituted,
677694
DependentValuesOther);
678695
if (const auto *OtherUO =
@@ -681,13 +698,7 @@ struct CompatibleCountExprVisitor
681698
return Visit(SelfUO->getSubExpr(), OtherUO->getSubExpr(),
682699
hasSelfBeenSubstituted, hasOtherBeenSubstituted);
683700
}
684-
// If `Other` is not a dereference expression, try to simplify `SelfUO`:
685-
const auto *SimplifiedSelf = trySubstituteAndSimplify(
686-
SelfUO, hasSelfBeenSubstituted, DependentValuesSelf);
687701

688-
if (SimplifiedSelf != SelfUO)
689-
return Visit(SimplifiedSelf, Other, hasSelfBeenSubstituted,
690-
hasOtherBeenSubstituted);
691702
return false;
692703
}
693704

0 commit comments

Comments
 (0)