Unverified Commit a699b25b authored by Timm Baeder's avatar Timm Baeder Committed by GitHub
Browse files

[clang][bytecode] Check reference initializers for one-past-the-end pointers (#195501)

parent 25073147
Loading
Loading
Loading
Loading
+17 −4
Original line number Diff line number Diff line
@@ -5238,8 +5238,9 @@ template <class Emitter>
VarCreationState Compiler<Emitter>::visitVarDecl(const VarDecl *VD,
                                                 const Expr *Init,
                                                 bool Toplevel) {
  QualType VarTy = VD->getType();
  // We don't know what to do with these, so just return false.
  if (VD->getType().isNull())
  if (VarTy.isNull())
    return false;

  // This case is EvalEmitter-only. If we won't create any instructions for the
@@ -5299,8 +5300,8 @@ VarCreationState Compiler<Emitter>::visitVarDecl(const VarDecl *VD,

  if (VarT) {
    unsigned Offset = this->allocateLocalPrimitive(
        VD, *VarT, VD->getType().isConstQualified(),
        VD->getType().isVolatileQualified(), ScopeKind::Block);
        VD, *VarT, VarTy.isConstQualified(), VarTy.isVolatileQualified(),
        ScopeKind::Block);

    if (!Init || Init->getType()->isVoidType())
      return true;
@@ -5315,11 +5316,23 @@ VarCreationState Compiler<Emitter>::visitVarDecl(const VarDecl *VD,
    }
    if (!this->visit(Init))
      return false;

    if (VarTy->isReferenceType()) {
      // [C++26][decl.ref]
      // The object designated by such a glvalue can be outside its lifetime
      // Because a null pointer value or a pointer past the end of an object
      // does not point to an object, a reference in a well-defined program
      // cannot refer to such things;
      assert(classifyPrim(VarTy) == PT_Ptr);
      if (!this->emitCheckRefInit(Init))
        return false;
    }

    return this->emitSetLocal(*VarT, Offset, VD);
  }
  // Local composite variables.
  if (UnsignedOrNone Offset =
          this->allocateLocal(VD, VD->getType(), ScopeKind::Block)) {
          this->allocateLocal(VD, VarTy, ScopeKind::Block)) {
    if (!Init)
      return true;

+5 −0
Original line number Diff line number Diff line
@@ -1977,6 +1977,11 @@ inline bool GetRefLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
  return handleReference(S, OpPC, LocalBlock);
}

inline bool CheckRefInit(InterpState &S, CodePtr OpPC) {
  const Pointer &Ptr = S.Stk.peek<Pointer>();
  return CheckRange(S, OpPC, Ptr, AK_Read);
}

inline bool GetPtrParam(InterpState &S, CodePtr OpPC, uint32_t Index) {
  if (S.Current->isBottomFrame())
    return false;
+3 −0
Original line number Diff line number Diff line
@@ -325,6 +325,9 @@ def GetPtrLocal : OffsetOpcode {
def GetRefLocal : OffsetOpcode {
  bit HasCustomEval = 1;
}

def CheckRefInit : Opcode {}

// [] -> [Pointer]
def GetPtrParam : OffsetOpcode;
// [] -> [Pointer]
+7 −0
Original line number Diff line number Diff line
@@ -28,3 +28,10 @@ constexpr int foo() {
  return s.b[0];
}
static_assert(foo() == 12, "");

int arr[3]; // both-note {{declared here}}
constexpr bool f() { // both-error {{constexpr function never produces a constant expression}}
  int &r  = arr[3]; // both-note {{read of dereferenced one-past-the-end pointer}} \
                    // both-warning {{array index 3 is past the end of the array}}
  return true;
}