This is an archive of the discontinued LLVM Phabricator instance.

[ASTMatchers] Made isExpandedFromMacro Polymorphic
ClosedPublic

Authored by njames93 on Oct 28 2020, 6:05 AM.

Details

Summary

Made the isExpandedFromMacro matcher work on Stmt's, TypeLocs and Decls in line with the other macro expansion matchers.
Also tweaked it to take a std::string instead of a StringRef.
This prevents potential use-after-free bugs if the matcher is created with a string thats destroyed before the matcher finishes matching.

Diff Detail

Event Timeline

njames93 created this revision.Oct 28 2020, 6:05 AM
Herald added a project: Restricted Project. · View Herald TranscriptOct 28 2020, 6:05 AM
Herald added a subscriber: cfe-commits. · View Herald Transcript
njames93 requested review of this revision.Oct 28 2020, 6:05 AM
aaron.ballman added inline comments.Nov 2 2020, 6:25 AM
clang/include/clang/ASTMatchers/ASTMatchers.h
313

You mentioned that the change from StringRef to std::string was to avoid lifetime issues while matching, but I'm wondering if you can expound on that situation a bit more. I would have assumed that any memoization that involves StringRef would be responsible for the lifetime issues rather than the matchers themselves, but maybe I'm thinking about a different way you can hit lifetime issues than you are.

clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
150

Can you also add a test for type-based matching?

njames93 added inline comments.Nov 2 2020, 6:20 PM
clang/include/clang/ASTMatchers/ASTMatchers.h
313

Take this as contrived, however using ASAN reports a heap-use-after-free for this code when isExpandedFromMacro takes a StringRef but works fine when using std::string.

TEST(IsExpandedFromMacro, IsExpandedFromMacro_MatchesDecls) {
  auto Matcher = isExpandedFromMacro(std::string("MY_MACRO_OVERFLOW_SMALL_STRING_SIZE"));// <-Temporary string created and destroyed here.
  StringRef input = R"cc(
#define MY_MACRO_OVERFLOW_SMALL_STRING_SIZE(a) int i = a;
    void Test() { MY_MACRO_OVERFLOW_SMALL_STRING_SIZE(4); }
  )cc";
  EXPECT_TRUE(matches(input, varDecl(Matcher))); // <- heap-use-after-free detected down the callstack from here.
}

Obviously this is very contrived to ensure asan detects the use-after-free and to ensure the temporary string is destroyed before the matcher. For these tests it doesn't look like a problem, but in other instances these matchers will outlive a string being passed to them

void addVarFromMacro(ASTMatchFinder* Finder, std::string MacroName) {
  Finder->addMatcher(varDecl(isExpandedFromMacro(MacroName)), this);
}
aaron.ballman accepted this revision.Nov 3 2020, 4:48 AM

LGTM aside from testing request.

clang/include/clang/ASTMatchers/ASTMatchers.h
313

Oh, how interesting! I can see now where the lifetime issues come in to play, thanks!

This revision is now accepted and ready to land.Nov 3 2020, 4:48 AM
This revision was landed with ongoing or failed builds.Nov 3 2020, 6:37 AM
This revision was automatically updated to reflect the committed changes.