-
Notifications
You must be signed in to change notification settings - Fork 15k
[clang] callee_type metadata for indirect calls #117036
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
base: users/Prabhuk/sprmain.clangcallgraphsection-add-type-id-metadata-to-indirect-call-and-targets-1
Are you sure you want to change the base?
Changes from all commits
08d0dc1
feeeeff
2ece26f
96c1d4e
bfb4b1a
5bfc9de
ccf13f2
158babd
fc860ab
7847eb0
ba49de6
1aba048
c6d8515
c8154ed
3e00a85
7228076
2cb23b7
11c0913
b7fbe09
3eb7a45
ffa1779
f10586e
5ddaf26
346e5b3
2d30d64
bdc76a9
e5157f6
02b2b3f
67eab8a
c183666
083270f
fac07fd
e193a40
599b585
e41d689
397fd64
842f976
13c0ffa
8ee6932
e179dc9
cb81b8a
ad6905d
d892b83
fcb1497
dfb1dc4
b902d6e
7c4b302
aa0c1d1
985522c
0382f0f
e4c653f
6195f97
6b8eb94
3788ce7
0ca9184
1f16b6a
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 |
---|---|---|
@@ -0,0 +1,114 @@ | ||
// Tests that we assign appropriate identifiers to indirect calls and targets | ||
// specifically for C++ templates. | ||
|
||
// RUN: %clang_cc1 -triple x86_64-unknown-linux -fexperimental-call-graph-section \ | ||
// RUN: -emit-llvm -o %t %s | ||
// RUN: FileCheck --check-prefix=FT %s < %t | ||
// RUN: FileCheck --check-prefix=CST %s < %t | ||
|
||
//////////////////////////////////////////////////////////////////////////////// | ||
// Class definitions and template classes (check for indirect target metadata) | ||
|
||
class Cls1 {}; | ||
|
||
// Cls2 is instantiated with T=Cls1 in foo(). Following checks are for this | ||
// instantiation. | ||
template <class T> | ||
class Cls2 { | ||
public: | ||
// FT: define {{.*}} void @_ZN4Cls2I4Cls1E2f1Ev({{.*}} !type [[F_TCLS2F1:![0-9]+]] | ||
void f1() {} | ||
|
||
// FT: define {{.*}} void @_ZN4Cls2I4Cls1E2f2ES0_({{.*}} !type [[F_TCLS2F2:![0-9]+]] | ||
void f2(T a) {} | ||
|
||
// FT: define {{.*}} void @_ZN4Cls2I4Cls1E2f3EPS0_({{.*}} !type [[F_TCLS2F3:![0-9]+]] | ||
void f3(T *a) {} | ||
|
||
// FT: define {{.*}} void @_ZN4Cls2I4Cls1E2f4EPKS0_({{.*}} !type [[F_TCLS2F4:![0-9]+]] | ||
void f4(const T *a) {} | ||
|
||
// FT: define {{.*}} void @_ZN4Cls2I4Cls1E2f5ERS0_({{.*}} !type [[F_TCLS2F5:![0-9]+]] | ||
void f5(T &a) {} | ||
|
||
// FT: define {{.*}} void @_ZN4Cls2I4Cls1E2f6ERKS0_({{.*}} !type [[F_TCLS2F6:![0-9]+]] | ||
void f6(const T &a) {} | ||
|
||
// Mixed type function pointer member | ||
T *(*fp)(T a, T *b, const T *c, T &d, const T &e); | ||
}; | ||
|
||
// FT-DAG: [[F_TCLS2F1]] = !{i64 0, !"_ZTSFvvE.generalized"} | ||
// FT-DAG: [[F_TCLS2F2]] = !{i64 0, !"_ZTSFv4Cls1E.generalized"} | ||
// FT-DAG: [[F_TCLS2F3]] = !{i64 0, !"_ZTSFvPvE.generalized"} | ||
// FT-DAG: [[F_TCLS2F4]] = !{i64 0, !"_ZTSFvPKvE.generalized"} | ||
// FT-DAG: [[F_TCLS2F5]] = !{i64 0, !"_ZTSFvR4Cls1E.generalized"} | ||
// FT-DAG: [[F_TCLS2F6]] = !{i64 0, !"_ZTSFvRK4Cls1E.generalized"} | ||
|
||
//////////////////////////////////////////////////////////////////////////////// | ||
// Callsites (check for indirect callsite operand bundles) | ||
|
||
template <class T> | ||
T *T_func(T a, T *b, const T *c, T &d, const T &e) { return b; } | ||
|
||
// CST-LABEL: define {{.*}} @_Z3foov | ||
void foo() { | ||
// Methods for Cls2<Cls1> is checked above within the template description. | ||
Cls2<Cls1> Obj; | ||
|
||
Obj.fp = T_func<Cls1>; | ||
Cls1 Cls1Obj; | ||
|
||
// CST: call noundef ptr %{{.*}}, !callee_type [[F_TFUNC_CLS1_CT:![0-9]+]] | ||
Obj.fp(Cls1Obj, &Cls1Obj, &Cls1Obj, Cls1Obj, Cls1Obj); | ||
|
||
// Make indirect calls to Cls2's member methods | ||
auto fp_f1 = &Cls2<Cls1>::f1; | ||
auto fp_f2 = &Cls2<Cls1>::f2; | ||
auto fp_f3 = &Cls2<Cls1>::f3; | ||
auto fp_f4 = &Cls2<Cls1>::f4; | ||
auto fp_f5 = &Cls2<Cls1>::f5; | ||
auto fp_f6 = &Cls2<Cls1>::f6; | ||
|
||
auto *Obj2Ptr = &Obj; | ||
|
||
// CST: call void %{{.*}}, !callee_type [[F_TCLS2F1_CT:![0-9]+]] | ||
(Obj2Ptr->*fp_f1)(); | ||
|
||
// CST: call void %{{.*}}, !callee_type [[F_TCLS2F2_CT:![0-9]+]] | ||
(Obj2Ptr->*fp_f2)(Cls1Obj); | ||
|
||
// CST: call void %{{.*}}, !callee_type [[F_TCLS2F3_CT:![0-9]+]] | ||
(Obj2Ptr->*fp_f3)(&Cls1Obj); | ||
|
||
// CST: call void %{{.*}}, !callee_type [[F_TCLS2F4_CT:![0-9]+]] | ||
(Obj2Ptr->*fp_f4)(&Cls1Obj); | ||
|
||
// CST: call void %{{.*}}, !callee_type [[F_TCLS2F5_CT:![0-9]+]] | ||
(Obj2Ptr->*fp_f5)(Cls1Obj); | ||
|
||
// CST: call void %{{.*}}, !callee_type [[F_TCLS2F6_CT:![0-9]+]] | ||
(Obj2Ptr->*fp_f6)(Cls1Obj); | ||
} | ||
|
||
// CST: define {{.*}} @_Z6T_funcI4Cls1EPT_S1_S2_PKS1_RS1_RS3_({{.*}} !type [[F_TFUNC_CLS1:![0-9]+]] | ||
// CST-DAG: [[F_TFUNC_CLS1_CT]] = !{[[F_TFUNC_CLS1:![0-9]+]]} | ||
// CST-DAG: [[F_TFUNC_CLS1]] = !{i64 0, !"_ZTSFPv4Cls1S_PKvRS0_RKS0_E.generalized"} | ||
|
||
// CST-DAG: [[F_TCLS2F1_CT]] = !{[[F_TCLS2F1:![0-9]+]]} | ||
// CST-DAG: [[F_TCLS2F1]] = !{i64 0, !"_ZTSFvvE.generalized"} | ||
|
||
// CST-DAG: [[F_TCLS2F2_CT]] = !{[[F_TCLS2F2:![0-9]+]]} | ||
// CST-DAG: [[F_TCLS2F2]] = !{i64 0, !"_ZTSFv4Cls1E.generalized"} | ||
|
||
// CST-DAG: [[F_TCLS2F3_CT]] = !{[[F_TCLS2F3:![0-9]+]]} | ||
// CST-DAG: [[F_TCLS2F3]] = !{i64 0, !"_ZTSFvPvE.generalized"} | ||
|
||
// CST-DAG: [[F_TCLS2F4_CT]] = !{[[F_TCLS2F4:![0-9]+]]} | ||
// CST-DAG: [[F_TCLS2F4]] = !{i64 0, !"_ZTSFvPKvE.generalized"} | ||
|
||
// CST-DAG: [[F_TCLS2F5_CT]] = !{[[F_TCLS2F5:![0-9]+]]} | ||
// CST-DAG: [[F_TCLS2F5]] = !{i64 0, !"_ZTSFvR4Cls1E.generalized"} | ||
|
||
// CST-DAG: [[F_TCLS2F6_CT]] = !{[[F_TCLS2F6:![0-9]+]]} | ||
// CST-DAG: [[F_TCLS2F6]] = !{i64 0, !"_ZTSFvRK4Cls1E.generalized"} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
// Tests that we assign appropriate identifiers to indirect calls and targets | ||
// specifically for virtual methods. | ||
|
||
// RUN: %clang_cc1 -triple x86_64-unknown-linux -fexperimental-call-graph-section \ | ||
// RUN: -emit-llvm -o %t %s | ||
// RUN: FileCheck --check-prefix=FT %s < %t | ||
// RUN: FileCheck --check-prefix=CST %s < %t | ||
|
||
//////////////////////////////////////////////////////////////////////////////// | ||
// Class definitions (check for indirect target metadata) | ||
|
||
class Base { | ||
public: | ||
// FT-DAG: define {{.*}} @_ZN4Base2vfEPc({{.*}} !type [[F_TVF:![0-9]+]] | ||
virtual int vf(char *a) { return 0; }; | ||
}; | ||
|
||
class Derived : public Base { | ||
public: | ||
// FT-DAG: define {{.*}} @_ZN7Derived2vfEPc({{.*}} !type [[F_TVF]] | ||
int vf(char *a) override { return 1; }; | ||
}; | ||
|
||
// FT-DAG: [[F_TVF]] = !{i64 0, !"_ZTSFiPvE.generalized"} | ||
|
||
//////////////////////////////////////////////////////////////////////////////// | ||
// Callsites (check for indirect callsite operand bundles) | ||
|
||
// CST-LABEL: define {{.*}} @_Z3foov | ||
void foo() { | ||
auto B = Base(); | ||
auto D = Derived(); | ||
|
||
Base *Bptr = &B; | ||
Base *BptrToD = &D; | ||
Derived *Dptr = &D; | ||
|
||
auto FpBaseVf = &Base::vf; | ||
auto FpDerivedVf = &Derived::vf; | ||
|
||
// CST: call noundef i32 %{{.*}}, !callee_type [[F_TVF_CT:![0-9]+]] | ||
(Bptr->*FpBaseVf)(0); | ||
|
||
// CST: call noundef i32 %{{.*}}, !callee_type [[F_TVF_CT:![0-9]+]] | ||
(BptrToD->*FpBaseVf)(0); | ||
|
||
// CST: call noundef i32 %{{.*}}, !callee_type [[F_TVF_CT:![0-9]+]] | ||
(Dptr->*FpBaseVf)(0); | ||
|
||
// CST: call noundef i32 %{{.*}}, !callee_type [[F_TVF_CT:![0-9]+]] | ||
(Dptr->*FpDerivedVf)(0); | ||
} | ||
|
||
// CST-DAG: [[F_TVF_CT]] = !{[[F_TVF:![0-9]+]]} | ||
// CST-DAG: [[F_TVF]] = !{i64 0, !"_ZTSFiPvE.generalized"} |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,83 @@ | ||||||
// Tests that we assign appropriate identifiers to indirect calls and targets. | ||||||
|
||||||
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
I think you need a requires line here, if you're gong to set the triple. Or this could be under |
||||||
// RUN: %clang_cc1 -triple x86_64-unknown-linux -fexperimental-call-graph-section \ | ||||||
// RUN: -emit-llvm -o - %s | FileCheck --check-prefixes=CHECK,ITANIUM %s | ||||||
|
||||||
// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -fexperimental-call-graph-section \ | ||||||
// RUN: -emit-llvm -o - %s | FileCheck --check-prefixes=CHECK,MS %s | ||||||
|
||||||
// CHECK-DAG: define {{(dso_local)?}} void @foo({{.*}} !type [[F_TVOID:![0-9]+]] | ||||||
void foo() { | ||||||
} | ||||||
|
||||||
// CHECK-DAG: define {{(dso_local)?}} void @bar({{.*}} !type [[F_TVOID]] | ||||||
void bar() { | ||||||
void (*fp)() = foo; | ||||||
// CHECK: call {{.*}}, !callee_type [[F_TVOID_CT:![0-9]+]] | ||||||
fp(); | ||||||
} | ||||||
|
||||||
// CHECK-DAG: define {{(dso_local)?}} i32 @baz({{.*}} !type [[F_TPRIMITIVE:![0-9]+]] | ||||||
int baz(char a, float b, double c) { | ||||||
return 1; | ||||||
} | ||||||
|
||||||
// CHECK-DAG: define {{(dso_local)?}} ptr @qux({{.*}} !type [[F_TPTR:![0-9]+]] | ||||||
int *qux(char *a, float *b, double *c) { | ||||||
return 0; | ||||||
} | ||||||
|
||||||
// CHECK-DAG: define {{(dso_local)?}} void @corge({{.*}} !type [[F_TVOID]] | ||||||
void corge() { | ||||||
int (*fp_baz)(char, float, double) = baz; | ||||||
// CHECK: call i32 {{.*}}, !callee_type [[F_TPRIMITIVE_CT:![0-9]+]] | ||||||
fp_baz('a', .0f, .0); | ||||||
|
||||||
int *(*fp_qux)(char *, float *, double *) = qux; | ||||||
// CHECK: call ptr {{.*}}, !callee_type [[F_TPTR_CT:![0-9]+]] | ||||||
fp_qux(0, 0, 0); | ||||||
} | ||||||
|
||||||
struct st1 { | ||||||
int *(*fp)(char *, float *, double *); | ||||||
}; | ||||||
|
||||||
struct st2 { | ||||||
struct st1 m; | ||||||
}; | ||||||
|
||||||
// CHECK-DAG: define {{(dso_local)?}} void @stparam({{.*}} !type [[F_TSTRUCT:![0-9]+]] | ||||||
void stparam(struct st2 a, struct st2 *b) {} | ||||||
|
||||||
// CHECK-DAG: define {{(dso_local)?}} void @stf({{.*}} !type [[F_TVOID]] | ||||||
void stf() { | ||||||
struct st1 St1; | ||||||
St1.fp = qux; | ||||||
// CHECK: call ptr {{.*}}, !callee_type [[F_TPTR_CT:![0-9]+]] | ||||||
St1.fp(0, 0, 0); | ||||||
|
||||||
struct st2 St2; | ||||||
St2.m.fp = qux; | ||||||
// CHECK: call ptr {{.*}}, !callee_type [[F_TPTR_CT:![0-9]+]] | ||||||
St2.m.fp(0, 0, 0); | ||||||
|
||||||
// CHECK: call void {{.*}}, !callee_type [[F_TSTRUCT_CT:![0-9]+]] | ||||||
void (*fp_stparam)(struct st2, struct st2 *) = stparam; | ||||||
fp_stparam(St2, &St2); | ||||||
} | ||||||
|
||||||
// CHECK-DAG: [[F_TVOID_CT]] = !{[[F_TVOID:![0-9]+]]} | ||||||
// ITANIUM-DAG: [[F_TVOID]] = !{i64 0, !"_ZTSFvE.generalized"} | ||||||
// MS-DAG: [[F_TVOID]] = !{i64 0, !"?6AX@Z.generalized"} | ||||||
|
||||||
// CHECK-DAG: [[F_TPRIMITIVE_CT]] = !{[[F_TPRIMITIVE:![0-9]+]]} | ||||||
// ITANIUM-DAG: [[F_TPRIMITIVE]] = !{i64 0, !"_ZTSFicfdE.generalized"} | ||||||
// MS-DAG: [[F_TPRIMITIVE]] = !{i64 0, !"?6AHDMN@Z.generalized"} | ||||||
|
||||||
// CHECK-DAG: [[F_TPTR_CT]] = !{[[F_TPTR:![0-9]+]]} | ||||||
// ITANIUM-DAG: [[F_TPTR]] = !{i64 0, !"_ZTSFPvS_S_S_E.generalized"} | ||||||
// MS-DAG: [[F_TPTR]] = !{i64 0, !"?6APEAXPEAX00@Z.generalized"} | ||||||
|
||||||
// CHECK-DAG: [[F_TSTRUCT_CT]] = !{[[F_TSTRUCT:![0-9]+]]} | ||||||
// ITANIUM-DAG: [[F_TSTRUCT]] = !{i64 0, !"_ZTSFv3st2PvE.generalized"} | ||||||
// MS-DAG: [[F_TSTRUCT]] = !{i64 0, !"?6AXUst2@@PEAX@Z.generalized"} |
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.
Relying on the IR function properties feels wrong here, can you detect whether this is indirect from the source context? I'm also not sure IgnoreCallbackUses is correct here (IgnoreAssumeLikeCalls is also potentially questionable)
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.
Doesn't this function just emit the type metadata if the function could be used as an indirect call target? The function name doesn't really communicate that though (at least to me).
Based on that reading, I'd say limiting it to any non-local function (e.g. could be addr taken in another TU) and any local function that has its address taken makes sense for the call-graph use-case.
Or was there some other aspect that concerns you?
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.
I also agree about the IgnoreCallbacks and IgnoreAssumeLIkeCalls.
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.
If clang is emitting the initial IR, then won't any IR based use query be unreliable? Later uses could yet to be determined. But also it shouldn't be fundamentally problematic to be conservatively correct and emit the annotation?
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.
Well, yeah, I guess that would be true, and you're right that just always doing it would be correct. Its also closer to what's done for CFI, so we should probably just do that to start, and we can try to limit the amount of type metadata later if we find its unnecessary/safe to do so.
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.
I think this still needs to be addressed...