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