This is an archive of the discontinued LLVM Phabricator instance.

[CodeGen] Diagnose and reject non-function ifunc resolvers
ClosedPublic

Authored by ibookstein on Oct 30 2021, 4:39 AM.

Details

Summary

Signed-off-by: Itay Bookstein <ibookstein@gmail.com>

Diff Detail

Event Timeline

ibookstein requested review of this revision.Oct 30 2021, 4:39 AM
ibookstein created this revision.
Herald added a project: Restricted Project. · View Herald TranscriptOct 30 2021, 4:39 AM
Herald added a subscriber: cfe-commits. · View Herald Transcript

clang-format

One thing that surprises me is that the test changes are in Sema but the code changes are in CodeGen. I see that this test actually emits LLVM IR. Should it be moved (as an NFC change)?

erichkeane added inline comments.
clang/lib/CodeGen/CodeGenModule.cpp
315–316

Can you explain a bit better how this change here works? The previous version appears to have done quite a bit of work in the loop to look through aliases/ifuncs, and it seems we don't do that anymore?

392

What is the purpose of changing this from checking the declaration to the IR? It seems that this is something we should be able to catch at the AST level and not have to revert to IR checks like this.

clang/test/Sema/attr-ifunc.c
16 ↗(On Diff #383661)

Did we lose this previous error? We still want that to happen, right?

ibookstein added inline comments.Nov 5 2021, 1:22 AM
clang/lib/CodeGen/CodeGenModule.cpp
315–316

Previously this function would have drilled through an arbitrary ifunc->alias->ifunc->alias interleaving structure. This is sort of peculiar since for alias->ifunc it would return the resolver (rather than the aliasee, which is the ifunc itself), and for ifunc->ifunc (which is invalid anyway) it would return the second ifunc's resolver.
In this change I want it to stop at the first non-alias object it encounters, and for ifuncs diagnose when the type of such an object is incorrect.
That is exactly what the GlobalValue::getAliaseeObject() function does - it pierces through aliases in a loop.

In essence, in an alias->ifunc->alias->... chain there should always be 0 or 1 ifuncs, and if there's an ifunc the last object should be a resolver function (and not a global variable or an ifunc).
If you were to try the following code snippet, you'll see that it asserts/crashes clang prior to this patch:

int g_var;
void foo(void) __attribute__((ifunc("g_var")));
392

Inside checkAliasedGlobal I wanted to save on a parameter (D) since then I would just be passing it redundantly because the information is already available on the Alias. Here I wanted the check to be an exact copy of the check inside checkAliasedGlobal for consistency. I don't mind changing that at at all, I guess I just don't see why I should prefer one over the other :)

clang/test/Sema/attr-ifunc.c
16 ↗(On Diff #383661)

One of the two errors (the one on f2_b) is enough, IMO.
There's some lopsidedness in this 'cycle' diagnosis because I consider the ifunc 'hop' to be special - it is no longer treated as a plain alias to loop into.
This case is the if (FinalGV == GV) in the getAliasedGlobal implementation above. It's also possible to diagnose this as "resolver of ifunc cannot be ifunc" (if I remove that condition).

Explanations make sense to me, I'm generally in favor with the 1 concern.

clang/lib/CodeGen/CodeGenModule.cpp
392

The CFE (particularly when doing checks, but even when generating code) should be doing as much based on the AST rather than the IR, as it makes us a bit more fragile/dependent on the form of the IR. So typcially we try to avoid determining types/etc from IR.

Note we break this rule a bunch, but it is currently burning us on opaque-ptr for example.

ibookstein updated this revision to Diff 385211.Nov 5 2021, 4:16 PM

Changed to using D->hasAttr<IFuncAttr>() and passing that
bool into the checkAliasedGlobal function.

ibookstein updated this revision to Diff 385212.Nov 5 2021, 4:19 PM

Nicer param order for checkAliasedGlobal..

erichkeane accepted this revision.Nov 8 2021, 5:51 AM
This revision is now accepted and ready to land.Nov 8 2021, 5:51 AM
ibookstein updated this revision to Diff 385541.Nov 8 2021, 9:52 AM

clang-format + fastforward rebase

One thing that surprises me is that the test changes are in Sema but the code changes are in CodeGen. I see that this test actually emits LLVM IR. Should it be moved (as an NFC change)?

Echo this question. Otherwise the new behavior looks good to me.

ibookstein retitled this revision from [Sema] Diagnose and reject non-function ifunc resolvers to [CodeGen] Diagnose and reject non-function ifunc resolvers.

move attr-ifunc.c test to codegen

ibookstein updated this revision to Diff 385606.Nov 8 2021, 1:01 PM

move test from Sema to CodeGen (trying to make arcanist send multiple
separate commits..?)

rebase fix after adding parent NFC commits

MaskRay accepted this revision.Nov 9 2021, 12:53 PM

I assume that dancing with GlobalValue makes this difficult to implement in lib/Sema.

Yeah, it's real ugly from a CFE/LLVM separation POV. I also can't avoid seeing it as a duplication of the verifier's logic. But emitting diagnoses is better than asserting/crashing...
For the recursion, maybe an equivalent of getAliaseeObject on GlobalDecl-s could work? For the rest - not steeped in the code enough to say...