#ifndef _OBJC_PTRAUTH_H_
#define _OBJC_PTRAUTH_H_
#include <objc/objc.h>
#if __has_include (<ptrauth.h>)
#include <ptrauth.h>
#else
#define ptrauth_strip(__value, __key) __value
#define ptrauth_blend_discriminator(__pointer, __integer) ((uintptr_t)0)
#define ptrauth_sign_constant(__value, __key, __data) __value
#define ptrauth_sign_unauthenticated(__value, __key, __data) __value
#define ptrauth_auth_and_resign(__value, __old_key, __old_data, __new_key, __new_data) __value
#define ptrauth_auth_function(__value, __old_key, __old_data) __value
#define ptrauth_auth_data(__value, __old_key, __old_data) __value
#define ptrauth_string_discriminator(__string) ((int)0)
#define ptrauth_sign_generic_data(__value, __data) ((ptrauth_generic_signature_t)0)
#define __ptrauth_function_pointer
#define __ptrauth_return_address
#define __ptrauth_block_invocation_pointer
#define __ptrauth_block_copy_helper
#define __ptrauth_block_destroy_helper
#define __ptrauth_block_byref_copy_helper
#define __ptrauth_block_byref_destroy_helper
#define __ptrauth_objc_method_list_imp
#define __ptrauth_cxx_vtable_pointer
#define __ptrauth_cxx_vtt_vtable_pointer
#define __ptrauth_swift_heap_object_destructor
#define __ptrauth_cxx_virtual_function_pointer(__declkey)
#define __ptrauth_swift_function_pointer(__typekey)
#define __ptrauth_swift_class_method_pointer(__declkey)
#define __ptrauth_swift_protocol_witness_function_pointer(__declkey)
#define __ptrauth_swift_value_witness_function_pointer(__key)
#endif
#if __has_feature(ptrauth_calls)
#define UNUSED_WITHOUT_PTRAUTH
#else
#define UNUSED_WITHOUT_PTRAUTH __unused
#endif
#if __has_feature(ptrauth_calls)
#if !__arm64__
#error ptrauth other than arm64e is unimplemented
#endif
using MethodListIMP = IMP __ptrauth_objc_method_list_imp;
#else
using MethodListIMP = IMP;
#endif
template<typename T, typename Auth>
struct WrappedPtr {
private:
T *ptr;
public:
WrappedPtr(T *p) {
*this = p;
}
WrappedPtr(const WrappedPtr<T, Auth> &p) {
*this = p;
}
WrappedPtr<T, Auth> &operator =(T *p) {
ptr = Auth::sign(p, &ptr);
return *this;
}
WrappedPtr<T, Auth> &operator =(const WrappedPtr<T, Auth> &p) {
*this = (T *)p;
return *this;
}
operator T*() const { return get(); }
T *operator->() const { return get(); }
T *get() const { return Auth::auth(ptr, &ptr); }
void validate() const {
#if !NDEBUG
char *p = (char *)get();
char dummy;
memset_s(&dummy, 1, *p, 1);
ASSERT(dummy == *p);
#endif
}
};
struct PtrauthRaw {
template <typename T>
static T *sign(T *ptr, __unused const void *address) {
return ptr;
}
template <typename T>
static T *auth(T *ptr, __unused const void *address) {
return ptr;
}
};
struct PtrauthStrip {
template <typename T>
static T *sign(T *ptr, __unused const void *address) {
return ptr;
}
template <typename T>
static T *auth(T *ptr, __unused const void *address) {
return ptrauth_strip(ptr, ptrauth_key_process_dependent_data);
}
};
template <unsigned discriminator>
struct Ptrauth {
template <typename T>
static T *sign(T *ptr, UNUSED_WITHOUT_PTRAUTH const void *address) {
if (!ptr)
return nullptr;
return ptrauth_sign_unauthenticated(ptr, ptrauth_key_process_dependent_data, ptrauth_blend_discriminator(address, discriminator));
}
template <typename T>
static T *auth(T *ptr, UNUSED_WITHOUT_PTRAUTH const void *address) {
if (!ptr)
return nullptr;
return ptrauth_auth_data(ptr, ptrauth_key_process_dependent_data, ptrauth_blend_discriminator(address, discriminator));
}
};
template <typename T> using RawPtr = WrappedPtr<T, PtrauthRaw>;
#if __has_feature(ptrauth_calls)
#if __BUILDING_OBJCDT__
#define PTRAUTH_STR(name) PtrauthStrip
#else
#define PTRAUTH_STR(name) Ptrauth<ptrauth_string_discriminator(#name)>
#endif
#define DECLARE_AUTHED_PTR_TEMPLATE(name) \
template <typename T> using name ## _authed_ptr \
= WrappedPtr<T, PTRAUTH_STR(name)>;
#else
#define PTRAUTH_STR(name) PtrauthRaw
#define DECLARE_AUTHED_PTR_TEMPLATE(name) \
template <typename T> using name ## _authed_ptr = RawPtr<T>;
#endif
#endif