103 changes: 51 additions & 52 deletions clang/lib/Sema/SemaChecking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2033,18 +2033,17 @@ bool Sema::checkConstantPointerAuthKey(Expr *Arg, unsigned &Result) {
static std::pair<const ValueDecl *, CharUnits>
findConstantBaseAndOffset(Sema &S, Expr *E) {
// Must evaluate as a pointer.
Expr::EvalResult result;
if (!E->EvaluateAsRValue(result, S.Context) ||
!result.Val.isLValue())
Expr::EvalResult Result;
if (!E->EvaluateAsRValue(Result, S.Context) || !Result.Val.isLValue())
return std::make_pair(nullptr, CharUnits());

// Base must be a declaration and can't be weakly imported.
auto baseDecl =
result.Val.getLValueBase().dyn_cast<const ValueDecl *>();
if (!baseDecl || baseDecl->hasAttr<WeakRefAttr>())
const auto *BaseDecl =
Result.Val.getLValueBase().dyn_cast<const ValueDecl *>();
if (!BaseDecl || BaseDecl->hasAttr<WeakRefAttr>())
return std::make_pair(nullptr, CharUnits());

return std::make_pair(baseDecl, result.Val.getLValueOffset());
return std::make_pair(BaseDecl, Result.Val.getLValueOffset());
}

static bool checkPointerAuthValue(Sema &S, Expr *&Arg,
Expand Down Expand Up @@ -2110,73 +2109,73 @@ static bool checkPointerAuthValue(Sema &S, Expr *&Arg,
// The main argument.
if (OpKind == PAO_Sign) {
// Require the value we're signing to have a special form.
auto result = findConstantBaseAndOffset(S, Arg);
bool invalid;
auto BaseOffsetPair = findConstantBaseAndOffset(S, Arg);
bool Invalid;

// Must be rooted in a declaration reference.
if (!result.first) {
invalid = true;
if (!BaseOffsetPair.first) {
Invalid = true;

// If it's a function declaration, we can't have an offset.
} else if (isa<FunctionDecl>(result.first)) {
invalid = !result.second.isZero();
// If it's a function declaration, we can't have an offset.
} else if (isa<FunctionDecl>(BaseOffsetPair.first)) {
Invalid = !BaseOffsetPair.second.isZero();

// Otherwise we're fine.
// Otherwise we're fine.
} else {
invalid = false;
Invalid = false;
}

if (invalid) {
if (Invalid) {
S.Diag(Arg->getExprLoc(), diag::err_ptrauth_bad_constant_pointer);
}
return invalid;
return Invalid;
}

// The discriminator argument.
assert(OpKind == PAO_Discriminator);

// Must be a pointer or integer or blend thereof.
Expr *pointer = nullptr;
Expr *integer = nullptr;
if (auto call = dyn_cast<CallExpr>(Arg->IgnoreParens())) {
if (call->getBuiltinCallee() ==
Builtin::BI__builtin_ptrauth_blend_discriminator) {
pointer = call->getArg(0);
integer = call->getArg(1);
Expr *Pointer = nullptr;
Expr *Integer = nullptr;
if (auto *Call = dyn_cast<CallExpr>(Arg->IgnoreParens())) {
if (Call->getBuiltinCallee() ==
Builtin::BI__builtin_ptrauth_blend_discriminator) {
Pointer = Call->getArg(0);
Integer = Call->getArg(1);
}
}
if (!pointer && !integer) {
if (!Pointer && !Integer) {
if (Arg->getType()->isPointerType())
pointer = Arg;
Pointer = Arg;
else
integer = Arg;
Integer = Arg;
}

// Check the pointer.
bool invalid = false;
if (pointer) {
assert(pointer->getType()->isPointerType());
bool Invalid = false;
if (Pointer) {
assert(Pointer->getType()->isPointerType());

// TODO: if we're initializing a global, check that the address is
// somehow related to what we're initializing. This probably will
// never really be feasible and we'll have to catch it at link-time.
auto result = findConstantBaseAndOffset(S, pointer);
if (!result.first || !isa<VarDecl>(result.first)) {
invalid = true;
auto BaseOffsetPair = findConstantBaseAndOffset(S, Pointer);
if (!BaseOffsetPair.first || !isa<VarDecl>(BaseOffsetPair.first)) {
Invalid = true;
}
}

// Check the integer.
if (integer) {
assert(integer->getType()->isIntegerType());
if (!integer->isEvaluatable(S.Context))
invalid = true;
if (Integer) {
assert(Integer->getType()->isIntegerType());
if (!Integer->isEvaluatable(S.Context))
Invalid = true;
}

if (invalid) {
if (Invalid) {
S.Diag(Arg->getExprLoc(), diag::err_ptrauth_bad_constant_discriminator);
}
return invalid;
return Invalid;
}

static ExprResult PointerAuthStrip(Sema &S, CallExpr *Call) {
Expand Down Expand Up @@ -2251,22 +2250,22 @@ static ExprResult PointerAuthAuthAndResign(Sema &S, CallExpr *Call) {
return Call;
}

static ExprResult PointerAuthStringDiscriminator(Sema &S, CallExpr *call) {
if (checkPointerAuthEnabled(S, call)) return ExprError();
static ExprResult PointerAuthStringDiscriminator(Sema &S, CallExpr *Call) {
if (checkPointerAuthEnabled(S, Call))
return ExprError();

// We've already performed normal call type-checking.
Expr *arg = call->getArgs()[0]->IgnoreParenImpCasts();
const Expr *Arg = Call->getArg(0)->IgnoreParenImpCasts();

// Operand must be an ordinary or UTF-8 string literal.
auto literal = dyn_cast<StringLiteral>(arg);
if (!literal || literal->getCharByteWidth() != 1) {
S.Diag(arg->getExprLoc(), diag::err_ptrauth_string_not_literal)
<< (literal ? 1 : 0)
<< arg->getSourceRange();
const auto *Literal = dyn_cast<StringLiteral>(Arg);
if (!Literal || Literal->getCharByteWidth() != 1) {
S.Diag(Arg->getExprLoc(), diag::err_ptrauth_string_not_literal)
<< (Literal ? 1 : 0) << Arg->getSourceRange();
return ExprError();
}

return call;
return Call;
}

static ExprResult BuiltinLaunder(Sema &S, CallExpr *TheCall) {
Expand Down Expand Up @@ -3029,13 +3028,13 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
return PointerAuthBlendDiscriminator(*this, TheCall);
case Builtin::BI__builtin_ptrauth_sign_constant:
return PointerAuthSignOrAuth(*this, TheCall, PAO_Sign,
/*constant*/ true);
/*RequireConstant=*/true);
case Builtin::BI__builtin_ptrauth_sign_unauthenticated:
return PointerAuthSignOrAuth(*this, TheCall, PAO_Sign,
/*constant*/ false);
/*RequireConstant=*/false);
case Builtin::BI__builtin_ptrauth_auth:
return PointerAuthSignOrAuth(*this, TheCall, PAO_Auth,
/*constant*/ false);
/*RequireConstant=*/false);
case Builtin::BI__builtin_ptrauth_sign_generic_data:
return PointerAuthSignGenericData(*this, TheCall);
case Builtin::BI__builtin_ptrauth_auth_and_resign:
Expand Down
3 changes: 2 additions & 1 deletion clang/test/CodeGen/ptrauth-intrinsic-sign-constant.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-intrinsics -emit-llvm %s -o - | FileCheck %s
// RUN: %clang_cc1 -triple aarch64-elf -fptrauth-intrinsics -emit-llvm %s -o - | FileCheck %s

extern int external;

Expand All @@ -12,7 +13,7 @@ void *ptr2 = __builtin_ptrauth_sign_constant(&external, 2, __builtin_ptrauth_ble
void *ptr3;

void test_sign_constant_code() {
// CHECK-LABEL: define void @test_sign_constant_code()
// CHECK-LABEL: define {{.*}}void @test_sign_constant_code()
// CHECK-NEXT: entry:
// CHECK-NEXT: store ptr ptrauth (ptr @external, i32 2, i64 1234), ptr @ptr3, align 8
// CHECK-NEXT: ret void
Expand Down
15 changes: 8 additions & 7 deletions clang/test/CodeGen/ptrauth-intrinsics.c
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-intrinsics -emit-llvm %s -o - | FileCheck %s
// RUN: %clang_cc1 -triple aarch64-elf -fptrauth-intrinsics -emit-llvm %s -o - | FileCheck %s

void (*fnptr)(void);
long int_discriminator;
void *ptr_discriminator;
long signature;

// CHECK-LABEL: define void @test_auth()
// CHECK-LABEL: define {{.*}}void @test_auth()
void test_auth() {
// CHECK: [[PTR:%.*]] = load ptr, ptr @fnptr,
// CHECK-NEXT: [[DISC0:%.*]] = load ptr, ptr @ptr_discriminator,
Expand All @@ -17,7 +18,7 @@ void test_auth() {
fnptr = __builtin_ptrauth_auth(fnptr, 0, ptr_discriminator);
}

// CHECK-LABEL: define void @test_strip()
// CHECK-LABEL: define {{.*}}void @test_strip()
void test_strip() {
// CHECK: [[PTR:%.*]] = load ptr, ptr @fnptr,
// CHECK-NEXT: [[T0:%.*]] = ptrtoint ptr [[PTR]] to i64
Expand All @@ -27,7 +28,7 @@ void test_strip() {
fnptr = __builtin_ptrauth_strip(fnptr, 0);
}

// CHECK-LABEL: define void @test_sign_unauthenticated()
// CHECK-LABEL: define {{.*}}void @test_sign_unauthenticated()
void test_sign_unauthenticated() {
// CHECK: [[PTR:%.*]] = load ptr, ptr @fnptr,
// CHECK-NEXT: [[DISC0:%.*]] = load ptr, ptr @ptr_discriminator,
Expand All @@ -39,7 +40,7 @@ void test_sign_unauthenticated() {
fnptr = __builtin_ptrauth_sign_unauthenticated(fnptr, 0, ptr_discriminator);
}

// CHECK-LABEL: define void @test_auth_and_resign()
// CHECK-LABEL: define {{.*}}void @test_auth_and_resign()
void test_auth_and_resign() {
// CHECK: [[PTR:%.*]] = load ptr, ptr @fnptr,
// CHECK-NEXT: [[DISC0:%.*]] = load ptr, ptr @ptr_discriminator,
Expand All @@ -51,7 +52,7 @@ void test_auth_and_resign() {
fnptr = __builtin_ptrauth_auth_and_resign(fnptr, 0, ptr_discriminator, 3, 15);
}

// CHECK-LABEL: define void @test_blend_discriminator()
// CHECK-LABEL: define {{.*}}void @test_blend_discriminator()
void test_blend_discriminator() {
// CHECK: [[PTR:%.*]] = load ptr, ptr @fnptr,
// CHECK-NEXT: [[DISC:%.*]] = load i64, ptr @int_discriminator,
Expand All @@ -61,7 +62,7 @@ void test_blend_discriminator() {
int_discriminator = __builtin_ptrauth_blend_discriminator(fnptr, int_discriminator);
}

// CHECK-LABEL: define void @test_sign_generic_data()
// CHECK-LABEL: define {{.*}}void @test_sign_generic_data()
void test_sign_generic_data() {
// CHECK: [[PTR:%.*]] = load ptr, ptr @fnptr,
// CHECK-NEXT: [[DISC0:%.*]] = load ptr, ptr @ptr_discriminator,
Expand All @@ -72,7 +73,7 @@ void test_sign_generic_data() {
signature = __builtin_ptrauth_sign_generic_data(fnptr, ptr_discriminator);
}

// CHECK-LABEL: define void @test_string_discriminator()
// CHECK-LABEL: define {{.*}}void @test_string_discriminator()
void test_string_discriminator() {
// CHECK: [[X:%.*]] = alloca i32

Expand Down
11 changes: 11 additions & 0 deletions clang/test/Sema/ptrauth.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,17 @@ void test_blend_discriminator(int *dp, int (*fp)(int), int value) {
float *mismatch = __builtin_ptrauth_blend_discriminator(dp, value); // expected-error {{incompatible integer to pointer conversion initializing 'float *' with an expression of type}}
}

void test_string_discriminator(const char *str) {
__builtin_ptrauth_string_discriminator(); // expected-error {{too few arguments}}
__builtin_ptrauth_string_discriminator(str, str); // expected-error {{too many arguments}}
(void) __builtin_ptrauth_string_discriminator("test string"); // no warning

__builtin_ptrauth_string_discriminator(str); // expected-error {{argument must be a string literal}}

void *mismatch = __builtin_ptrauth_string_discriminator("test string"); // expected-error {{incompatible integer to pointer conversion initializing 'void *' with an expression of type 'unsigned long'}}
}


void test_sign_constant(int *dp, int (*fp)(int)) {
__builtin_ptrauth_sign_constant(&dv, VALID_DATA_KEY); // expected-error {{too few arguments}}
__builtin_ptrauth_sign_constant(&dv, VALID_DATA_KEY, &dv, &dv); // expected-error {{too many arguments}}
Expand Down