Mercurial > hg > sv-dependency-builds
comparison osx/include/capnp/arena.h @ 134:41e769c91eca
Add Capnp and KJ builds for OSX
author | Chris Cannam <cannam@all-day-breakfast.com> |
---|---|
date | Tue, 25 Oct 2016 14:48:23 +0100 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
133:1ac99bfc383d | 134:41e769c91eca |
---|---|
1 // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors | |
2 // Licensed under the MIT License: | |
3 // | |
4 // Permission is hereby granted, free of charge, to any person obtaining a copy | |
5 // of this software and associated documentation files (the "Software"), to deal | |
6 // in the Software without restriction, including without limitation the rights | |
7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
8 // copies of the Software, and to permit persons to whom the Software is | |
9 // furnished to do so, subject to the following conditions: | |
10 // | |
11 // The above copyright notice and this permission notice shall be included in | |
12 // all copies or substantial portions of the Software. | |
13 // | |
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
20 // THE SOFTWARE. | |
21 | |
22 #ifndef CAPNP_ARENA_H_ | |
23 #define CAPNP_ARENA_H_ | |
24 | |
25 #if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) | |
26 #pragma GCC system_header | |
27 #endif | |
28 | |
29 #ifndef CAPNP_PRIVATE | |
30 #error "This header is only meant to be included by Cap'n Proto's own source code." | |
31 #endif | |
32 | |
33 #include <kj/common.h> | |
34 #include <kj/mutex.h> | |
35 #include <kj/exception.h> | |
36 #include <kj/vector.h> | |
37 #include "common.h" | |
38 #include "message.h" | |
39 #include "layout.h" | |
40 #include <unordered_map> | |
41 | |
42 #if !CAPNP_LITE | |
43 #include "capability.h" | |
44 #endif // !CAPNP_LITE | |
45 | |
46 namespace capnp { | |
47 | |
48 #if !CAPNP_LITE | |
49 class ClientHook; | |
50 #endif // !CAPNP_LITE | |
51 | |
52 namespace _ { // private | |
53 | |
54 class SegmentReader; | |
55 class SegmentBuilder; | |
56 class Arena; | |
57 class BuilderArena; | |
58 class ReadLimiter; | |
59 | |
60 class Segment; | |
61 typedef kj::Id<uint32_t, Segment> SegmentId; | |
62 | |
63 class ReadLimiter { | |
64 // Used to keep track of how much data has been processed from a message, and cut off further | |
65 // processing if and when a particular limit is reached. This is primarily intended to guard | |
66 // against maliciously-crafted messages which contain cycles or overlapping structures. Cycles | |
67 // and overlapping are not permitted by the Cap'n Proto format because in many cases they could | |
68 // be used to craft a deceptively small message which could consume excessive server resources to | |
69 // process, perhaps even sending it into an infinite loop. Actually detecting overlaps would be | |
70 // time-consuming, so instead we just keep track of how many words worth of data structures the | |
71 // receiver has actually dereferenced and error out if this gets too high. | |
72 // | |
73 // This counting takes place as you call getters (for non-primitive values) on the message | |
74 // readers. If you call the same getter twice, the data it returns may be double-counted. This | |
75 // should not be a big deal in most cases -- just set the read limit high enough that it will | |
76 // only trigger in unreasonable cases. | |
77 // | |
78 // This class is "safe" to use from multiple threads for its intended use case. Threads may | |
79 // overwrite each others' changes to the counter, but this is OK because it only means that the | |
80 // limit is enforced a bit less strictly -- it will still kick in eventually. | |
81 | |
82 public: | |
83 inline explicit ReadLimiter(); // No limit. | |
84 inline explicit ReadLimiter(WordCount64 limit); // Limit to the given number of words. | |
85 | |
86 inline void reset(WordCount64 limit); | |
87 | |
88 KJ_ALWAYS_INLINE(bool canRead(WordCount amount, Arena* arena)); | |
89 | |
90 void unread(WordCount64 amount); | |
91 // Adds back some words to the limit. Useful when the caller knows they are double-reading | |
92 // some data. | |
93 | |
94 private: | |
95 volatile uint64_t limit; | |
96 // Current limit, decremented each time catRead() is called. Volatile because multiple threads | |
97 // could be trying to modify it at once. (This is not real thread-safety, but good enough for | |
98 // the purpose of this class. See class comment.) | |
99 | |
100 KJ_DISALLOW_COPY(ReadLimiter); | |
101 }; | |
102 | |
103 #if !CAPNP_LITE | |
104 class BrokenCapFactory { | |
105 // Callback for constructing broken caps. We use this so that we can avoid arena.c++ having a | |
106 // link-time dependency on capability code that lives in libcapnp-rpc. | |
107 | |
108 public: | |
109 virtual kj::Own<ClientHook> newBrokenCap(kj::StringPtr description) = 0; | |
110 virtual kj::Own<ClientHook> newNullCap() = 0; | |
111 }; | |
112 #endif // !CAPNP_LITE | |
113 | |
114 class SegmentReader { | |
115 public: | |
116 inline SegmentReader(Arena* arena, SegmentId id, kj::ArrayPtr<const word> ptr, | |
117 ReadLimiter* readLimiter); | |
118 | |
119 KJ_ALWAYS_INLINE(bool containsInterval(const void* from, const void* to)); | |
120 | |
121 KJ_ALWAYS_INLINE(bool amplifiedRead(WordCount virtualAmount)); | |
122 // Indicates that the reader should pretend that `virtualAmount` additional data was read even | |
123 // though no actual pointer was traversed. This is used e.g. when reading a struct list pointer | |
124 // where the element sizes are zero -- the sender could set the list size arbitrarily high and | |
125 // cause the receiver to iterate over this list even though the message itself is small, so we | |
126 // need to defend against DoS attacks based on this. | |
127 | |
128 inline Arena* getArena(); | |
129 inline SegmentId getSegmentId(); | |
130 | |
131 inline const word* getStartPtr(); | |
132 inline WordCount getOffsetTo(const word* ptr); | |
133 inline WordCount getSize(); | |
134 | |
135 inline kj::ArrayPtr<const word> getArray(); | |
136 | |
137 inline void unread(WordCount64 amount); | |
138 // Add back some words to the ReadLimiter. | |
139 | |
140 private: | |
141 Arena* arena; | |
142 SegmentId id; | |
143 kj::ArrayPtr<const word> ptr; | |
144 ReadLimiter* readLimiter; | |
145 | |
146 KJ_DISALLOW_COPY(SegmentReader); | |
147 | |
148 friend class SegmentBuilder; | |
149 }; | |
150 | |
151 class SegmentBuilder: public SegmentReader { | |
152 public: | |
153 inline SegmentBuilder(BuilderArena* arena, SegmentId id, kj::ArrayPtr<word> ptr, | |
154 ReadLimiter* readLimiter, size_t wordsUsed = 0); | |
155 inline SegmentBuilder(BuilderArena* arena, SegmentId id, kj::ArrayPtr<const word> ptr, | |
156 ReadLimiter* readLimiter); | |
157 inline SegmentBuilder(BuilderArena* arena, SegmentId id, decltype(nullptr), | |
158 ReadLimiter* readLimiter); | |
159 | |
160 KJ_ALWAYS_INLINE(word* allocate(WordCount amount)); | |
161 | |
162 KJ_ALWAYS_INLINE(void checkWritable()); | |
163 // Throw an exception if the segment is read-only (meaning it is a reference to external data). | |
164 | |
165 KJ_ALWAYS_INLINE(word* getPtrUnchecked(WordCount offset)); | |
166 // Get a writable pointer into the segment. Throws an exception if the segment is read-only (i.e. | |
167 // a reference to external immutable data). | |
168 | |
169 inline BuilderArena* getArena(); | |
170 | |
171 inline kj::ArrayPtr<const word> currentlyAllocated(); | |
172 | |
173 inline void reset(); | |
174 | |
175 inline bool isWritable() { return !readOnly; } | |
176 | |
177 inline void tryTruncate(word* from, word* to); | |
178 // If `from` points just past the current end of the segment, then move the end back to `to`. | |
179 // Otherwise, do nothing. | |
180 | |
181 inline bool tryExtend(word* from, word* to); | |
182 // If `from` points just past the current end of the segment, and `to` is within the segment | |
183 // boundaries, then move the end up to `to` and return true. Otherwise, do nothing and return | |
184 // false. | |
185 | |
186 private: | |
187 word* pos; | |
188 // Pointer to a pointer to the current end point of the segment, i.e. the location where the | |
189 // next object should be allocated. | |
190 | |
191 bool readOnly; | |
192 | |
193 void throwNotWritable(); | |
194 | |
195 KJ_DISALLOW_COPY(SegmentBuilder); | |
196 }; | |
197 | |
198 class Arena { | |
199 public: | |
200 virtual ~Arena() noexcept(false); | |
201 | |
202 virtual SegmentReader* tryGetSegment(SegmentId id) = 0; | |
203 // Gets the segment with the given ID, or return nullptr if no such segment exists. | |
204 | |
205 virtual void reportReadLimitReached() = 0; | |
206 // Called to report that the read limit has been reached. See ReadLimiter, below. This invokes | |
207 // the VALIDATE_INPUT() macro which may throw an exception; if it returns normally, the caller | |
208 // will need to continue with default values. | |
209 }; | |
210 | |
211 class ReaderArena final: public Arena { | |
212 public: | |
213 ReaderArena(MessageReader* message); | |
214 ~ReaderArena() noexcept(false); | |
215 KJ_DISALLOW_COPY(ReaderArena); | |
216 | |
217 // implements Arena ------------------------------------------------ | |
218 SegmentReader* tryGetSegment(SegmentId id) override; | |
219 void reportReadLimitReached() override; | |
220 | |
221 private: | |
222 MessageReader* message; | |
223 ReadLimiter readLimiter; | |
224 | |
225 // Optimize for single-segment messages so that small messages are handled quickly. | |
226 SegmentReader segment0; | |
227 | |
228 typedef std::unordered_map<uint, kj::Own<SegmentReader>> SegmentMap; | |
229 kj::MutexGuarded<kj::Maybe<kj::Own<SegmentMap>>> moreSegments; | |
230 // We need to mutex-guard the segment map because we lazily initialize segments when they are | |
231 // first requested, but a Reader is allowed to be used concurrently in multiple threads. Luckily | |
232 // this only applies to large messages. | |
233 // | |
234 // TODO(perf): Thread-local thing instead? Some kind of lockless map? Or do sharing of data | |
235 // in a different way, where you have to construct a new MessageReader in each thread (but | |
236 // possibly backed by the same data)? | |
237 }; | |
238 | |
239 class BuilderArena final: public Arena { | |
240 // A BuilderArena that does not allow the injection of capabilities. | |
241 | |
242 public: | |
243 explicit BuilderArena(MessageBuilder* message); | |
244 BuilderArena(MessageBuilder* message, kj::ArrayPtr<MessageBuilder::SegmentInit> segments); | |
245 ~BuilderArena() noexcept(false); | |
246 KJ_DISALLOW_COPY(BuilderArena); | |
247 | |
248 inline SegmentBuilder* getRootSegment() { return &segment0; } | |
249 | |
250 kj::ArrayPtr<const kj::ArrayPtr<const word>> getSegmentsForOutput(); | |
251 // Get an array of all the segments, suitable for writing out. This only returns the allocated | |
252 // portion of each segment, whereas tryGetSegment() returns something that includes | |
253 // not-yet-allocated space. | |
254 | |
255 inline CapTableBuilder* getLocalCapTable() { | |
256 // Return a CapTableBuilder that merely implements local loopback. That is, you can set | |
257 // capabilities, then read the same capabilities back, but there is no intent ever to transmit | |
258 // these capabilities. A MessageBuilder that isn't imbued with some other CapTable uses this | |
259 // by default. | |
260 // | |
261 // TODO(cleanup): It's sort of a hack that this exists. In theory, perhaps, unimbued | |
262 // MessageBuilders should throw exceptions on any attempt to access capability fields, like | |
263 // unimbued MessageReaders do. However, lots of code exists which uses MallocMessageBuilder | |
264 // as a temporary holder for data to be copied in and out (without being serialized), and it | |
265 // is expected that such data can include capabilities, which is admittedly reasonable. | |
266 // Therefore, all MessageBuilders must have a cap table by default. Arguably we should | |
267 // deprecate this usage and instead define a new helper type for this exact purpose. | |
268 | |
269 return &localCapTable; | |
270 } | |
271 | |
272 SegmentBuilder* getSegment(SegmentId id); | |
273 // Get the segment with the given id. Crashes or throws an exception if no such segment exists. | |
274 | |
275 struct AllocateResult { | |
276 SegmentBuilder* segment; | |
277 word* words; | |
278 }; | |
279 | |
280 AllocateResult allocate(WordCount amount); | |
281 // Find a segment with at least the given amount of space available and allocate the space. | |
282 // Note that allocating directly from a particular segment is much faster, but allocating from | |
283 // the arena is guaranteed to succeed. Therefore callers should try to allocate from a specific | |
284 // segment first if there is one, then fall back to the arena. | |
285 | |
286 SegmentBuilder* addExternalSegment(kj::ArrayPtr<const word> content); | |
287 // Add a new segment to the arena which points to some existing memory region. The segment is | |
288 // assumed to be completley full; the arena will never allocate from it. In fact, the segment | |
289 // is considered read-only. Any attempt to get a Builder pointing into this segment will throw | |
290 // an exception. Readers are allowed, however. | |
291 // | |
292 // This can be used to inject some external data into a message without a copy, e.g. embedding a | |
293 // large mmap'd file into a message as `Data` without forcing that data to actually be read in | |
294 // from disk (until the message itself is written out). `Orphanage` provides the public API for | |
295 // this feature. | |
296 | |
297 // implements Arena ------------------------------------------------ | |
298 SegmentReader* tryGetSegment(SegmentId id) override; | |
299 void reportReadLimitReached() override; | |
300 | |
301 private: | |
302 MessageBuilder* message; | |
303 ReadLimiter dummyLimiter; | |
304 | |
305 class LocalCapTable: public CapTableBuilder { | |
306 #if !CAPNP_LITE | |
307 public: | |
308 kj::Maybe<kj::Own<ClientHook>> extractCap(uint index) override; | |
309 uint injectCap(kj::Own<ClientHook>&& cap) override; | |
310 void dropCap(uint index) override; | |
311 | |
312 private: | |
313 kj::Vector<kj::Maybe<kj::Own<ClientHook>>> capTable; | |
314 #endif // ! CAPNP_LITE | |
315 }; | |
316 | |
317 LocalCapTable localCapTable; | |
318 | |
319 SegmentBuilder segment0; | |
320 kj::ArrayPtr<const word> segment0ForOutput; | |
321 | |
322 struct MultiSegmentState { | |
323 kj::Vector<kj::Own<SegmentBuilder>> builders; | |
324 kj::Vector<kj::ArrayPtr<const word>> forOutput; | |
325 }; | |
326 kj::Maybe<kj::Own<MultiSegmentState>> moreSegments; | |
327 | |
328 SegmentBuilder* segmentWithSpace = nullptr; | |
329 // When allocating, look for space in this segment first before resorting to allocating a new | |
330 // segment. This is not necessarily the last segment because addExternalSegment() may add a | |
331 // segment that is already-full, in which case we don't update this pointer. | |
332 | |
333 template <typename T> // Can be `word` or `const word`. | |
334 SegmentBuilder* addSegmentInternal(kj::ArrayPtr<T> content); | |
335 }; | |
336 | |
337 // ======================================================================================= | |
338 | |
339 inline ReadLimiter::ReadLimiter() | |
340 : limit(kj::maxValue) {} | |
341 | |
342 inline ReadLimiter::ReadLimiter(WordCount64 limit): limit(limit / WORDS) {} | |
343 | |
344 inline void ReadLimiter::reset(WordCount64 limit) { this->limit = limit / WORDS; } | |
345 | |
346 inline bool ReadLimiter::canRead(WordCount amount, Arena* arena) { | |
347 // Be careful not to store an underflowed value into `limit`, even if multiple threads are | |
348 // decrementing it. | |
349 uint64_t current = limit; | |
350 if (KJ_UNLIKELY(amount / WORDS > current)) { | |
351 arena->reportReadLimitReached(); | |
352 return false; | |
353 } else { | |
354 limit = current - amount / WORDS; | |
355 return true; | |
356 } | |
357 } | |
358 | |
359 // ------------------------------------------------------------------- | |
360 | |
361 inline SegmentReader::SegmentReader(Arena* arena, SegmentId id, kj::ArrayPtr<const word> ptr, | |
362 ReadLimiter* readLimiter) | |
363 : arena(arena), id(id), ptr(ptr), readLimiter(readLimiter) {} | |
364 | |
365 inline bool SegmentReader::containsInterval(const void* from, const void* to) { | |
366 return from >= this->ptr.begin() && to <= this->ptr.end() && from <= to && | |
367 readLimiter->canRead( | |
368 intervalLength(reinterpret_cast<const byte*>(from), | |
369 reinterpret_cast<const byte*>(to)) / BYTES_PER_WORD, | |
370 arena); | |
371 } | |
372 | |
373 inline bool SegmentReader::amplifiedRead(WordCount virtualAmount) { | |
374 return readLimiter->canRead(virtualAmount, arena); | |
375 } | |
376 | |
377 inline Arena* SegmentReader::getArena() { return arena; } | |
378 inline SegmentId SegmentReader::getSegmentId() { return id; } | |
379 inline const word* SegmentReader::getStartPtr() { return ptr.begin(); } | |
380 inline WordCount SegmentReader::getOffsetTo(const word* ptr) { | |
381 return intervalLength(this->ptr.begin(), ptr); | |
382 } | |
383 inline WordCount SegmentReader::getSize() { return ptr.size() * WORDS; } | |
384 inline kj::ArrayPtr<const word> SegmentReader::getArray() { return ptr; } | |
385 inline void SegmentReader::unread(WordCount64 amount) { readLimiter->unread(amount); } | |
386 | |
387 // ------------------------------------------------------------------- | |
388 | |
389 inline SegmentBuilder::SegmentBuilder( | |
390 BuilderArena* arena, SegmentId id, kj::ArrayPtr<word> ptr, ReadLimiter* readLimiter, | |
391 size_t wordsUsed) | |
392 : SegmentReader(arena, id, ptr, readLimiter), pos(ptr.begin() + wordsUsed), readOnly(false) {} | |
393 inline SegmentBuilder::SegmentBuilder( | |
394 BuilderArena* arena, SegmentId id, kj::ArrayPtr<const word> ptr, ReadLimiter* readLimiter) | |
395 : SegmentReader(arena, id, ptr, readLimiter), | |
396 // const_cast is safe here because the member won't ever be dereferenced because it appears | |
397 // to point to the end of the segment anyway. | |
398 pos(const_cast<word*>(ptr.end())), | |
399 readOnly(true) {} | |
400 inline SegmentBuilder::SegmentBuilder(BuilderArena* arena, SegmentId id, decltype(nullptr), | |
401 ReadLimiter* readLimiter) | |
402 : SegmentReader(arena, id, nullptr, readLimiter), pos(nullptr), readOnly(false) {} | |
403 | |
404 inline word* SegmentBuilder::allocate(WordCount amount) { | |
405 if (intervalLength(pos, ptr.end()) < amount) { | |
406 // Not enough space in the segment for this allocation. | |
407 return nullptr; | |
408 } else { | |
409 // Success. | |
410 word* result = pos; | |
411 pos = pos + amount; | |
412 return result; | |
413 } | |
414 } | |
415 | |
416 inline void SegmentBuilder::checkWritable() { | |
417 if (KJ_UNLIKELY(readOnly)) throwNotWritable(); | |
418 } | |
419 | |
420 inline word* SegmentBuilder::getPtrUnchecked(WordCount offset) { | |
421 return const_cast<word*>(ptr.begin() + offset); | |
422 } | |
423 | |
424 inline BuilderArena* SegmentBuilder::getArena() { | |
425 // Down-cast safe because SegmentBuilder's constructor always initializes its SegmentReader base | |
426 // class with an Arena pointer that actually points to a BuilderArena. | |
427 return static_cast<BuilderArena*>(arena); | |
428 } | |
429 | |
430 inline kj::ArrayPtr<const word> SegmentBuilder::currentlyAllocated() { | |
431 return kj::arrayPtr(ptr.begin(), pos - ptr.begin()); | |
432 } | |
433 | |
434 inline void SegmentBuilder::reset() { | |
435 word* start = getPtrUnchecked(0 * WORDS); | |
436 memset(start, 0, (pos - start) * sizeof(word)); | |
437 pos = start; | |
438 } | |
439 | |
440 inline void SegmentBuilder::tryTruncate(word* from, word* to) { | |
441 if (pos == from) pos = to; | |
442 } | |
443 | |
444 inline bool SegmentBuilder::tryExtend(word* from, word* to) { | |
445 // Careful about overflow. | |
446 if (pos == from && to <= ptr.end() && to >= from) { | |
447 pos = to; | |
448 return true; | |
449 } else { | |
450 return false; | |
451 } | |
452 } | |
453 | |
454 } // namespace _ (private) | |
455 } // namespace capnp | |
456 | |
457 #endif // CAPNP_ARENA_H_ |