@@ -3140,6 +3140,285 @@ ASTContext::getPointerAuthVTablePointerDiscriminator(const CXXRecordDecl *RD) {
31403140 return llvm::getPointerAuthStableSipHash(Str);
31413141}
31423142
3143+ /// Encode a function type for use in the discriminator of a function pointer
3144+ /// type. We can't use the itanium scheme for this since C has quite permissive
3145+ /// rules for type compatibility that we need to be compatible with.
3146+ ///
3147+ /// Formally, this function associates every function pointer type T with an
3148+ /// encoded string E(T). Let the equivalence relation T1 ~ T2 be defined as
3149+ /// E(T1) == E(T2). E(T) is part of the ABI of values of type T. C type
3150+ /// compatibility requires equivalent treatment under the ABI, so
3151+ /// CCompatible(T1, T2) must imply E(T1) == E(T2), that is, CCompatible must be
3152+ /// a subset of ~. Crucially, however, it must be a proper subset because
3153+ /// CCompatible is not an equivalence relation: for example, int[] is compatible
3154+ /// with both int[1] and int[2], but the latter are not compatible with each
3155+ /// other. Therefore this encoding function must be careful to only distinguish
3156+ /// types if there is no third type with which they are both required to be
3157+ /// compatible.
3158+ static void encodeTypeForFunctionPointerAuth(const ASTContext &Ctx,
3159+ raw_ostream &OS, QualType QT) {
3160+ // FIXME: Consider address space qualifiers.
3161+ const Type *T = QT.getCanonicalType().getTypePtr();
3162+
3163+ // FIXME: Consider using the C++ type mangling when we encounter a construct
3164+ // that is incompatible with C.
3165+
3166+ switch (T->getTypeClass()) {
3167+ case Type::Atomic:
3168+ return encodeTypeForFunctionPointerAuth(
3169+ Ctx, OS, cast<AtomicType>(T)->getValueType());
3170+
3171+ case Type::LValueReference:
3172+ OS << "R";
3173+ encodeTypeForFunctionPointerAuth(Ctx, OS,
3174+ cast<ReferenceType>(T)->getPointeeType());
3175+ return;
3176+ case Type::RValueReference:
3177+ OS << "O";
3178+ encodeTypeForFunctionPointerAuth(Ctx, OS,
3179+ cast<ReferenceType>(T)->getPointeeType());
3180+ return;
3181+
3182+ case Type::Pointer:
3183+ // C11 6.7.6.1p2:
3184+ // For two pointer types to be compatible, both shall be identically
3185+ // qualified and both shall be pointers to compatible types.
3186+ // FIXME: we should also consider pointee types.
3187+ OS << "P";
3188+ return;
3189+
3190+ case Type::ObjCObjectPointer:
3191+ case Type::BlockPointer:
3192+ OS << "P";
3193+ return;
3194+
3195+ case Type::Complex:
3196+ OS << "C";
3197+ return encodeTypeForFunctionPointerAuth(
3198+ Ctx, OS, cast<ComplexType>(T)->getElementType());
3199+
3200+ case Type::VariableArray:
3201+ case Type::ConstantArray:
3202+ case Type::IncompleteArray:
3203+ case Type::ArrayParameter:
3204+ // C11 6.7.6.2p6:
3205+ // For two array types to be compatible, both shall have compatible
3206+ // element types, and if both size specifiers are present, and are integer
3207+ // constant expressions, then both size specifiers shall have the same
3208+ // constant value [...]
3209+ //
3210+ // So since ElemType[N] has to be compatible ElemType[], we can't encode the
3211+ // width of the array.
3212+ OS << "A";
3213+ return encodeTypeForFunctionPointerAuth(
3214+ Ctx, OS, cast<ArrayType>(T)->getElementType());
3215+
3216+ case Type::ObjCInterface:
3217+ case Type::ObjCObject:
3218+ OS << "<objc_object>";
3219+ return;
3220+
3221+ case Type::Enum:
3222+ // C11 6.7.2.2p4:
3223+ // Each enumerated type shall be compatible with char, a signed integer
3224+ // type, or an unsigned integer type.
3225+ //
3226+ // So we have to treat enum types as integers.
3227+ return encodeTypeForFunctionPointerAuth(
3228+ Ctx, OS, cast<EnumType>(T)->getDecl()->getIntegerType());
3229+
3230+ case Type::FunctionNoProto:
3231+ case Type::FunctionProto: {
3232+ // C11 6.7.6.3p15:
3233+ // For two function types to be compatible, both shall specify compatible
3234+ // return types. Moreover, the parameter type lists, if both are present,
3235+ // shall agree in the number of parameters and in the use of the ellipsis
3236+ // terminator; corresponding parameters shall have compatible types.
3237+ //
3238+ // That paragraph goes on to describe how unprototyped functions are to be
3239+ // handled, which we ignore here. Unprototyped function pointers are hashed
3240+ // as though they were prototyped nullary functions since thats probably
3241+ // what the user meant. This behavior is non-conforming.
3242+ // FIXME: If we add a "custom discriminator" function type attribute we
3243+ // should encode functions as their discriminators.
3244+ OS << "F";
3245+ const auto *FuncType = cast<FunctionType>(T);
3246+ encodeTypeForFunctionPointerAuth(Ctx, OS, FuncType->getReturnType());
3247+ if (const auto *FPT = dyn_cast<FunctionProtoType>(FuncType)) {
3248+ for (QualType Param : FPT->param_types()) {
3249+ Param = Ctx.getSignatureParameterType(Param);
3250+ encodeTypeForFunctionPointerAuth(Ctx, OS, Param);
3251+ }
3252+ if (FPT->isVariadic())
3253+ OS << "z";
3254+ }
3255+ OS << "E";
3256+ return;
3257+ }
3258+
3259+ case Type::MemberPointer: {
3260+ OS << "M";
3261+ const auto *MPT = T->getAs<MemberPointerType>();
3262+ encodeTypeForFunctionPointerAuth(Ctx, OS, QualType(MPT->getClass(), 0));
3263+ encodeTypeForFunctionPointerAuth(Ctx, OS, MPT->getPointeeType());
3264+ return;
3265+ }
3266+ case Type::ExtVector:
3267+ case Type::Vector:
3268+ OS << "Dv" << Ctx.getTypeSizeInChars(T).getQuantity();
3269+ break;
3270+
3271+ // Don't bother discriminating based on these types.
3272+ case Type::Pipe:
3273+ case Type::BitInt:
3274+ case Type::ConstantMatrix:
3275+ OS << "?";
3276+ return;
3277+
3278+ case Type::Builtin: {
3279+ const auto *BTy = T->getAs<BuiltinType>();
3280+ switch (BTy->getKind()) {
3281+ #define SIGNED_TYPE(Id, SingletonId) \
3282+ case BuiltinType::Id: \
3283+ OS << "i"; \
3284+ return;
3285+ #define UNSIGNED_TYPE(Id, SingletonId) \
3286+ case BuiltinType::Id: \
3287+ OS << "i"; \
3288+ return;
3289+ #define PLACEHOLDER_TYPE(Id, SingletonId) case BuiltinType::Id:
3290+ #define BUILTIN_TYPE(Id, SingletonId)
3291+ #include "clang/AST/BuiltinTypes.def"
3292+ llvm_unreachable("placeholder types should not appear here.");
3293+
3294+ case BuiltinType::Half:
3295+ OS << "Dh";
3296+ return;
3297+ case BuiltinType::Float:
3298+ OS << "f";
3299+ return;
3300+ case BuiltinType::Double:
3301+ OS << "d";
3302+ return;
3303+ case BuiltinType::LongDouble:
3304+ OS << "e";
3305+ return;
3306+ case BuiltinType::Float16:
3307+ OS << "DF16_";
3308+ return;
3309+ case BuiltinType::Float128:
3310+ OS << "g";
3311+ return;
3312+
3313+ case BuiltinType::Void:
3314+ OS << "v";
3315+ return;
3316+
3317+ case BuiltinType::ObjCId:
3318+ case BuiltinType::ObjCClass:
3319+ case BuiltinType::ObjCSel:
3320+ case BuiltinType::NullPtr:
3321+ OS << "P";
3322+ return;
3323+
3324+ // Don't bother discriminating based on OpenCL types.
3325+ case BuiltinType::OCLSampler:
3326+ case BuiltinType::OCLEvent:
3327+ case BuiltinType::OCLClkEvent:
3328+ case BuiltinType::OCLQueue:
3329+ case BuiltinType::OCLReserveID:
3330+ case BuiltinType::BFloat16:
3331+ case BuiltinType::VectorQuad:
3332+ case BuiltinType::VectorPair:
3333+ OS << "?";
3334+ return;
3335+
3336+ // Don't bother discriminating based on these seldom-used types.
3337+ case BuiltinType::Ibm128:
3338+ return;
3339+ #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
3340+ case BuiltinType::Id: \
3341+ return;
3342+ #include "clang/Basic/OpenCLImageTypes.def"
3343+ #define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \
3344+ case BuiltinType::Id: \
3345+ return;
3346+ #include "clang/Basic/OpenCLExtensionTypes.def"
3347+ #define SVE_TYPE(Name, Id, SingletonId) \
3348+ case BuiltinType::Id: \
3349+ return;
3350+ #include "clang/Basic/AArch64SVEACLETypes.def"
3351+ case BuiltinType::Dependent:
3352+ llvm_unreachable("should never get here");
3353+ case BuiltinType::AMDGPUBufferRsrc:
3354+ case BuiltinType::WasmExternRef:
3355+ #define RVV_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
3356+ #include "clang/Basic/RISCVVTypes.def"
3357+ llvm_unreachable("not yet implemented");
3358+ }
3359+ }
3360+ case Type::Record: {
3361+ const RecordDecl *RD = T->getAs<RecordType>()->getDecl();
3362+ const IdentifierInfo *II = RD->getIdentifier();
3363+
3364+ // In C++, an immediate typedef of an anonymous struct or union
3365+ // is considered to name it for ODR purposes, but C's specification
3366+ // of type compatibility does not have a similar rule. Using the typedef
3367+ // name in function type discriminators anyway, as we do here,
3368+ // therefore technically violates the C standard: two function pointer
3369+ // types defined in terms of two typedef'd anonymous structs with
3370+ // different names are formally still compatible, but we are assigning
3371+ // them different discriminators and therefore incompatible ABIs.
3372+ //
3373+ // This is a relatively minor violation that significantly improves
3374+ // discrimination in some cases and has not caused problems in
3375+ // practice. Regardless, it is now part of the ABI in places where
3376+ // function type discrimination is used, and it can no longer be
3377+ // changed except on new platforms.
3378+
3379+ if (!II)
3380+ if (const TypedefNameDecl *Typedef = RD->getTypedefNameForAnonDecl())
3381+ II = Typedef->getDeclName().getAsIdentifierInfo();
3382+
3383+ if (!II) {
3384+ OS << "<anonymous_record>";
3385+ return;
3386+ }
3387+ OS << II->getLength() << II->getName();
3388+ return;
3389+ }
3390+ case Type::DeducedTemplateSpecialization:
3391+ case Type::Auto:
3392+ #define NON_CANONICAL_TYPE(Class, Base) case Type::Class:
3393+ #define DEPENDENT_TYPE(Class, Base) case Type::Class:
3394+ #define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) case Type::Class:
3395+ #define ABSTRACT_TYPE(Class, Base)
3396+ #define TYPE(Class, Base)
3397+ #include "clang/AST/TypeNodes.inc"
3398+ llvm_unreachable("unexpected non-canonical or dependent type!");
3399+ return;
3400+ }
3401+ }
3402+
3403+ uint16_t ASTContext::getPointerAuthTypeDiscriminator(QualType T) const {
3404+ assert(!T->isDependentType() &&
3405+ "cannot compute type discriminator of a dependent type");
3406+
3407+ SmallString<256> Str;
3408+ llvm::raw_svector_ostream Out(Str);
3409+
3410+ if (T->isFunctionPointerType() || T->isFunctionReferenceType())
3411+ T = T->getPointeeType();
3412+
3413+ if (T->isFunctionType())
3414+ encodeTypeForFunctionPointerAuth(*this, Out, T);
3415+ else
3416+ llvm_unreachable(
3417+ "type discrimination of non-function type not implemented yet");
3418+
3419+ return llvm::getPointerAuthStableSipHash(Str);
3420+ }
3421+
31433422QualType ASTContext::getObjCGCQualType(QualType T,
31443423 Qualifiers::GC GCAttr) const {
31453424 QualType CanT = getCanonicalType(T);
0 commit comments