Skip to content

Commit 71cc97c

Browse files
Add bounds checking to DeleteSubrange, create new helper, RuntimeAssertInBoundsGE, and modify LogIndexOutOfBoundsAndAbort to customize the message being logged.
PiperOrigin-RevId: 853478344
1 parent c301c2c commit 71cc97c

File tree

3 files changed

+44
-18
lines changed

3 files changed

+44
-18
lines changed

src/google/protobuf/repeated_field.cc

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,25 @@ void LogIndexOutOfBounds(int index, int size) {
3434
ABSL_DLOG(FATAL) << "Index " << index << " out of bounds " << size;
3535
}
3636

37-
void LogIndexOutOfBoundsAndAbort(int64_t index, int64_t size) {
38-
ABSL_LOG(FATAL) << "Index (" << index
39-
<< ") out of bounds of container with size (" << size << ")";
37+
void LogIndexOutOfBoundsAndAbort(int64_t index, int64_t size,
38+
BoundsCheckMessageType type) {
39+
switch (type) {
40+
case BoundsCheckMessageType::kIndex:
41+
ABSL_LOG(FATAL) << "Index (" << index
42+
<< ") out of bounds of container with size (" << size
43+
<< ")";
44+
break;
45+
case BoundsCheckMessageType::kGe:
46+
ABSL_LOG(FATAL) << "Value (" << index
47+
<< ") must be greater than or equal to limit (" << size
48+
<< ")";
49+
break;
50+
case BoundsCheckMessageType::kLe:
51+
ABSL_LOG(FATAL) << "Value (" << index
52+
<< ") must be less than or equal to limit (" << size
53+
<< ")";
54+
break;
55+
}
4056
}
4157
} // namespace internal
4258

src/google/protobuf/repeated_field.h

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1122,16 +1122,7 @@ inline Element* RepeatedField<Element>::AddAlreadyReserved()
11221122
template <typename Element>
11231123
inline Element* RepeatedField<Element>::AddNAlreadyReserved(int n)
11241124
ABSL_ATTRIBUTE_LIFETIME_BOUND {
1125-
if (ABSL_PREDICT_FALSE(n < 0)) {
1126-
// Calling with size 0 ensures that internal check (`n < 0 || n >= 0`)
1127-
// fails for any negative input.
1128-
internal::RuntimeAssertInBounds(n, 0);
1129-
}
1130-
// n = 0 will fail if it reaches RuntimeAssertInBoundsLE.
1131-
if (n == 0) {
1132-
return unsafe_elements(is_soo()) + size(is_soo());
1133-
}
1134-
1125+
internal::RuntimeAssertInBoundsGE(n, 0);
11351126
const bool is_soo = this->is_soo();
11361127
const int old_size = size(is_soo);
11371128
[[maybe_unused]] const int capacity = Capacity(is_soo);

src/google/protobuf/repeated_ptr_field.h

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,12 @@ struct InternalMetadataResolverOffsetHelper {
104104
PROTOBUF_EXPORT MessageLite* CloneSlow(Arena* arena, const MessageLite& value);
105105
PROTOBUF_EXPORT std::string* CloneSlow(Arena* arena, const std::string& value);
106106

107+
enum class BoundsCheckMessageType {
108+
kIndex,
109+
kGe,
110+
kLe,
111+
};
112+
107113
// A utility function for logging that doesn't need any template types.
108114
PROTOBUF_EXPORT void LogIndexOutOfBounds(int index, int size);
109115

@@ -113,7 +119,8 @@ PROTOBUF_EXPORT void LogIndexOutOfBounds(int index, int size);
113119
// TODO: Remove preserve_all and add no_return once experiment is
114120
// complete.
115121
PROTOBUF_PRESERVE_ALL PROTOBUF_EXPORT void LogIndexOutOfBoundsAndAbort(
116-
int64_t index, int64_t size);
122+
int64_t index, int64_t size,
123+
BoundsCheckMessageType type = BoundsCheckMessageType::kIndex);
117124
PROTOBUF_EXPORT inline void RuntimeAssertInBounds(int index, int size) {
118125
if constexpr (GetBoundsCheckMode() == BoundsCheckMode::kAbort) {
119126
if (ABSL_PREDICT_FALSE(index < 0 || index >= size)) {
@@ -131,13 +138,25 @@ PROTOBUF_EXPORT inline void RuntimeAssertInBoundsLE(int64_t value,
131138
int64_t limit) {
132139
if constexpr (GetBoundsCheckMode() == BoundsCheckMode::kAbort) {
133140
if (ABSL_PREDICT_FALSE(value > limit)) {
134-
PROTOBUF_NO_MERGE LogIndexOutOfBoundsAndAbort(value, limit);
141+
PROTOBUF_NO_MERGE LogIndexOutOfBoundsAndAbort(
142+
value, limit, BoundsCheckMessageType::kLe);
135143
}
136144
}
137145

138146
ABSL_DCHECK_LE(value, limit);
139147
}
140148

149+
PROTOBUF_EXPORT inline void RuntimeAssertInBoundsGE(int64_t value,
150+
int64_t limit) {
151+
if constexpr (GetBoundsCheckMode() == BoundsCheckMode::kAbort) {
152+
if (ABSL_PREDICT_FALSE(value < limit)) {
153+
PROTOBUF_NO_MERGE LogIndexOutOfBoundsAndAbort(
154+
value, limit, BoundsCheckMessageType::kGe);
155+
}
156+
}
157+
ABSL_DCHECK_GE(value, limit);
158+
}
159+
141160
// Defined further below.
142161
template <typename Type>
143162
class GenericTypeHandler;
@@ -1764,9 +1783,9 @@ inline void RepeatedPtrField<Element>::RemoveLast() {
17641783

17651784
template <typename Element>
17661785
inline void RepeatedPtrField<Element>::DeleteSubrange(int start, int num) {
1767-
ABSL_DCHECK_GE(start, 0);
1768-
ABSL_DCHECK_GE(num, 0);
1769-
ABSL_DCHECK_LE(start + num, size());
1786+
internal::RuntimeAssertInBoundsGE(start, 0);
1787+
internal::RuntimeAssertInBoundsGE(num, 0);
1788+
internal::RuntimeAssertInBoundsLE(static_cast<int64_t>(start) + num, size());
17701789
void** subrange = raw_mutable_data() + start;
17711790
Arena* arena = GetArena();
17721791
for (int i = 0; i < num; ++i) {

0 commit comments

Comments
 (0)