-
Notifications
You must be signed in to change notification settings - Fork 12.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Sema] Mark alias/ifunc targets used and consider mangled names #87130
Changes from 2 commits
23422a0
9ae8958
3bd4297
6f2a3da
1b3847e
c3793ad
1e8d74c
fb2b988
5b85c1b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,6 @@ | ||
set(LLVM_LINK_COMPONENTS | ||
Core | ||
Demangle | ||
FrontendHLSL | ||
FrontendOpenMP | ||
MC | ||
|
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
@@ -42,6 +42,7 @@ | |||||||||
#include "clang/Sema/SemaInternal.h" | ||||||||||
#include "llvm/ADT/STLExtras.h" | ||||||||||
#include "llvm/ADT/StringExtras.h" | ||||||||||
#include "llvm/Demangle/Demangle.h" | ||||||||||
#include "llvm/IR/Assumptions.h" | ||||||||||
#include "llvm/MC/MCSectionMachO.h" | ||||||||||
#include "llvm/Support/Error.h" | ||||||||||
|
@@ -1980,6 +1981,23 @@ static void handleWeakRefAttr(Sema &S, Decl *D, const ParsedAttr &AL) { | |||||||||
D->addAttr(::new (S.Context) WeakRefAttr(S.Context, AL)); | ||||||||||
} | ||||||||||
|
||||||||||
// Mark alias/ifunc target as used. For C++, we look up the demangled name | ||||||||||
// ignoring parameters. This should handle the majority of use cases while | ||||||||||
// leaveing false positives for namespace scope names and false negatives in | ||||||||||
// the presence of overloads. | ||||||||||
static void markUsedForAliasOrIfunc(Sema &S, Decl *D, const ParsedAttr &AL, | ||||||||||
StringRef Str) { | ||||||||||
char *Demangled = llvm::itaniumDemangle(Str, /*ParseParams=*/false); | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can't really assume 'itanium demangle' here, this could be a non-itanium build. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How does one specify a "non-itanium build?" There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Triple is the only way I am aware of IIRC. So we should be checking that triple. I think There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looks like there's There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Yep, Microsoft is the exception. We DO typically use https://clang.llvm.org/doxygen/classclang_1_1TargetCXXABI.html to determine which. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
It's an error
The reported issue has nothing to do with security as all. It's about a The warning (under -Wall) becomes an error if users provide There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
If we know the target ABI uses Microsoft mangling, then we should be using There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. FWIW, I agree that we should not be assuming itanium demangling here; we definitely should care about Microsoft mangling as well because
Eh, I don't agree. Replacing false positives with false negatives can be a security concern because the false negatives could be hiding an issue. @nickdesaulniers pointed out a potential in https://github.com/llvm/llvm-project/pull/87130/files#r1546691566. (The reverse can also be true -- replacing false negatives with false positives can hide security issues because low-quality output may either cause the user to disable the diagnostic entirely or may drown out the valid issues.) Regardless, I think the direction of this patch is heading where we want it to go. But urging caution in this area is very reasonable IMO. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I added a Note: while I've also updated the description to state
This makes internal linkage target difficult to use in C++ even on Linux. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I'm not certain why there's so much resistance to doing this when three people have pointed out the concern. It still works for Windows. e.g.,
We should support it properly rather than only halfway, especially considering the context of the bug report.
nickdesaulniers marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||
if (Demangled) | ||||||||||
Str = Demangled; | ||||||||||
erichkeane marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||
const DeclarationNameInfo target(&S.Context.Idents.get(Str), AL.getLoc()); | ||||||||||
LookupResult LR(S, target, Sema::LookupOrdinaryName); | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Coding style nits |
||||||||||
if (S.LookupQualifiedName(LR, S.getCurLexicalContext())) | ||||||||||
for (NamedDecl *ND : LR) | ||||||||||
ND->markUsed(S.Context); | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This loop doesn't seem quite right either. First, we need to ensure we're only marking 'functions' as used, not all possible named decls I think. Second, we need to ensure we're doing a better job with testing, this doesn't seem to be adding enough test infrastructure to make sure we're picking up the right function. Finally, what does this mean in the case of template declarations/instantiations? We need to make sure we're marking those correctly (or not picking them up at all perhaps?). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe you can put There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "alias" can target variables. "ifunc" has an existing diagnostic to reject non-function targets.
I am adding a template test: template <class T>
static void *f3(T) { return nullptr; }
static void *f3() { return nullptr; } // expected-warning{{unused function 'f3'}}
extern void g3() __attribute__((ifunc("_ZL2f3IiEPvT_")));
void *use3 = f3(0); I think the current code does the right thing for templates because mangled names for templates contain
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Because of the nature of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've added code to check the mangled name to avoid -Wunused-function false negatives. |
||||||||||
free(Demangled); | ||||||||||
} | ||||||||||
|
||||||||||
static void handleIFuncAttr(Sema &S, Decl *D, const ParsedAttr &AL) { | ||||||||||
StringRef Str; | ||||||||||
if (!S.checkStringLiteralArgumentAttr(AL, 0, Str)) | ||||||||||
|
@@ -1992,6 +2010,7 @@ static void handleIFuncAttr(Sema &S, Decl *D, const ParsedAttr &AL) { | |||||||||
return; | ||||||||||
} | ||||||||||
|
||||||||||
markUsedForAliasOrIfunc(S, D, AL, Str); | ||||||||||
D->addAttr(::new (S.Context) IFuncAttr(S.Context, AL, Str)); | ||||||||||
} | ||||||||||
|
||||||||||
|
@@ -2026,17 +2045,7 @@ static void handleAliasAttr(Sema &S, Decl *D, const ParsedAttr &AL) { | |||||||||
} | ||||||||||
} | ||||||||||
|
||||||||||
// Mark target used to prevent unneeded-internal-declaration warnings. | ||||||||||
if (!S.LangOpts.CPlusPlus) { | ||||||||||
// FIXME: demangle Str for C++, as the attribute refers to the mangled | ||||||||||
// linkage name, not the pre-mangled identifier. | ||||||||||
const DeclarationNameInfo target(&S.Context.Idents.get(Str), AL.getLoc()); | ||||||||||
LookupResult LR(S, target, Sema::LookupOrdinaryName); | ||||||||||
if (S.LookupQualifiedName(LR, S.getCurLexicalContext())) | ||||||||||
for (NamedDecl *ND : LR) | ||||||||||
ND->markUsed(S.Context); | ||||||||||
} | ||||||||||
|
||||||||||
markUsedForAliasOrIfunc(S, D, AL, Str); | ||||||||||
D->addAttr(::new (S.Context) AliasAttr(S.Context, AL, Str)); | ||||||||||
} | ||||||||||
|
||||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,43 @@ | ||
// RUN: %clang_cc1 -triple x86_64-linux-gnu -Wunneeded-internal-declaration -x c -verify %s | ||
// RUN: %clang_cc1 -triple x86_64-linux-gnu -Wunused -x c -verify %s | ||
// RUN: %clang_cc1 -triple x86_64-linux-gnu -Wunused -x c++ -verify %s | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd like to see a non-Itanium RUN line as well. Perhaps we should be using |
||
#ifdef __cplusplus | ||
extern "C" { | ||
#else | ||
// expected-no-diagnostics | ||
#endif | ||
static int f(void) { return 42; } | ||
int g(void) __attribute__((alias("f"))); | ||
|
||
static int foo [] = { 42, 0xDEAD }; | ||
extern typeof(foo) bar __attribute__((unused, alias("foo"))); | ||
|
||
static int (*resolver(void))(void) { return f; } | ||
int ifunc(void) __attribute__((ifunc("resolver"))); | ||
|
||
#ifdef __cplusplus | ||
} | ||
|
||
/// We demangle alias/ifunc target and mark all found functions as used. | ||
/// We should report "unused function" for f1(int). | ||
static int f1(int) { return 42; } | ||
static int f1(void) { return 42; } | ||
int g1() __attribute__((alias("_ZL2f1v"))); | ||
|
||
/// We should report "unused function" for resolver1(int). | ||
static int (*resolver1(void))(void) { return f; } | ||
static int (*resolver1(int))(void) { return f; } | ||
int ifunc1() __attribute__((ifunc("_ZL9resolver1v"))); | ||
|
||
namespace ns { | ||
static int f2(int) { return 42; } // expected-warning{{unused function 'f2'}} | ||
static int f2(void) { return 42; } // expected-warning{{unused function 'f2'}} | ||
int g2() __attribute__((alias("_ZN2nsL2f2Ev"))); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why warn for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This weakness is mentioned in the description as "... does not handle namespace scope names" There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
} | ||
|
||
template <class T> | ||
static void *f3(T) { return nullptr; } | ||
static void *f3() { return nullptr; } // expected-warning{{unused function 'f3'}} | ||
extern void g3() __attribute__((ifunc("_ZL2f3IiEPvT_"))); | ||
void *use3 = f3(0); | ||
#endif |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should also happen in C because of
__attribute__((overloadable))
(so the code is correct, but we should fix up the comment and add a test case in C for this situation)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for mentioning
overloadable
. Added a test and fixed the comment.