Commit e2cbc1b5 authored by Kenton Varda's avatar Kenton Varda

WIP integer overflow detection via template metaprogramming.

See: https://capnproto.org/news/2015-03-02-security-advisory-and-integer-overflow-protection.html

This commit as-is is the result of wading through two years of merge conflicts. It does not build as-is because new code added in that time hasn't been converted over.
parent a37a0cc7
......@@ -45,7 +45,7 @@ kj::Own<ClientHook> AnyPointer::Reader::getPipelinedCap(
break;
case PipelineOp::Type::GET_POINTER_FIELD:
pointer = pointer.getStruct(nullptr).getPointerField(op.pointerIndex * POINTERS);
pointer = pointer.getStruct(nullptr).getPointerField(guarded(op.pointerIndex) * POINTERS);
break;
}
}
......
......@@ -208,9 +208,9 @@ struct AnyPointer {
// Note: Does not accept INLINE_COMPOSITE for elementSize.
inline List<AnyStruct>::Builder initAsListOfAnyStruct(
uint dataWordCount, uint pointerCount, uint elementCount);
uint16_t dataWordCount, uint16_t pointerCount, uint elementCount);
inline AnyStruct::Builder initAsAnyStruct(uint dataWordCount, uint pointerCount);
inline AnyStruct::Builder initAsAnyStruct(uint16_t dataWordCount, uint16_t pointerCount);
template <typename T>
inline void setAs(ReaderFor<T> value);
......@@ -398,10 +398,10 @@ struct List<AnyPointer, Kind::OTHER> {
inline Reader(): reader(ElementSize::POINTER) {}
inline explicit Reader(_::ListReader reader): reader(reader) {}
inline uint size() const { return reader.size() / ELEMENTS; }
inline uint size() const { return unguard(reader.size() / ELEMENTS); }
inline AnyPointer::Reader operator[](uint index) const {
KJ_IREQUIRE(index < size());
return AnyPointer::Reader(reader.getPointerElement(index * ELEMENTS));
return AnyPointer::Reader(reader.getPointerElement(guarded(index) * ELEMENTS));
}
typedef _::IndexingIterator<const Reader, typename AnyPointer::Reader> Iterator;
......@@ -430,10 +430,10 @@ struct List<AnyPointer, Kind::OTHER> {
inline operator Reader() const { return Reader(builder.asReader()); }
inline Reader asReader() const { return Reader(builder.asReader()); }
inline uint size() const { return builder.size() / ELEMENTS; }
inline uint size() const { return unguard(builder.size() / ELEMENTS); }
inline AnyPointer::Builder operator[](uint index) {
KJ_IREQUIRE(index < size());
return AnyPointer::Builder(builder.getPointerElement(index * ELEMENTS));
return AnyPointer::Builder(builder.getPointerElement(guarded(index) * ELEMENTS));
}
typedef _::IndexingIterator<Builder, typename AnyPointer::Builder> Iterator;
......@@ -563,10 +563,10 @@ public:
inline Reader(): reader(ElementSize::INLINE_COMPOSITE) {}
inline explicit Reader(_::ListReader reader): reader(reader) {}
inline uint size() const { return reader.size() / ELEMENTS; }
inline uint size() const { return unguard(reader.size() / ELEMENTS); }
inline AnyStruct::Reader operator[](uint index) const {
KJ_IREQUIRE(index < size());
return AnyStruct::Reader(reader.getStructElement(index * ELEMENTS));
return AnyStruct::Reader(reader.getStructElement(guarded(index) * ELEMENTS));
}
typedef _::IndexingIterator<const Reader, typename AnyStruct::Reader> Iterator;
......@@ -595,10 +595,10 @@ public:
inline operator Reader() const { return Reader(builder.asReader()); }
inline Reader asReader() const { return Reader(builder.asReader()); }
inline uint size() const { return builder.size() / ELEMENTS; }
inline uint size() const { return unguard(builder.size() / ELEMENTS); }
inline AnyStruct::Builder operator[](uint index) {
KJ_IREQUIRE(index < size());
return AnyStruct::Builder(builder.getStructElement(index * ELEMENTS));
return AnyStruct::Builder(builder.getStructElement(guarded(index) * ELEMENTS));
}
typedef _::IndexingIterator<Builder, typename AnyStruct::Builder> Iterator;
......@@ -628,7 +628,7 @@ public:
#endif
inline ElementSize getElementSize() { return _reader.getElementSize(); }
inline uint size() { return _reader.size() / ELEMENTS; }
inline uint size() { return unguard(_reader.size() / ELEMENTS); }
inline kj::ArrayPtr<const byte> getRawBytes() { return _reader.asRawBytes(); }
......@@ -664,7 +664,7 @@ public:
#endif
inline ElementSize getElementSize() { return _builder.getElementSize(); }
inline uint size() { return _builder.size() / ELEMENTS; }
inline uint size() { return unguard(_builder.size() / ELEMENTS); }
Equality equals(AnyList::Reader right);
inline bool operator==(AnyList::Reader right) {
......@@ -781,18 +781,21 @@ inline BuilderFor<T> AnyPointer::Builder::initAs(uint elementCount) {
inline AnyList::Builder AnyPointer::Builder::initAsAnyList(
ElementSize elementSize, uint elementCount) {
return AnyList::Builder(builder.initList(elementSize, elementCount * ELEMENTS));
return AnyList::Builder(builder.initList(elementSize, guarded(elementCount) * ELEMENTS));
}
inline List<AnyStruct>::Builder AnyPointer::Builder::initAsListOfAnyStruct(
uint dataWordCount, uint pointerCount, uint elementCount) {
return List<AnyStruct>::Builder(builder.initStructList(elementCount * ELEMENTS,
_::StructSize(dataWordCount * WORDS, pointerCount * POINTERS)));
uint16_t dataWordCount, uint16_t pointerCount, uint elementCount) {
return List<AnyStruct>::Builder(builder.initStructList(guarded(elementCount) * ELEMENTS,
_::StructSize(guarded(dataWordCount) * WORDS,
guarded(pointerCount) * POINTERS)));
}
inline AnyStruct::Builder AnyPointer::Builder::initAsAnyStruct(uint dataWordCount, uint pointerCount) {
inline AnyStruct::Builder AnyPointer::Builder::initAsAnyStruct(
uint16_t dataWordCount, uint16_t pointerCount) {
return AnyStruct::Builder(builder.initStruct(
_::StructSize(dataWordCount * WORDS, pointerCount * POINTERS)));
_::StructSize(guarded(dataWordCount) * WORDS,
guarded(pointerCount) * POINTERS)));
}
template <typename T>
......@@ -960,15 +963,16 @@ struct PointerHelpers<AnyStruct, Kind::OTHER> {
PointerBuilder builder, const word* defaultValue = nullptr) {
// TODO(someday): Allow specifying the size somehow?
return AnyStruct::Builder(builder.getStruct(
_::StructSize(0 * WORDS, 0 * POINTERS), defaultValue));
_::StructSize(ZERO * WORDS, ZERO * POINTERS), defaultValue));
}
static inline void set(PointerBuilder builder, AnyStruct::Reader value) {
builder.setStruct(value._reader);
}
static inline AnyStruct::Builder init(
PointerBuilder builder, uint dataWordCount, uint pointerCount) {
PointerBuilder builder, uint16_t dataWordCount, uint16_t pointerCount) {
return AnyStruct::Builder(builder.initStruct(
StructSize(dataWordCount * WORDS, pointerCount * POINTERS)));
StructSize(guarded(dataWordCount) * WORDS,
guarded(pointerCount) * POINTERS)));
}
// TODO(soon): implement these
......@@ -991,12 +995,15 @@ struct PointerHelpers<AnyList, Kind::OTHER> {
}
static inline AnyList::Builder init(
PointerBuilder builder, ElementSize elementSize, uint elementCount) {
return AnyList::Builder(builder.initList(elementSize, elementCount * ELEMENTS));
return AnyList::Builder(builder.initList(
elementSize, guarded(elementCount) * ELEMENTS));
}
static inline AnyList::Builder init(
PointerBuilder builder, uint dataWordCount, uint pointerCount, uint elementCount) {
PointerBuilder builder, uint16_t dataWordCount, uint16_t pointerCount, uint elementCount) {
return AnyList::Builder(builder.initStructList(
elementCount * ELEMENTS, StructSize(dataWordCount * WORDS, pointerCount * POINTERS)));
guarded(elementCount) * ELEMENTS,
StructSize(guarded(dataWordCount) * WORDS,
guarded(pointerCount) * POINTERS)));
}
// TODO(soon): implement these
......
......@@ -42,7 +42,7 @@ void ReadLimiter::unread(WordCount64 amount) {
// the limit value was not updated correctly for one or more reads, and therefore unread() could
// overflow it even if it is only unreading bytes that were actually read.
uint64_t oldValue = limit;
uint64_t newValue = oldValue + amount / WORDS;
uint64_t newValue = oldValue + unguard(amount / WORDS);
if (newValue > oldValue) {
limit = newValue;
}
......@@ -57,10 +57,24 @@ void SegmentBuilder::throwNotWritable() {
// =======================================================================================
ReaderArena::ReaderArena(MessageReader* message)
static SegmentWordCount verifySegmentSize(size_t size) {
auto gsize = guarded(size) * WORDS;
return assertMaxBits<SEGMENT_WORD_COUNT_BITS>(gsize, [&]() {
KJ_FAIL_REQUIRE("segment is too large", size);
});
}
inline ReaderArena::ReaderArena(MessageReader* message, const word* firstSegment,
SegmentWordCount firstSegmentSize)
: message(message),
readLimiter(message->getOptions().traversalLimitInWords * WORDS),
segment0(this, SegmentId(0), message->getSegment(0), &readLimiter) {}
readLimiter(guarded(message->getOptions().traversalLimitInWords) * WORDS),
segment0(this, SegmentId(0), firstSegment, firstSegmentSize, &readLimiter) {}
inline ReaderArena::ReaderArena(MessageReader* message, kj::ArrayPtr<const word> firstSegment)
: ReaderArena(message, firstSegment.begin(), verifySegmentSize(firstSegment.size())) {}
ReaderArena::ReaderArena(MessageReader* message)
: ReaderArena(message, message->getSegment(0)) {}
ReaderArena::~ReaderArena() noexcept(false) {}
......@@ -89,6 +103,8 @@ SegmentReader* ReaderArena::tryGetSegment(SegmentId id) {
return nullptr;
}
SegmentWordCount newSegmentSize = verifySegmentSize(newSegment.size());
if (*lock == nullptr) {
// OK, the segment exists, so allocate the map.
auto s = kj::heap<SegmentMap>();
......@@ -96,7 +112,8 @@ SegmentReader* ReaderArena::tryGetSegment(SegmentId id) {
*lock = kj::mv(s);
}
auto segment = kj::heap<SegmentReader>(this, id, newSegment, &readLimiter);
auto segment = kj::heap<SegmentReader>(
this, id, newSegment.begin(), newSegmentSize, &readLimiter);
SegmentReader* result = segment;
segments->insert(std::make_pair(id.value, mv(segment)));
return result;
......@@ -116,14 +133,17 @@ BuilderArena::BuilderArena(MessageBuilder* message)
BuilderArena::BuilderArena(MessageBuilder* message,
kj::ArrayPtr<MessageBuilder::SegmentInit> segments)
: message(message),
segment0(this, SegmentId(0), segments[0].space, &this->dummyLimiter, segments[0].wordsUsed) {
segment0(this, SegmentId(0), segments[0].space.begin(),
verifySegmentSize(segments[0].space.size()),
&this->dummyLimiter, verifySegmentSize(segments[0].wordsUsed)) {
if (segments.size() > 1) {
kj::Vector<kj::Own<SegmentBuilder>> builders(segments.size() - 1);
uint i = 1;
for (auto& segment: segments.slice(1, segments.size())) {
builders.add(kj::heap<SegmentBuilder>(
this, SegmentId(i++), segment.space, &this->dummyLimiter, segment.wordsUsed));
this, SegmentId(i++), segment.space.begin(), verifySegmentSize(segment.space.size()),
&this->dummyLimiter, verifySegmentSize(segment.wordsUsed)));
}
kj::Vector<kj::ArrayPtr<const word>> forOutput;
......@@ -155,15 +175,16 @@ SegmentBuilder* BuilderArena::getSegment(SegmentId id) {
}
}
BuilderArena::AllocateResult BuilderArena::allocate(WordCount amount) {
BuilderArena::AllocateResult BuilderArena::allocate(SegmentWordCount amount) {
if (segment0.getArena() == nullptr) {
// We're allocating the first segment.
kj::ArrayPtr<word> ptr = message->allocateSegment(amount / WORDS);
kj::ArrayPtr<word> ptr = message->allocateSegment(unguard(amount / WORDS));
auto actualSize = verifySegmentSize(ptr.size());
// Re-allocate segment0 in-place. This is a bit of a hack, but we have not returned any
// pointers to this segment yet, so it should be fine.
kj::dtor(segment0);
kj::ctor(segment0, this, SegmentId(0), ptr, &this->dummyLimiter);
kj::ctor(segment0, this, SegmentId(0), ptr.begin(), actualSize, &this->dummyLimiter);
segmentWithSpace = &segment0;
return AllocateResult { &segment0, segment0.allocate(amount) };
......@@ -183,7 +204,7 @@ BuilderArena::AllocateResult BuilderArena::allocate(WordCount amount) {
}
// Need to allocate a new segment.
SegmentBuilder* result = addSegmentInternal(message->allocateSegment(amount / WORDS));
SegmentBuilder* result = addSegmentInternal(message->allocateSegment(unguard(amount / WORDS)));
// Check this new segment first the next time we need to allocate.
segmentWithSpace = result;
......@@ -204,6 +225,8 @@ SegmentBuilder* BuilderArena::addSegmentInternal(kj::ArrayPtr<T> content) {
KJ_REQUIRE(segment0.getArena() != nullptr,
"Can't allocate external segments before allocating the root segment.");
auto contentSize = verifySegmentSize(content.size());
MultiSegmentState* segmentState;
KJ_IF_MAYBE(s, moreSegments) {
segmentState = *s;
......@@ -214,7 +237,8 @@ SegmentBuilder* BuilderArena::addSegmentInternal(kj::ArrayPtr<T> content) {
}
kj::Own<SegmentBuilder> newBuilder = kj::heap<SegmentBuilder>(
this, SegmentId(segmentState->builders.size() + 1), content, &this->dummyLimiter);
this, SegmentId(segmentState->builders.size() + 1),
content.begin(), contentSize, &this->dummyLimiter);
SegmentBuilder* result = newBuilder.get();
segmentState->builders.add(kj::mv(newBuilder));
......
......@@ -85,7 +85,7 @@ public:
inline void reset(WordCount64 limit);
KJ_ALWAYS_INLINE(bool canRead(WordCount amount, Arena* arena));
KJ_ALWAYS_INLINE(bool canRead(WordCount64 amount, Arena* arena));
void unread(WordCount64 amount);
// Adds back some words to the limit. Useful when the caller knows they are double-reading
......@@ -113,7 +113,7 @@ public:
class SegmentReader {
public:
inline SegmentReader(Arena* arena, SegmentId id, kj::ArrayPtr<const word> ptr,
inline SegmentReader(Arena* arena, SegmentId id, const word* ptr, SegmentWordCount size,
ReadLimiter* readLimiter);
KJ_ALWAYS_INLINE(bool containsInterval(const void* from, const void* to));
......@@ -129,8 +129,8 @@ public:
inline SegmentId getSegmentId();
inline const word* getStartPtr();
inline WordCount getOffsetTo(const word* ptr);
inline WordCount getSize();
inline SegmentWordCount getOffsetTo(const word* ptr);
inline SegmentWordCount getSize();
inline kj::ArrayPtr<const word> getArray();
......@@ -140,7 +140,7 @@ public:
private:
Arena* arena;
SegmentId id;
kj::ArrayPtr<const word> ptr;
kj::ArrayPtr<const word> ptr; // size guaranteed to fit in SEGMENT_WORD_COUNT_BITS bits
ReadLimiter* readLimiter;
KJ_DISALLOW_COPY(SegmentReader);
......@@ -150,19 +150,19 @@ private:
class SegmentBuilder: public SegmentReader {
public:
inline SegmentBuilder(BuilderArena* arena, SegmentId id, kj::ArrayPtr<word> ptr,
ReadLimiter* readLimiter, size_t wordsUsed = 0);
inline SegmentBuilder(BuilderArena* arena, SegmentId id, kj::ArrayPtr<const word> ptr,
inline SegmentBuilder(BuilderArena* arena, SegmentId id, word* ptr, SegmentWordCount size,
ReadLimiter* readLimiter, SegmentWordCount wordsUsed = ZERO * WORDS);
inline SegmentBuilder(BuilderArena* arena, SegmentId id, const word* ptr, SegmentWordCount size,
ReadLimiter* readLimiter);
inline SegmentBuilder(BuilderArena* arena, SegmentId id, decltype(nullptr),
ReadLimiter* readLimiter);
KJ_ALWAYS_INLINE(word* allocate(WordCount amount));
KJ_ALWAYS_INLINE(word* allocate(SegmentWordCount amount));
KJ_ALWAYS_INLINE(void checkWritable());
// Throw an exception if the segment is read-only (meaning it is a reference to external data).
KJ_ALWAYS_INLINE(word* getPtrUnchecked(WordCount offset));
KJ_ALWAYS_INLINE(word* getPtrUnchecked(SegmentWordCount offset));
// Get a writable pointer into the segment. Throws an exception if the segment is read-only (i.e.
// a reference to external immutable data).
......@@ -210,7 +210,7 @@ public:
class ReaderArena final: public Arena {
public:
ReaderArena(MessageReader* message);
explicit ReaderArena(MessageReader* message);
~ReaderArena() noexcept(false);
KJ_DISALLOW_COPY(ReaderArena);
......@@ -234,6 +234,9 @@ private:
// TODO(perf): Thread-local thing instead? Some kind of lockless map? Or do sharing of data
// in a different way, where you have to construct a new MessageReader in each thread (but
// possibly backed by the same data)?
ReaderArena(MessageReader* message, kj::ArrayPtr<const word> firstSegment);
ReaderArena(MessageReader* message, const word* firstSegment, SegmentWordCount firstSegmentSize);
};
class BuilderArena final: public Arena {
......@@ -277,7 +280,7 @@ public:
word* words;
};
AllocateResult allocate(WordCount amount);
AllocateResult allocate(SegmentWordCount amount);
// Find a segment with at least the given amount of space available and allocate the space.
// Note that allocating directly from a particular segment is much faster, but allocating from
// the arena is guaranteed to succeed. Therefore callers should try to allocate from a specific
......@@ -339,34 +342,36 @@ private:
inline ReadLimiter::ReadLimiter()
: limit(kj::maxValue) {}
inline ReadLimiter::ReadLimiter(WordCount64 limit): limit(limit / WORDS) {}
inline ReadLimiter::ReadLimiter(WordCount64 limit): limit(unguard(limit / WORDS)) {}
inline void ReadLimiter::reset(WordCount64 limit) { this->limit = limit / WORDS; }
inline void ReadLimiter::reset(WordCount64 limit) { this->limit = unguard(limit / WORDS); }
inline bool ReadLimiter::canRead(WordCount amount, Arena* arena) {
inline bool ReadLimiter::canRead(WordCount64 amount, Arena* arena) {
// Be careful not to store an underflowed value into `limit`, even if multiple threads are
// decrementing it.
uint64_t current = limit;
if (KJ_UNLIKELY(amount / WORDS > current)) {
if (KJ_UNLIKELY(unguard(amount / WORDS) > current)) {
arena->reportReadLimitReached();
return false;
} else {
limit = current - amount / WORDS;
limit = current - unguard(amount / WORDS);
return true;
}
}
// -------------------------------------------------------------------
inline SegmentReader::SegmentReader(Arena* arena, SegmentId id, kj::ArrayPtr<const word> ptr,
ReadLimiter* readLimiter)
: arena(arena), id(id), ptr(ptr), readLimiter(readLimiter) {}
inline SegmentReader::SegmentReader(Arena* arena, SegmentId id, const word* ptr,
SegmentWordCount size, ReadLimiter* readLimiter)
: arena(arena), id(id), ptr(kj::arrayPtr(ptr, unguard(size / WORDS))),
readLimiter(readLimiter) {}
inline bool SegmentReader::containsInterval(const void* from, const void* to) {
return from >= this->ptr.begin() && to <= this->ptr.end() && from <= to &&
readLimiter->canRead(
intervalLength(reinterpret_cast<const byte*>(from),
reinterpret_cast<const byte*>(to)) / BYTES_PER_WORD,
reinterpret_cast<const byte*>(to))
/ BYTES_PER_WORD,
arena);
}
......@@ -377,31 +382,36 @@ inline bool SegmentReader::amplifiedRead(WordCount virtualAmount) {
inline Arena* SegmentReader::getArena() { return arena; }
inline SegmentId SegmentReader::getSegmentId() { return id; }
inline const word* SegmentReader::getStartPtr() { return ptr.begin(); }
inline WordCount SegmentReader::getOffsetTo(const word* ptr) {
return intervalLength(this->ptr.begin(), ptr);
inline SegmentWordCount SegmentReader::getOffsetTo(const word* ptr) {
KJ_IREQUIRE(this->ptr.begin() <= ptr && ptr < this->ptr.end());
return assumeBits<SEGMENT_WORD_COUNT_BITS>(intervalLength(this->ptr.begin(), ptr));
}
inline SegmentWordCount SegmentReader::getSize() {
return assumeBits<SEGMENT_WORD_COUNT_BITS>(ptr.size()) * WORDS;
}
inline WordCount SegmentReader::getSize() { return ptr.size() * WORDS; }
inline kj::ArrayPtr<const word> SegmentReader::getArray() { return ptr; }
inline void SegmentReader::unread(WordCount64 amount) { readLimiter->unread(amount); }
// -------------------------------------------------------------------
inline SegmentBuilder::SegmentBuilder(
BuilderArena* arena, SegmentId id, kj::ArrayPtr<word> ptr, ReadLimiter* readLimiter,
size_t wordsUsed)
: SegmentReader(arena, id, ptr, readLimiter), pos(ptr.begin() + wordsUsed), readOnly(false) {}
BuilderArena* arena, SegmentId id, word* ptr, SegmentWordCount size,
ReadLimiter* readLimiter, SegmentWordCount wordsUsed)
: SegmentReader(arena, id, ptr, size, readLimiter),
pos(ptr + wordsUsed), readOnly(false) {}
inline SegmentBuilder::SegmentBuilder(
BuilderArena* arena, SegmentId id, kj::ArrayPtr<const word> ptr, ReadLimiter* readLimiter)
: SegmentReader(arena, id, ptr, readLimiter),
BuilderArena* arena, SegmentId id, const word* ptr, SegmentWordCount size,
ReadLimiter* readLimiter)
: SegmentReader(arena, id, ptr, size, readLimiter),
// const_cast is safe here because the member won't ever be dereferenced because it appears
// to point to the end of the segment anyway.
pos(const_cast<word*>(ptr.end())),
readOnly(true) {}
pos(const_cast<word*>(ptr + size)), readOnly(true) {}
inline SegmentBuilder::SegmentBuilder(BuilderArena* arena, SegmentId id, decltype(nullptr),
ReadLimiter* readLimiter)
: SegmentReader(arena, id, nullptr, readLimiter), pos(nullptr), readOnly(false) {}
: SegmentReader(arena, id, nullptr, ZERO * WORDS, readLimiter),
pos(nullptr), readOnly(false) {}
inline word* SegmentBuilder::allocate(WordCount amount) {
inline word* SegmentBuilder::allocate(SegmentWordCount amount) {
if (intervalLength(pos, ptr.end()) < amount) {
// Not enough space in the segment for this allocation.
return nullptr;
......@@ -417,7 +427,7 @@ inline void SegmentBuilder::checkWritable() {
if (KJ_UNLIKELY(readOnly)) throwNotWritable();
}
inline word* SegmentBuilder::getPtrUnchecked(WordCount offset) {
inline word* SegmentBuilder::getPtrUnchecked(SegmentWordCount offset) {
return const_cast<word*>(ptr.begin() + offset);
}
......@@ -432,7 +442,7 @@ inline kj::ArrayPtr<const word> SegmentBuilder::currentlyAllocated() {
}
inline void SegmentBuilder::reset() {
word* start = getPtrUnchecked(0 * WORDS);
word* start = getPtrUnchecked(ZERO * WORDS);
memset(start, 0, (pos - start) * sizeof(word));
pos = start;
}
......
......@@ -653,7 +653,8 @@ struct List<T, Kind::INTERFACE> {
inline uint size() const { return reader.size() / ELEMENTS; }
inline typename T::Client operator[](uint index) const {
KJ_IREQUIRE(index < size());
return typename T::Client(reader.getPointerElement(index * ELEMENTS).getCapability());
return typename T::Client(reader.getPointerElement(
guarded(index) * ELEMENTS).getCapability());
}
typedef _::IndexingIterator<const Reader, typename T::Client> Iterator;
......@@ -685,19 +686,20 @@ struct List<T, Kind::INTERFACE> {
inline uint size() const { return builder.size() / ELEMENTS; }
inline typename T::Client operator[](uint index) {
KJ_IREQUIRE(index < size());
return typename T::Client(builder.getPointerElement(index * ELEMENTS).getCapability());
return typename T::Client(builder.getPointerElement(
guarded(index) * ELEMENTS).getCapability());
}
inline void set(uint index, typename T::Client value) {
KJ_IREQUIRE(index < size());
builder.getPointerElement(index * ELEMENTS).setCapability(kj::mv(value.hook));
builder.getPointerElement(guarded(index) * ELEMENTS).setCapability(kj::mv(value.hook));
}
inline void adopt(uint index, Orphan<T>&& value) {
KJ_IREQUIRE(index < size());
builder.getPointerElement(index * ELEMENTS).adopt(kj::mv(value));
builder.getPointerElement(guarded(index) * ELEMENTS).adopt(kj::mv(value));
}
inline Orphan<T> disown(uint index) {
KJ_IREQUIRE(index < size());
return Orphan<T>(builder.getPointerElement(index * ELEMENTS).disown());
return Orphan<T>(builder.getPointerElement(guarded(index) * ELEMENTS).disown());
}
typedef _::IndexingIterator<Builder, typename T::Client> Iterator;
......@@ -713,7 +715,7 @@ struct List<T, Kind::INTERFACE> {
private:
inline static _::ListBuilder initPointer(_::PointerBuilder builder, uint size) {
return builder.initList(ElementSize::POINTER, size * ELEMENTS);
return builder.initList(ElementSize::POINTER, guarded(size) * ELEMENTS);
}
inline static _::ListBuilder getFromPointer(_::PointerBuilder builder, const word* defaultValue) {
return builder.getList(ElementSize::POINTER, defaultValue);
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -117,7 +117,7 @@ struct List<T, Kind::PRIMITIVE> {
inline uint size() const { return reader.size() / ELEMENTS; }
inline T operator[](uint index) const {
KJ_IREQUIRE(index < size());
return reader.template getDataElement<T>(index * ELEMENTS);
return reader.template getDataElement<T>(guarded(index) * ELEMENTS);
}
typedef _::IndexingIterator<const Reader, T> Iterator;
......@@ -149,7 +149,7 @@ struct List<T, Kind::PRIMITIVE> {
inline uint size() const { return builder.size() / ELEMENTS; }
inline T operator[](uint index) {
KJ_IREQUIRE(index < size());
return builder.template getDataElement<T>(index * ELEMENTS);
return builder.template getDataElement<T>(guarded(index) * ELEMENTS);
}
inline void set(uint index, T value) {
// Alas, it is not possible to make operator[] return a reference to which you can assign,
......@@ -158,7 +158,7 @@ struct List<T, Kind::PRIMITIVE> {
// operator=() because it will lead to surprising behavior when using type inference (e.g.
// calling a template function with inferred argument types, or using "auto" or "decltype").
builder.template setDataElement<T>(index * ELEMENTS, value);
builder.template setDataElement<T>(guarded(index) * ELEMENTS, value);
}
typedef _::IndexingIterator<Builder, T> Iterator;
......@@ -178,7 +178,7 @@ struct List<T, Kind::PRIMITIVE> {
private:
inline static _::ListBuilder initPointer(_::PointerBuilder builder, uint size) {
return builder.initList(_::elementSizeForType<T>(), size * ELEMENTS);
return builder.initList(_::elementSizeForType<T>(), guarded(size) * ELEMENTS);
}
inline static _::ListBuilder getFromPointer(_::PointerBuilder builder, const word* defaultValue) {
return builder.getList(_::elementSizeForType<T>(), defaultValue);
......@@ -213,7 +213,7 @@ struct List<T, Kind::STRUCT> {
inline uint size() const { return reader.size() / ELEMENTS; }
inline typename T::Reader operator[](uint index) const {
KJ_IREQUIRE(index < size());
return typename T::Reader(reader.getStructElement(index * ELEMENTS));
return typename T::Reader(reader.getStructElement(guarded(index) * ELEMENTS));
}
typedef _::IndexingIterator<const Reader, typename T::Reader> Iterator;
......@@ -245,7 +245,7 @@ struct List<T, Kind::STRUCT> {
inline uint size() const { return builder.size() / ELEMENTS; }
inline typename T::Builder operator[](uint index) {
KJ_IREQUIRE(index < size());
return typename T::Builder(builder.getStructElement(index * ELEMENTS));
return typename T::Builder(builder.getStructElement(guarded(index) * ELEMENTS));
}
inline void adoptWithCaveats(uint index, Orphan<T>&& orphan) {
......@@ -263,8 +263,8 @@ struct List<T, Kind::STRUCT> {
// We pass a zero-valued StructSize to asStruct() because we do not want the struct to be
// expanded under any circumstances. We're just going to throw it away anyway, and
// transferContentFrom() already carefully compares the struct sizes before transferring.
builder.getStructElement(index * ELEMENTS).transferContentFrom(
orphan.builder.asStruct(_::StructSize(0 * WORDS, 0 * POINTERS)));
builder.getStructElement(guarded(index) * ELEMENTS).transferContentFrom(
orphan.builder.asStruct(_::StructSize(ZERO * WORDS, ZERO * POINTERS)));
}
inline void setWithCaveats(uint index, const typename T::Reader& reader) {
// Mostly behaves like you'd expect `set` to behave, but with a caveat originating from
......@@ -278,7 +278,7 @@ struct List<T, Kind::STRUCT> {
// protocol. (Plus, it's easier to use anyhow.)
KJ_IREQUIRE(index < size());
builder.getStructElement(index * ELEMENTS).copyContentFrom(reader._reader);
builder.getStructElement(guarded(index) * ELEMENTS).copyContentFrom(reader._reader);
}
// There are no init(), set(), adopt(), or disown() methods for lists of structs because the
......@@ -303,7 +303,7 @@ struct List<T, Kind::STRUCT> {
private:
inline static _::ListBuilder initPointer(_::PointerBuilder builder, uint size) {
return builder.initStructList(size * ELEMENTS, _::structSize<T>());
return builder.initStructList(guarded(size) * ELEMENTS, _::structSize<T>());
}
inline static _::ListBuilder getFromPointer(_::PointerBuilder builder, const word* defaultValue) {
return builder.getStructList(_::structSize<T>(), defaultValue);
......@@ -335,8 +335,8 @@ struct List<List<T>, Kind::LIST> {
inline uint size() const { return reader.size() / ELEMENTS; }
inline typename List<T>::Reader operator[](uint index) const {
KJ_IREQUIRE(index < size());
return typename List<T>::Reader(
_::PointerHelpers<List<T>>::get(reader.getPointerElement(index * ELEMENTS)));
return typename List<T>::Reader(_::PointerHelpers<List<T>>::get(
reader.getPointerElement(guarded(index) * ELEMENTS)));
}
typedef _::IndexingIterator<const Reader, typename List<T>::Reader> Iterator;
......@@ -368,17 +368,17 @@ struct List<List<T>, Kind::LIST> {
inline uint size() const { return builder.size() / ELEMENTS; }
inline typename List<T>::Builder operator[](uint index) {
KJ_IREQUIRE(index < size());
return typename List<T>::Builder(
_::PointerHelpers<List<T>>::get(builder.getPointerElement(index * ELEMENTS)));
return typename List<T>::Builder(_::PointerHelpers<List<T>>::get(
builder.getPointerElement(guarded(index) * ELEMENTS)));
}
inline typename List<T>::Builder init(uint index, uint size) {
KJ_IREQUIRE(index < this->size());
return typename List<T>::Builder(
_::PointerHelpers<List<T>>::init(builder.getPointerElement(index * ELEMENTS), size));
return typename List<T>::Builder(_::PointerHelpers<List<T>>::init(
builder.getPointerElement(guarded(index) * ELEMENTS), size));
}
inline void set(uint index, typename List<T>::Reader value) {
KJ_IREQUIRE(index < size());
builder.getPointerElement(index * ELEMENTS).setList(value.reader);
builder.getPointerElement(guarded(index) * ELEMENTS).setList(value.reader);
}
void set(uint index, std::initializer_list<ReaderFor<T>> value) {
KJ_IREQUIRE(index < size());
......@@ -390,11 +390,11 @@ struct List<List<T>, Kind::LIST> {
}
inline void adopt(uint index, Orphan<T>&& value) {
KJ_IREQUIRE(index < size());
builder.getPointerElement(index * ELEMENTS).adopt(kj::mv(value.builder));
builder.getPointerElement(guarded(index) * ELEMENTS).adopt(kj::mv(value.builder));
}
inline Orphan<T> disown(uint index) {
KJ_IREQUIRE(index < size());
return Orphan<T>(builder.getPointerElement(index * ELEMENTS).disown());
return Orphan<T>(builder.getPointerElement(guarded(index) * ELEMENTS).disown());
}
typedef _::IndexingIterator<Builder, typename List<T>::Builder> Iterator;
......@@ -414,7 +414,7 @@ struct List<List<T>, Kind::LIST> {
private:
inline static _::ListBuilder initPointer(_::PointerBuilder builder, uint size) {
return builder.initList(ElementSize::POINTER, size * ELEMENTS);
return builder.initList(ElementSize::POINTER, guarded(size) * ELEMENTS);
}
inline static _::ListBuilder getFromPointer(_::PointerBuilder builder, const word* defaultValue) {
return builder.getList(ElementSize::POINTER, defaultValue);
......@@ -444,7 +444,8 @@ struct List<T, Kind::BLOB> {
inline uint size() const { return reader.size() / ELEMENTS; }
inline typename T::Reader operator[](uint index) const {
KJ_IREQUIRE(index < size());
return reader.getPointerElement(index * ELEMENTS).template getBlob<T>(nullptr, 0 * BYTES);
return reader.getPointerElement(guarded(index) * ELEMENTS)
.template getBlob<T>(nullptr, ZERO * BYTES);
}
typedef _::IndexingIterator<const Reader, typename T::Reader> Iterator;
......@@ -476,23 +477,25 @@ struct List<T, Kind::BLOB> {
inline uint size() const { return builder.size() / ELEMENTS; }
inline typename T::Builder operator[](uint index) {
KJ_IREQUIRE(index < size());
return builder.getPointerElement(index * ELEMENTS).template getBlob<T>(nullptr, 0 * BYTES);
return builder.getPointerElement(guarded(index) * ELEMENTS)
.template getBlob<T>(nullptr, ZERO * BYTES);
}
inline void set(uint index, typename T::Reader value) {
KJ_IREQUIRE(index < size());
builder.getPointerElement(index * ELEMENTS).template setBlob<T>(value);
builder.getPointerElement(guarded(index) * ELEMENTS).template setBlob<T>(value);
}
inline typename T::Builder init(uint index, uint size) {
KJ_IREQUIRE(index < this->size());
return builder.getPointerElement(index * ELEMENTS).template initBlob<T>(size * BYTES);
return builder.getPointerElement(guarded(index) * ELEMENTS)
.template initBlob<T>(guarded(size) * BYTES);
}
inline void adopt(uint index, Orphan<T>&& value) {
KJ_IREQUIRE(index < size());
builder.getPointerElement(index * ELEMENTS).adopt(kj::mv(value.builder));
builder.getPointerElement(guarded(index) * ELEMENTS).adopt(kj::mv(value.builder));
}
inline Orphan<T> disown(uint index) {
KJ_IREQUIRE(index < size());
return Orphan<T>(builder.getPointerElement(index * ELEMENTS).disown());
return Orphan<T>(builder.getPointerElement(guarded(index) * ELEMENTS).disown());
}
typedef _::IndexingIterator<Builder, typename T::Builder> Iterator;
......@@ -512,7 +515,7 @@ struct List<T, Kind::BLOB> {
private:
inline static _::ListBuilder initPointer(_::PointerBuilder builder, uint size) {
return builder.initList(ElementSize::POINTER, size * ELEMENTS);
return builder.initList(ElementSize::POINTER, guarded(size) * ELEMENTS);
}
inline static _::ListBuilder getFromPointer(_::PointerBuilder builder, const word* defaultValue) {
return builder.getList(ElementSize::POINTER, defaultValue);
......
......@@ -135,7 +135,7 @@ _::SegmentBuilder* MessageBuilder::getRootSegment() {
KJ_ASSERT(allocation.segment->getSegmentId() == _::SegmentId(0),
"First allocated word of new arena was not in segment ID 0.");
KJ_ASSERT(allocation.words == allocation.segment->getPtrUnchecked(0 * WORDS),
KJ_ASSERT(allocation.words == allocation.segment->getPtrUnchecked(ZERO * WORDS),
"First allocated word of new arena was not the first word in its segment.");
return allocation.segment;
}
......@@ -144,7 +144,7 @@ _::SegmentBuilder* MessageBuilder::getRootSegment() {
AnyPointer::Builder MessageBuilder::getRootInternal() {
_::SegmentBuilder* rootSegment = getRootSegment();
return AnyPointer::Builder(_::PointerBuilder::getRoot(
rootSegment, arena()->getLocalCapTable(), rootSegment->getPtrUnchecked(0 * WORDS)));
rootSegment, arena()->getLocalCapTable(), rootSegment->getPtrUnchecked(ZERO * WORDS)));
}
kj::ArrayPtr<const kj::ArrayPtr<const word>> MessageBuilder::getSegmentsForOutput() {
......
......@@ -307,17 +307,17 @@ inline ReaderFor<T> Orphan<T>::getReader() const {
template <typename T>
inline void Orphan<T>::truncate(uint size) {
_::OrphanGetImpl<ListElementType<T>>::truncateListOf(builder, size * ELEMENTS);
_::OrphanGetImpl<ListElementType<T>>::truncateListOf(builder, guarded(size) * ELEMENTS);
}
template <>
inline void Orphan<Text>::truncate(uint size) {
builder.truncateText(size * ELEMENTS);
builder.truncateText(guarded(size) * ELEMENTS);
}
template <>
inline void Orphan<Data>::truncate(uint size) {
builder.truncate(size * ELEMENTS, ElementSize::BYTE);
builder.truncate(guarded(size) * ELEMENTS, ElementSize::BYTE);
}
template <typename T>
......@@ -350,7 +350,7 @@ struct Orphanage::NewOrphanListImpl<List<T, k>> {
static inline _::OrphanBuilder apply(
_::BuilderArena* arena, _::CapTableBuilder* capTable, uint size) {
return _::OrphanBuilder::initList(
arena, capTable, size * ELEMENTS, _::ElementSizeForType<T>::value);
arena, capTable, guarded(size) * ELEMENTS, _::ElementSizeForType<T>::value);
}
};
......@@ -359,7 +359,7 @@ struct Orphanage::NewOrphanListImpl<List<T, Kind::STRUCT>> {
static inline _::OrphanBuilder apply(
_::BuilderArena* arena, _::CapTableBuilder* capTable, uint size) {
return _::OrphanBuilder::initStructList(
arena, capTable, size * ELEMENTS, _::structSize<T>());
arena, capTable, guarded(size) * ELEMENTS, _::structSize<T>());
}
};
......@@ -367,7 +367,7 @@ template <>
struct Orphanage::NewOrphanListImpl<Text> {
static inline _::OrphanBuilder apply(
_::BuilderArena* arena, _::CapTableBuilder* capTable, uint size) {
return _::OrphanBuilder::initText(arena, capTable, size * BYTES);
return _::OrphanBuilder::initText(arena, capTable, guarded(size) * BYTES);
}
};
......@@ -375,7 +375,7 @@ template <>
struct Orphanage::NewOrphanListImpl<Data> {
static inline _::OrphanBuilder apply(
_::BuilderArena* arena, _::CapTableBuilder* capTable, uint size) {
return _::OrphanBuilder::initData(arena, capTable, size * BYTES);
return _::OrphanBuilder::initData(arena, capTable, guarded(size) * BYTES);
}
};
......
......@@ -113,12 +113,12 @@ struct PointerHelpers<T, Kind::BLOB> {
static inline typename T::Reader get(PointerReader reader,
const void* defaultValue = nullptr,
uint defaultBytes = 0) {
return reader.getBlob<T>(defaultValue, defaultBytes * BYTES);
return reader.getBlob<T>(defaultValue, guarded(defaultBytes) * BYTES);
}
static inline typename T::Builder get(PointerBuilder builder,
const void* defaultValue = nullptr,
uint defaultBytes = 0) {
return builder.getBlob<T>(defaultValue, defaultBytes * BYTES);
return builder.getBlob<T>(defaultValue, guarded(defaultBytes) * BYTES);
}
static inline void set(PointerBuilder builder, typename T::Reader value) {
builder.setBlob<T>(value);
......@@ -127,7 +127,7 @@ struct PointerHelpers<T, Kind::BLOB> {
builder.setBlob<T>(value);
}
static inline typename T::Builder init(PointerBuilder builder, uint size) {
return builder.initBlob<T>(size * BYTES);
return builder.initBlob<T>(guarded(size) * BYTES);
}
static inline void adopt(PointerBuilder builder, Orphan<T>&& value) {
builder.adopt(kj::mv(value.builder));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment