Skip to content

Commit

Permalink
Merged master:99d18f79646c into amd-gfx:67f09f7a0ee9
Browse files Browse the repository at this point in the history
Local branch amd-gfx 67f09f7 Merged master:30507137986a into amd-gfx:4075ffb32ad6
Remote branch master 99d18f7 Reland [IR] Intrinsics default attributes and opt-out flag
  • Loading branch information
Sw authored and Sw committed Aug 26, 2020
2 parents 67f09f7 + 99d18f7 commit e081759
Show file tree
Hide file tree
Showing 27 changed files with 507 additions and 139 deletions.
53 changes: 39 additions & 14 deletions clang-tools-extra/clangd/SemanticHighlighting.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -221,23 +221,51 @@ class HighlightingsBuilder {
// the end of the Tokens).
TokRef = TokRef.drop_front(Conflicting.size());
}
// Add tokens indicating lines skipped by the preprocessor.
for (const Range &R : AST.getMacros().SkippedRanges) {
const auto &SM = AST.getSourceManager();
StringRef MainCode = SM.getBuffer(SM.getMainFileID())->getBuffer();

// Merge token stream with "inactive line" markers.
std::vector<HighlightingToken> WithInactiveLines;
auto SortedSkippedRanges = AST.getMacros().SkippedRanges;
llvm::sort(SortedSkippedRanges);
auto It = NonConflicting.begin();
for (const Range &R : SortedSkippedRanges) {
// Create one token for each line in the skipped range, so it works
// with line-based diffing.
assert(R.start.line <= R.end.line);
for (int Line = R.start.line; Line <= R.end.line; ++Line) {
// Don't bother computing the offset for the end of the line, just use
// zero. The client will treat this highlighting kind specially, and
// highlight the entire line visually (i.e. not just to where the text
// on the line ends, but to the end of the screen).
NonConflicting.push_back({HighlightingKind::InactiveCode,
{Position{Line, 0}, Position{Line, 0}}});
// Copy tokens before the inactive line
for (; It != NonConflicting.end() && It->R.start.line < Line; ++It)
WithInactiveLines.push_back(std::move(*It));
// Add a token for the inactive line itself.
auto StartOfLine = positionToOffset(MainCode, Position{Line, 0});
if (StartOfLine) {
StringRef LineText =
MainCode.drop_front(*StartOfLine).take_until([](char C) {
return C == '\n';
});
WithInactiveLines.push_back(
{HighlightingKind::InactiveCode,
{Position{Line, 0},
Position{Line, static_cast<int>(lspLength(LineText))}}});
} else {
elog("Failed to convert position to offset: {0}",
StartOfLine.takeError());
}

// Skip any other tokens on the inactive line. e.g.
// `#ifndef Foo` is considered as part of an inactive region when Foo is
// defined, and there is a Foo macro token.
// FIXME: we should reduce the scope of the inactive region to not
// include the directive itself.
while (It != NonConflicting.end() && It->R.start.line == Line)
++It;
}
}
// Re-sort the tokens because that's what the diffing expects.
llvm::sort(NonConflicting);
return NonConflicting;
// Copy tokens after the last inactive line
for (; It != NonConflicting.end(); ++It)
WithInactiveLines.push_back(std::move(*It));
return WithInactiveLines;
}

