From 2b9be10319dfc9122beb27d19df69b907ae7e28c Mon Sep 17 00:00:00 2001 From: Andreas Fertig Date: Sun, 26 Jul 2020 11:32:03 +0200 Subject: [PATCH] Fixed #333: Check for valid `SourceLocation` of attributes. Functions like `operator new` and `operator delete` carry a hidden attribute `__attribute__((visibility("default")))` which has no valid `SourceLocation` as it is inherited from the STL. This patch adds code to use only a valid `SourceLocation` to apply the offset to it to get the replacement range of the `FunctionDecl`. --- FunctionDeclHandler.cpp | 10 ++++++++-- tests/Issue333.cpp | 20 ++++++++++++++++++++ tests/Issue333.expect | 24 ++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 2 deletions(-) create mode 100644 tests/Issue333.cpp create mode 100644 tests/Issue333.expect diff --git a/FunctionDeclHandler.cpp b/FunctionDeclHandler.cpp index 76f87934..b979072b 100644 --- a/FunctionDeclHandler.cpp +++ b/FunctionDeclHandler.cpp @@ -70,8 +70,14 @@ void FunctionDeclHandler::run(const MatchFinder::MatchResult& result) // Adjust the begin location, if this decl has an attribute if(funcDecl->hasAttrs()) { - // the -3 are a guess that seems to work - funcRange.setBegin((*funcDecl->attr_begin())->getLocation().getLocWithOffset(-3)); + // Find the first attribute with a valid source-location + for(const auto& attr : funcDecl->attrs()) { + if(const auto location = attr->getLocation(); location.isValid()) { + // the -3 are a guess that seems to work + funcRange.setBegin(location.getLocWithOffset(-3)); + return funcRange; + } + } } return funcRange; diff --git a/tests/Issue333.cpp b/tests/Issue333.cpp new file mode 100644 index 00000000..a0f25df9 --- /dev/null +++ b/tests/Issue333.cpp @@ -0,0 +1,20 @@ +#include +#include + +// replacement of a minimal set of functions: +void* operator new(std::size_t sz) { + std::printf("global op new called, size = %zu\n",sz); + return std::malloc(sz); +} +void operator delete(void* ptr) noexcept +{ + std::puts("global op delete called"); + std::free(ptr); +} +int main() { + int* p1 = new int; + delete p1; + + int* p2 = new int[10]; // guaranteed to call the replacement in C++11 + delete[] p2; +} diff --git a/tests/Issue333.expect b/tests/Issue333.expect new file mode 100644 index 00000000..90045a23 --- /dev/null +++ b/tests/Issue333.expect @@ -0,0 +1,24 @@ +#include +#include + +// replacement of a minimal set of functions: +__attribute__((visibility("default"))) void * operator new(std::size_t sz) +{ + printf("global op new called, size = %zu\n", sz); + return malloc(sz); +} + +__attribute__((visibility("default"))) void operator delete(void * ptr) noexcept +{ + puts("global op delete called"); + free(ptr); +} + +int main() +{ + int * p1 = new int; + delete p1; + int * p2 = new int[10]; + delete[] p2; +} +