Merge "versioner: Add versioner_fortify_inline annotation"
This commit is contained in:
commit
d2b8149dda
6 changed files with 48 additions and 3 deletions
|
@ -106,6 +106,7 @@ class Visitor : public RecursiveASTVisitor<Visitor> {
|
|||
bool is_extern = named_decl->getFormalLinkage() == ExternalLinkage;
|
||||
bool is_definition = false;
|
||||
bool no_guard = false;
|
||||
bool fortify_inline = false;
|
||||
|
||||
if (auto function_decl = dyn_cast<FunctionDecl>(decl)) {
|
||||
is_definition = function_decl->isThisDeclarationADefinition();
|
||||
|
@ -147,6 +148,8 @@ class Visitor : public RecursiveASTVisitor<Visitor> {
|
|||
llvm::StringRef annotation = attr->getAnnotation();
|
||||
if (annotation == "versioner_no_guard") {
|
||||
no_guard = true;
|
||||
} else if (annotation == "versioner_fortify_inline") {
|
||||
fortify_inline = true;
|
||||
} else {
|
||||
llvm::SmallVector<llvm::StringRef, 2> fragments;
|
||||
annotation.split(fragments, "=");
|
||||
|
@ -217,7 +220,8 @@ class Visitor : public RecursiveASTVisitor<Visitor> {
|
|||
declaration_it != symbol_it->second.declarations.end()) {
|
||||
if (declaration_it->second.is_extern != is_extern ||
|
||||
declaration_it->second.is_definition != is_definition ||
|
||||
declaration_it->second.no_guard != no_guard) {
|
||||
declaration_it->second.no_guard != no_guard ||
|
||||
declaration_it->second.fortify_inline != fortify_inline) {
|
||||
errx(1, "varying declaration of '%s' at %s:%u:%u", declaration_name.c_str(),
|
||||
location.filename.c_str(), location.start.line, location.start.column);
|
||||
}
|
||||
|
@ -229,6 +233,7 @@ class Visitor : public RecursiveASTVisitor<Visitor> {
|
|||
declaration.is_extern = is_extern;
|
||||
declaration.is_definition = is_definition;
|
||||
declaration.no_guard = no_guard;
|
||||
declaration.fortify_inline = fortify_inline;
|
||||
declaration.availability.insert(std::make_pair(type, availability));
|
||||
symbol_it->second.declarations.insert(std::make_pair(location, declaration));
|
||||
}
|
||||
|
|
|
@ -127,6 +127,7 @@ struct Declaration {
|
|||
bool is_extern;
|
||||
bool is_definition;
|
||||
bool no_guard;
|
||||
bool fortify_inline;
|
||||
std::map<CompilationType, DeclarationAvailability> availability;
|
||||
|
||||
bool calculateAvailability(DeclarationAvailability* output) const;
|
||||
|
@ -143,6 +144,9 @@ struct Declaration {
|
|||
if (no_guard) {
|
||||
fprintf(out, "no_guard ");
|
||||
}
|
||||
if (fortify_inline) {
|
||||
fprintf(out, "fortify_inline ");
|
||||
}
|
||||
fprintf(out, "@ %s:%u:%u", StripPrefix(location.filename, base_path).str().c_str(),
|
||||
location.start.line, location.start.column);
|
||||
|
||||
|
|
|
@ -277,7 +277,9 @@ static std::vector<T> Intersection(const std::set<T>& a, const std::set<T>& b) {
|
|||
}
|
||||
|
||||
// Perform a sanity check on a symbol's declarations, enforcing the following invariants:
|
||||
// 1. At most one inline definition of the function exists.
|
||||
// 1. At most one inline definition of the function exists (overloaded inline functions for
|
||||
// _FORTIFY_SOURCE do not count because they are usually introduced to intercept the original
|
||||
// functions or usually have enable_if attributes).
|
||||
// 2. All of the availability declarations for a symbol are compatible.
|
||||
// If a function is declared as an inline before a certain version, the inline definition
|
||||
// should have no version tag.
|
||||
|
@ -290,7 +292,7 @@ static bool checkSymbol(const Symbol& symbol) {
|
|||
std::unordered_map<const Declaration*, std::set<CompilationType>> inline_definitions;
|
||||
for (const auto& decl_it : symbol.declarations) {
|
||||
const Declaration* decl = &decl_it.second;
|
||||
if (decl->is_definition) {
|
||||
if (decl->is_definition && !decl->fortify_inline) {
|
||||
std::set<CompilationType> compilation_types = getCompilationTypes(decl);
|
||||
for (const auto& inline_def_it : inline_definitions) {
|
||||
auto intersection = Intersection(compilation_types, inline_def_it.second);
|
||||
|
|
29
tools/versioner/tests/fortify_inline/headers/fcntl.h
Normal file
29
tools/versioner/tests/fortify_inline/headers/fcntl.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern int open_real(const char* name, int flags, ...) __asm__("open");
|
||||
|
||||
#define O_CREAT 00000100
|
||||
|
||||
typedef unsigned int mode_t;
|
||||
|
||||
static inline __attribute__((always_inline))
|
||||
int open(const char* name, int flags)
|
||||
__attribute__((annotate("versioner_fortify_inline")))
|
||||
__attribute__((overloadable))
|
||||
__attribute__((enable_if(!(flags & O_CREAT), ""))) {
|
||||
return open_real(name, flags);
|
||||
}
|
||||
|
||||
static inline __attribute__((always_inline))
|
||||
int open(const char* name, int flags, mode_t mode)
|
||||
__attribute__((annotate("versioner_fortify_inline")))
|
||||
__attribute__((overloadable))
|
||||
__attribute__((enable_if(flags & O_CREAT, ""))) {
|
||||
return open_real(name, flags, mode);
|
||||
}
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,4 @@
|
|||
LIBC {
|
||||
global:
|
||||
open;
|
||||
};
|
1
tools/versioner/tests/fortify_inline/run.sh
Normal file
1
tools/versioner/tests/fortify_inline/run.sh
Normal file
|
@ -0,0 +1 @@
|
|||
versioner headers -p platforms -r arm -a 9 -a 12 -i
|
Loading…
Reference in a new issue