private:
Expand Down Expand Up @@ -493,9 +521,6 @@ toSemanticTokens(llvm::ArrayRef<HighlightingToken> Tokens) {
std::vector<SemanticToken> Result;
const HighlightingToken *Last = nullptr;
for (const HighlightingToken &Tok : Tokens) {
// FIXME: support inactive code - we need to provide the actual bounds.
if (Tok.Kind == HighlightingKind::InactiveCode)
continue;
Result.emplace_back();
SemanticToken &Out = Result.back();
// deltaStart/deltaLine are relative if possible.
Expand Down
24 changes: 12 additions & 12 deletions clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -503,11 +503,11 @@ TEST(SemanticHighlighting, GetsCorrectTokens) {
#define $Macro[[test]]
#undef $Macro[[test]]
$InactiveCode[[]] #ifdef $Macro[[test]]
$InactiveCode[[]] #endif
$InactiveCode[[#ifdef test]]
$InactiveCode[[#endif]]
$InactiveCode[[]] #if defined($Macro[[test]])
$InactiveCode[[]] #endif
$InactiveCode[[#if defined(test)]]
$InactiveCode[[#endif]]
)cpp",
R"cpp(
struct $Class[[S]] {
Expand Down Expand Up @@ -614,26 +614,26 @@ TEST(SemanticHighlighting, GetsCorrectTokens) {
R"cpp(
// Code in the preamble.
// Inactive lines get an empty InactiveCode token at the beginning.
$InactiveCode[[]] #ifdef $Macro[[test]]
$InactiveCode[[]] #endif
$InactiveCode[[#ifdef test]]
$InactiveCode[[#endif]]
// A declaration to cause the preamble to end.
int $Variable[[EndPreamble]];
// Code after the preamble.
// Code inside inactive blocks does not get regular highlightings
// because it's not part of the AST.
$InactiveCode[[]] #ifdef $Macro[[test]]
$InactiveCode[[]] int Inactive2;
$InactiveCode[[]] #endif
$InactiveCode[[#ifdef test]]
$InactiveCode[[int Inactive2;]]
$InactiveCode[[#endif]]
#ifndef $Macro[[test]]
int $Variable[[Active1]];
#endif
$InactiveCode[[]] #ifdef $Macro[[test]]
$InactiveCode[[]] int Inactive3;
$InactiveCode[[]] #else
$InactiveCode[[#ifdef test]]
$InactiveCode[[int Inactive3;]]
$InactiveCode[[#else]]
int $Variable[[Active2]];
#endif
)cpp",
Expand Down
4 changes: 2 additions & 2 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -698,7 +698,7 @@ def emit_ast : Flag<["-"], "emit-ast">,
def emit_llvm : Flag<["-"], "emit-llvm">, Flags<[CC1Option]>, Group<Action_Group>,
HelpText<"Use the LLVM representation for assembler and object files">;
def emit_interface_stubs : Flag<["-"], "emit-interface-stubs">, Flags<[CC1Option]>, Group<Action_Group>,
HelpText<"Generate Inteface Stub Files.">;
HelpText<"Generate Interface Stub Files.">;
def emit_merged_ifs : Flag<["-"], "emit-merged-ifs">,
Flags<[CC1Option]>, Group<Action_Group>,
HelpText<"Generate Interface Stub Files, emit merged text not binary.">;
Expand Down Expand Up @@ -1809,7 +1809,7 @@ def fstack_protector : Flag<["-"], "fstack-protector">, Group<f_Group>,
"This uses a loose heuristic which considers functions vulnerable if they "
"contain a char (or 8bit integer) array or constant sized calls to alloca "
", which are of greater size than ssp-buffer-size (default: 8 bytes). All "
"variable sized calls to alloca are considered vulnerable. A function with"
"variable sized calls to alloca are considered vulnerable. A function with "
"a stack protector has a guard value added to the stack frame that is "
"checked on function exit. The guard value must be positioned in the "
"stack frame such that a buffer overflow from a vulnerable variable will "
Expand Down
92 changes: 88 additions & 4 deletions clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ namespace {
class SmartPtrModeling
: public Checker<eval::Call, check::DeadSymbols, check::RegionChanges> {

bool isNullAfterMoveMethod(const CallEvent &Call) const;
bool isAssignOpMethod(const CallEvent &Call) const;

public:
// Whether the checker should model for null dereferences of smart pointers.
Expand All @@ -57,6 +57,7 @@ class SmartPtrModeling
void handleRelease(const CallEvent &Call, CheckerContext &C) const;
void handleSwap(const CallEvent &Call, CheckerContext &C) const;
void handleGet(const CallEvent &Call, CheckerContext &C) const;
bool handleAssignOp(const CallEvent &Call, CheckerContext &C) const;

using SmartPtrMethodHandlerFn =
void (SmartPtrModeling::*)(const CallEvent &Call, CheckerContext &) const;
Expand Down Expand Up @@ -123,7 +124,7 @@ static ProgramStateRef updateSwappedRegion(ProgramStateRef State,
return State;
}

bool SmartPtrModeling::isNullAfterMoveMethod(const CallEvent &Call) const {
bool SmartPtrModeling::isAssignOpMethod(const CallEvent &Call) const {
// TODO: Update CallDescription to support anonymous calls?
// TODO: Handle other methods, such as .get() or .release().
// But once we do, we'd need a visitor to explain null dereferences
Expand All @@ -134,12 +135,11 @@ bool SmartPtrModeling::isNullAfterMoveMethod(const CallEvent &Call) const {

bool SmartPtrModeling::evalCall(const CallEvent &Call,
CheckerContext &C) const {

ProgramStateRef State = C.getState();
if (!smartptr::isStdSmartPtrCall(Call))
return false;

if (isNullAfterMoveMethod(Call)) {
if (isAssignOpMethod(Call)) {
const MemRegion *ThisR =
cast<CXXInstanceCall>(&Call)->getCXXThisVal().getAsRegion();

Expand Down Expand Up @@ -206,6 +206,9 @@ bool SmartPtrModeling::evalCall(const CallEvent &Call,
return true;
}

if (handleAssignOp(Call, C))
return true;

const SmartPtrMethodHandlerFn *Handler = SmartPtrMethodHandlers.lookup(Call);
if (!Handler)
return false;
Expand Down Expand Up @@ -374,6 +377,87 @@ void SmartPtrModeling::handleGet(const CallEvent &Call,
C.addTransition(State);
}

bool SmartPtrModeling::handleAssignOp(const CallEvent &Call,
CheckerContext &C) const {
ProgramStateRef State = C.getState();
const auto *OC = dyn_cast<CXXMemberOperatorCall>(&Call);
if (!OC)
return false;
OverloadedOperatorKind OOK = OC->getOverloadedOperator();
if (OOK != OO_Equal)
return false;
const MemRegion *ThisRegion = OC->getCXXThisVal().getAsRegion();
if (!ThisRegion)
return false;

const MemRegion *OtherSmartPtrRegion = OC->getArgSVal(0).getAsRegion();
// In case of 'nullptr' or '0' assigned
if (!OtherSmartPtrRegion) {
bool AssignedNull = Call.getArgSVal(0).isZeroConstant();
if (!AssignedNull)
return false;
auto NullVal = C.getSValBuilder().makeNull();
State = State->set<TrackedRegionMap>(ThisRegion, NullVal);
C.addTransition(State, C.getNoteTag([ThisRegion](PathSensitiveBugReport &BR,
llvm::raw_ostream &OS) {
if (&BR.getBugType() != smartptr::getNullDereferenceBugType() ||
!BR.isInteresting(ThisRegion))
return;
OS << "Smart pointer ";
ThisRegion->printPretty(OS);
OS << " is assigned to null";
}));
return true;
}

const auto *OtherInnerPtr = State->get<TrackedRegionMap>(OtherSmartPtrRegion);
if (OtherInnerPtr) {
State = State->set<TrackedRegionMap>(ThisRegion, *OtherInnerPtr);
auto NullVal = C.getSValBuilder().makeNull();
State = State->set<TrackedRegionMap>(OtherSmartPtrRegion, NullVal);
bool IsArgValNull = OtherInnerPtr->isZeroConstant();

C.addTransition(
State,
C.getNoteTag([ThisRegion, OtherSmartPtrRegion, IsArgValNull](
PathSensitiveBugReport &BR, llvm::raw_ostream &OS) {
if (&BR.getBugType() != smartptr::getNullDereferenceBugType())
return;
if (BR.isInteresting(OtherSmartPtrRegion)) {
OS << "Smart pointer ";
OtherSmartPtrRegion->printPretty(OS);
OS << " is null after being moved to ";
ThisRegion->printPretty(OS);
}
if (BR.isInteresting(ThisRegion) && IsArgValNull) {
OS << "Null pointer value move-assigned to ";
ThisRegion->printPretty(OS);
BR.markInteresting(OtherSmartPtrRegion);
}
}));
return true;
} else {
// In case we dont know anything about value we are moving from
// remove the entry from map for which smart pointer got moved to.
auto NullVal = C.getSValBuilder().makeNull();
State = State->remove<TrackedRegionMap>(ThisRegion);
State = State->set<TrackedRegionMap>(OtherSmartPtrRegion, NullVal);
C.addTransition(State, C.getNoteTag([OtherSmartPtrRegion,
ThisRegion](PathSensitiveBugReport &BR,
llvm::raw_ostream &OS) {
if (&BR.getBugType() != smartptr::getNullDereferenceBugType() ||
!BR.isInteresting(OtherSmartPtrRegion))
return;
OS << "Smart pointer ";
OtherSmartPtrRegion->printPretty(OS);
OS << " is null after; previous value moved to ";
ThisRegion->printPretty(OS);
}));
return true;
}
return false;
}

void ento::registerSmartPtrModeling(CheckerManager &Mgr) {
auto *Checker = Mgr.registerChecker<SmartPtrModeling>();
Checker->ModelSmartPtrDereference =
Expand Down
1 change: 1 addition & 0 deletions clang/test/Analysis/Inputs/system-header-simulator-cxx.h
Original file line number Diff line number Diff line change
Expand Up @@ -970,6 +970,7 @@ class unique_ptr {
T *operator->() const noexcept;
operator bool() const noexcept;
unique_ptr<T> &operator=(unique_ptr<T> &&p) noexcept;
unique_ptr<T> &operator=(nullptr_t) noexcept;
};

// TODO :: Once the deleter parameter is added update with additional template parameter.
Expand Down
57 changes: 48 additions & 9 deletions clang/test/Analysis/smart-ptr-text-output.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ void derefOnSwappedNullPtr() {
void derefOnStdSwappedNullPtr() {
std::unique_ptr<A> P; // expected-note {{Default constructed smart pointer 'P' is null}}
std::unique_ptr<A> PNull; // expected-note {{Default constructed smart pointer 'PNull' is null}}
std::swap(P, PNull); // expected-note@Inputs/system-header-simulator-cxx.h:978 {{Swapped null smart pointer 'PNull' with smart pointer 'P'}}
std::swap(P, PNull); // expected-note@Inputs/system-header-simulator-cxx.h:979 {{Swapped null smart pointer 'PNull' with smart pointer 'P'}}
// expected-note@-1 {{Calling 'swap<A>'}}
// expected-note@-2 {{Returning from 'swap<A>'}}
P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
Expand Down Expand Up @@ -109,14 +109,6 @@ void noNoteTagsForNonInterestingRegion() {
// expected-note@-1{{Dereference of null smart pointer 'P'}}
}

void noNoteTagsForNonMatchingBugType() {
std::unique_ptr<A> P; // No note.
std::unique_ptr<A> P1; // No note.
P1 = std::move(P); // expected-note {{Smart pointer 'P' of type 'std::unique_ptr' is reset to null when moved from}}
P->foo(); // expected-warning {{Dereference of null smart pointer 'P' of type 'std::unique_ptr' [cplusplus.Move]}}
// expected-note@-1 {{Dereference of null smart pointer 'P' of type 'std::unique_ptr'}}
}

void derefOnRawPtrFromGetOnNullPtr() {
std::unique_ptr<A> P; // FIXME: add note "Default constructed smart pointer 'P' is null"
P.get()->foo(); // expected-warning {{Called C++ object pointer is null [core.CallAndMessage]}}
Expand All @@ -131,3 +123,50 @@ void derefOnRawPtrFromGetOnValidPtr() {
void derefOnRawPtrFromGetOnUnknownPtr(std::unique_ptr<A> P) {
P.get()->foo(); // No warning.
}

void derefOnMovedFromValidPtr() {
std::unique_ptr<A> PToMove(new A()); // expected-note {{Smart pointer 'PToMove' is constructed}}
// FIXME: above note should go away once we fix marking region not interested.
std::unique_ptr<A> P;
P = std::move(PToMove); // expected-note {{Smart pointer 'PToMove' is null after being moved to 'P'}}
PToMove->foo(); // expected-warning {{Dereference of null smart pointer 'PToMove' [alpha.cplusplus.SmartPtr]}}
// expected-note@-1 {{Dereference of null smart pointer 'PToMove'}}
}

void derefOnMovedToNullPtr() {
std::unique_ptr<A> PToMove(new A());
std::unique_ptr<A> P;
P = std::move(PToMove); // No note.
P->foo(); // No warning.
}

void derefOnNullPtrGotMovedFromValidPtr() {
std::unique_ptr<A> P(new A()); // expected-note {{Smart pointer 'P' is constructed}}
// FIXME: above note should go away once we fix marking region not interested.
std::unique_ptr<A> PToMove; // expected-note {{Default constructed smart pointer 'PToMove' is null}}
P = std::move(PToMove); // expected-note {{Null pointer value move-assigned to 'P'}}
P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
// expected-note@-1 {{Dereference of null smart pointer 'P'}}
}

void derefOnMovedUnknownPtr(std::unique_ptr<A> PToMove) {
std::unique_ptr<A> P;
P = std::move(PToMove); // expected-note {{Smart pointer 'PToMove' is null after; previous value moved to 'P'}}
PToMove->foo(); // expected-warning {{Dereference of null smart pointer 'PToMove' [alpha.cplusplus.SmartPtr]}}
// expected-note@-1 {{Dereference of null smart pointer 'PToMove'}}
}

void derefOnAssignedNullPtrToNullSmartPtr() {
std::unique_ptr<A> P; // expected-note {{Default constructed smart pointer 'P' is null}}
P = nullptr; // expected-note {{Smart pointer 'P' is assigned to null}}
P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
// expected-note@-1 {{Dereference of null smart pointer 'P'}}
}

void derefOnAssignedZeroToNullSmartPtr() {
std::unique_ptr<A> P(new A()); // expected-note {{Smart pointer 'P' is constructed}}
// FIXME: above note should go away once we fix marking region not interested.
P = 0; // expected-note {{Smart pointer 'P' is assigned to null}}
P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
// expected-note@-1 {{Dereference of null smart pointer 'P'}}
}
Loading

0 comments on commit e081759

Please sign in to comment.