Skip to content

Commit e16ced3

Browse files
authored
[clang][bytecode] Diagnose one-past-end reads from global arrays (#154484)
Fixes #154312
1 parent 018c5ba commit e16ced3

File tree

6 files changed

+17
-7
lines changed

6 files changed

+17
-7
lines changed

clang/lib/AST/ByteCode/Interp.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -530,7 +530,7 @@ bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
530530

531531
bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
532532
CheckSubobjectKind CSK) {
533-
if (!Ptr.isElementPastEnd())
533+
if (!Ptr.isElementPastEnd() && !Ptr.isZeroSizeArray())
534534
return true;
535535
const SourceInfo &Loc = S.Current->getSource(OpPC);
536536
S.FFDiag(Loc, diag::note_constexpr_past_end_subobject)
@@ -1312,7 +1312,7 @@ bool Free(InterpState &S, CodePtr OpPC, bool DeleteIsArrayForm,
13121312
return false;
13131313
}
13141314

1315-
if (!Ptr.isRoot() || Ptr.isOnePastEnd() ||
1315+
if (!Ptr.isRoot() || (Ptr.isOnePastEnd() && !Ptr.isZeroSizeArray()) ||
13161316
(Ptr.isArrayElement() && Ptr.getIndex() != 0)) {
13171317
const SourceInfo &Loc = S.Current->getSource(OpPC);
13181318
S.FFDiag(Loc, diag::note_constexpr_delete_subobject)

clang/lib/AST/ByteCode/Interp.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3158,8 +3158,10 @@ inline bool ArrayDecay(InterpState &S, CodePtr OpPC) {
31583158
return true;
31593159
}
31603160

3161-
if (!CheckRange(S, OpPC, Ptr, CSK_ArrayToPointer))
3162-
return false;
3161+
if (!Ptr.isZeroSizeArray()) {
3162+
if (!CheckRange(S, OpPC, Ptr, CSK_ArrayToPointer))
3163+
return false;
3164+
}
31633165

31643166
if (Ptr.isRoot() || !Ptr.isUnknownSizeArray()) {
31653167
S.Stk.push<Pointer>(Ptr.atIndex(0));

clang/lib/AST/ByteCode/Pointer.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ APValue Pointer::toAPValue(const ASTContext &ASTCtx) const {
231231
UsePath = false;
232232

233233
// Build the path into the object.
234-
bool OnePastEnd = isOnePastEnd();
234+
bool OnePastEnd = isOnePastEnd() && !isZeroSizeArray();
235235
Pointer Ptr = *this;
236236
while (Ptr.isField() || Ptr.isArrayElement()) {
237237

clang/lib/AST/ByteCode/Pointer.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -647,7 +647,7 @@ class Pointer {
647647
if (isUnknownSizeArray())
648648
return false;
649649

650-
return isPastEnd() || (getSize() == getOffset() && !isZeroSizeArray());
650+
return isPastEnd() || (getSize() == getOffset());
651651
}
652652

653653
/// Checks if the pointer points past the end of the object.

clang/test/AST/ByteCode/arrays.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -795,4 +795,8 @@ namespace ZeroSizeArrayRead {
795795
constexpr const char *p1 = &str[0];
796796
constexpr const char *p2 = &str[1]; // both-error {{must be initialized by a constant expression}} \
797797
// both-note {{cannot refer to element 1 of array of 0 elements in a constant expression}}
798+
799+
constexpr char s[] = {};
800+
static_assert(s[0] == '0', ""); // both-error {{not an integral constant expression}} \
801+
// both-note {{read of dereferenced one-past-the-end pointer}}
798802
}

clang/unittests/AST/ByteCode/Descriptor.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -399,7 +399,11 @@ TEST(Descriptor, Primitives) {
399399
const Pointer &PF5 = GlobalPtr.atField(F5->Offset);
400400

401401
ASSERT_TRUE(PF5.isZeroSizeArray());
402-
ASSERT_FALSE(PF5.isOnePastEnd());
402+
ASSERT_TRUE(PF5.isOnePastEnd());
403+
ASSERT_FALSE(PF5.isElementPastEnd());
404+
405+
const Pointer &E1 = PF5.atIndex(0);
406+
ASSERT_TRUE(PF5.isOnePastEnd());
403407
ASSERT_FALSE(PF5.isElementPastEnd());
404408
}
405409
}

0 commit comments

Comments
 (0)