[lldb] Handle ConstantExpr constants in InjectPointerSigningFixupCode (#194476)

Currently, the injection code assumes we encounter ConstantAggregate
constants and emits a GEP to access the fields/members. However, it's
possible for a CPA to be an operand of a ConstantExpr (e.g. a bitcast).
Emitting a GEP in that scenario doesn't make sense. This should instead
be handled by keeping track of the path to the CPA (which operands need
to be followed from the top-level ConstantExpr).

After this change, most arm64e tests that crash LLDB either pass or fail
with some other issue. The main exception is TestWeakSymbols.py which
needs more work.
This commit is contained in:
Alex Langford
2026-04-29 10:34:22 -07:00
committed by GitHub
parent 7e13df61d2
commit df65c8b25b

View File

@@ -38,6 +38,7 @@
#include "llvm/IR/Constants.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/TargetParser/Triple.h"
@@ -45,31 +46,54 @@
using namespace llvm;
namespace {
struct ExprStep {
ConstantExpr *CE;
unsigned OperandIdx;
};
struct PtrAuthFixup {
GlobalVariable *GV;
ConstantPtrAuth *CPA;
SmallVector<unsigned> Indices;
/// ConstantAggregate types are walekd via GEP indices.
SmallVector<unsigned> GEPPath;
/// ConstantExpr types are traversed via ExprStep (ConstantExpr + Operand
/// index).
SmallVector<ExprStep> ExprPath;
PtrAuthFixup(GlobalVariable *GV, ConstantPtrAuth *CPA,
const SmallVectorImpl<unsigned> &Indices)
: GV(GV), CPA(CPA), Indices(Indices.begin(), Indices.end()) {}
const SmallVectorImpl<unsigned> &GEPPath,
const SmallVectorImpl<ExprStep> &ExprPath)
: GV(GV), CPA(CPA), GEPPath(GEPPath.begin(), GEPPath.end()),
ExprPath(ExprPath.begin(), ExprPath.end()) {}
};
} // namespace
/// Recursively walk a constant looking for ConstantPtrAuth expressions.
/// When found, record the global variable containing the ConstantPtrAuth and
/// the index path to reach it within the initializer.
static void findPtrAuth(Constant *C, GlobalVariable &GV,
SmallVectorImpl<unsigned> &Indices,
SmallVectorImpl<unsigned> &GEPPath,
SmallVectorImpl<ExprStep> &ExprPath,
SmallVectorImpl<PtrAuthFixup> &Fixups) {
if (auto *CPA = dyn_cast<ConstantPtrAuth>(C)) {
Fixups.emplace_back(&GV, CPA, Indices);
Fixups.emplace_back(&GV, CPA, GEPPath, ExprPath);
return;
}
for (unsigned I = 0, E = C->getNumOperands(); I != E; ++I) {
if (auto *COp = dyn_cast<Constant>(C->getOperand(I))) {
Indices.push_back(I);
findPtrAuth(COp, GV, Indices, Fixups);
Indices.pop_back();
if (isa<ConstantAggregate>(C)) {
for (unsigned I = 0, E = C->getNumOperands(); I != E; ++I) {
if (auto *COp = dyn_cast<Constant>(C->getOperand(I))) {
GEPPath.push_back(I);
findPtrAuth(COp, GV, GEPPath, ExprPath, Fixups);
GEPPath.pop_back();
}
}
return;
}
if (auto *CE = dyn_cast<ConstantExpr>(C)) {
for (unsigned I = 0, E = C->getNumOperands(); I != E; ++I) {
if (auto *COp = dyn_cast<Constant>(C->getOperand(I))) {
ExprPath.push_back({CE, I});
findPtrAuth(COp, GV, GEPPath, ExprPath, Fixups);
ExprPath.pop_back();
}
}
}
}
@@ -93,8 +117,9 @@ Error InjectPointerSigningFixupCode(llvm::Module &M,
for (auto &G : M.globals()) {
if (!G.hasInitializer())
continue;
SmallVector<unsigned> Indices;
findPtrAuth(G.getInitializer(), G, Indices, Fixups);
SmallVector<unsigned> GEPPath;
SmallVector<ExprStep> ExprPath;
findPtrAuth(G.getInitializer(), G, GEPPath, ExprPath, Fixups);
}
if (Fixups.empty())
@@ -126,37 +151,50 @@ Error InjectPointerSigningFixupCode(llvm::Module &M,
continue;
}
// Build a GEP to the location of the ConstantPtrAuth within the global.
// Build a GEP to the location of the ConstantPtrAuth (or the expression
// path to the ConstantPtrAuth) within the global.
Value *Loc;
if (Fixup.Indices.empty()) {
if (Fixup.GEPPath.empty()) {
Loc = GV;
} else {
SmallVector<Value *> GEPIndices;
GEPIndices.push_back(ConstantInt::get(Int32Ty, 0));
for (unsigned Idx : Fixup.Indices)
GEPIndices.push_back(ConstantInt::get(Int32Ty, Idx));
Loc = B.CreateGEP(GV->getValueType(), GV, GEPIndices);
SmallVector<Value *> GEPValues;
GEPValues.push_back(ConstantInt::get(Int32Ty, 0));
for (unsigned Idx : Fixup.GEPPath)
GEPValues.push_back(ConstantInt::get(Int32Ty, Idx));
Loc = B.CreateGEP(GV->getValueType(), GV, GEPValues);
}
Type *PtrTy = CPA->getType();
// Load the raw (unsigned) pointer.
Value *RawPtr = B.CreateLoad(PtrTy, Loc);
// Compute the discriminator, blending with the address if needed.
Value *Disc = CPA->getDiscriminator();
if (CPA->hasAddressDiscriminator())
Disc = B.CreateCall(BlendIntrinsic,
{B.CreatePointerCast(Loc, IntPtrTy), Disc});
// Sign the pointer.
Value *SignedPtr =
B.CreateCall(SignIntrinsic, {B.CreatePointerCast(RawPtr, IntPtrTy),
CPA->getKey(), Disc});
// Store the signed pointer back.
B.CreateStore(B.CreateBitOrPointerCast(SignedPtr, PtrTy), Loc);
if (!Fixup.ExprPath.empty()) {
// The CPA is wrapped in a ConstantExpr chain. Sign the CPA's pointer
// directly and re-evaluate the expr chain.
Value *SignedPtr = B.CreateCall(
SignIntrinsic, {B.CreatePointerCast(CPA->getPointer(), IntPtrTy),
CPA->getKey(), Disc});
Value *Result = B.CreateIntToPtr(SignedPtr, PtrTy);
for (auto &Step : llvm::reverse(Fixup.ExprPath)) {
Instruction *I = Step.CE->getAsInstruction();
I->setOperand(Step.OperandIdx, Result);
B.Insert(I);
Result = I;
}
B.CreateStore(Result, Loc);
} else {
// There is no expression chain. Load and sign the pointer directly.
Value *RawPtr = B.CreateLoad(PtrTy, Loc);
Value *SignedPtr =
B.CreateCall(SignIntrinsic, {B.CreatePointerCast(RawPtr, IntPtrTy),
CPA->getKey(), Disc});
B.CreateStore(B.CreateBitOrPointerCast(SignedPtr, PtrTy), Loc);
}
// Replace the ConstantPtrAuth in the initializer with the unsigned pointer.
CPA->replaceAllUsesWith(CPA->getPointer());
}