Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
C
capnproto
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
capnproto
Commits
9c3cb05f
Commit
9c3cb05f
authored
Mar 18, 2013
by
Kenton Varda
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Another iteration of refactoring the Message classes.
parent
fe29fa08
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
171 additions
and
198 deletions
+171
-198
arena.c++
c++/src/capnproto/arena.c++
+21
-11
arena.h
c++/src/capnproto/arena.h
+5
-6
encoding-test.c++
c++/src/capnproto/encoding-test.c++
+35
-33
message-internal.h
c++/src/capnproto/message-internal.h
+0
-112
message.c++
c++/src/capnproto/message.c++
+0
-0
message.h
c++/src/capnproto/message.h
+0
-0
type-safety.h
c++/src/capnproto/type-safety.h
+73
-2
wire-format-test.c++
c++/src/capnproto/wire-format-test.c++
+6
-3
wire-format.c++
c++/src/capnproto/wire-format.c++
+20
-20
wire-format.h
c++/src/capnproto/wire-format.h
+11
-11
No files found.
c++/src/capnproto/arena.c++
View file @
9c3cb05f
...
...
@@ -34,10 +34,11 @@ Arena::~Arena() {}
// =======================================================================================
ReaderArena
::
ReaderArena
(
std
::
unique_ptr
<
ReaderContext
>
context
)
:
context
(
std
::
move
(
context
)),
readLimiter
(
this
->
context
->
getReadLimit
()
*
WORDS
),
segment0
(
this
,
SegmentId
(
0
),
this
->
context
->
getSegment
(
0
),
&
readLimiter
)
{}
ReaderArena
::
ReaderArena
(
MessageReader
*
message
)
:
message
(
message
),
readLimiter
(
this
->
message
->
getOptions
().
traversalLimitInWords
*
WORDS
),
ignoreErrors
(
false
),
segment0
(
this
,
SegmentId
(
0
),
this
->
message
->
getSegment
(
0
),
&
readLimiter
)
{}
ReaderArena
::~
ReaderArena
()
{}
...
...
@@ -61,7 +62,7 @@ SegmentReader* ReaderArena::tryGetSegment(SegmentId id) {
}
}
ArrayPtr
<
const
word
>
newSegment
=
context
->
getSegment
(
id
.
value
);
ArrayPtr
<
const
word
>
newSegment
=
message
->
getSegment
(
id
.
value
);
if
(
newSegment
==
nullptr
)
{
return
nullptr
;
}
...
...
@@ -77,17 +78,26 @@ SegmentReader* ReaderArena::tryGetSegment(SegmentId id) {
}
void
ReaderArena
::
reportInvalidData
(
const
char
*
description
)
{
context
->
reportError
(
description
);
if
(
!
ignoreErrors
)
{
message
->
getOptions
().
errorReporter
->
reportError
(
description
);
}
}
void
ReaderArena
::
reportReadLimitReached
()
{
context
->
reportError
(
"Exceeded read limit."
);
if
(
!
ignoreErrors
)
{
message
->
getOptions
().
errorReporter
->
reportError
(
"Exceeded message traversal limit. See capnproto::ReaderOptions."
);
// Ignore further errors since they are likely repeats or caused by the read limit being
// reached.
ignoreErrors
=
true
;
}
}
// =======================================================================================
BuilderArena
::
BuilderArena
(
std
::
unique_ptr
<
BuilderContext
>
context
)
:
context
(
std
::
move
(
context
)
),
segment0
(
nullptr
,
SegmentId
(
0
),
nullptr
,
nullptr
)
{}
BuilderArena
::
BuilderArena
(
MessageBuilder
*
message
)
:
message
(
message
),
segment0
(
nullptr
,
SegmentId
(
0
),
nullptr
,
nullptr
)
{}
BuilderArena
::~
BuilderArena
()
{}
SegmentBuilder
*
BuilderArena
::
getSegment
(
SegmentId
id
)
{
...
...
@@ -105,7 +115,7 @@ SegmentBuilder* BuilderArena::getSegmentWithAvailable(WordCount minimumAvailable
if
(
segment0
.
getArena
()
==
nullptr
)
{
// We're allocating the first segment.
ArrayPtr
<
word
>
ptr
=
context
->
allocateSegment
(
minimumAvailable
/
WORDS
);
ArrayPtr
<
word
>
ptr
=
message
->
allocateSegment
(
minimumAvailable
/
WORDS
);
// 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.
...
...
@@ -132,7 +142,7 @@ SegmentBuilder* BuilderArena::getSegmentWithAvailable(WordCount minimumAvailable
std
::
unique_ptr
<
SegmentBuilder
>
newBuilder
=
std
::
unique_ptr
<
SegmentBuilder
>
(
new
SegmentBuilder
(
this
,
SegmentId
(
moreSegments
->
builders
.
size
()
+
1
),
context
->
allocateSegment
(
minimumAvailable
/
WORDS
),
&
this
->
dummyLimiter
));
message
->
allocateSegment
(
minimumAvailable
/
WORDS
),
&
this
->
dummyLimiter
));
SegmentBuilder
*
result
=
newBuilder
.
get
();
moreSegments
->
builders
.
push_back
(
std
::
move
(
newBuilder
));
...
...
c++/src/capnproto/arena.h
View file @
9c3cb05f
...
...
@@ -116,8 +116,6 @@ private:
word
*
pos
;
CAPNPROTO_DISALLOW_COPY
(
SegmentBuilder
);
// TODO: Do we need mutex locking?
};
class
Arena
{
...
...
@@ -158,7 +156,7 @@ public:
class
ReaderArena
final
:
public
Arena
{
public
:
ReaderArena
(
std
::
unique_ptr
<
ReaderContext
>
context
);
ReaderArena
(
MessageReader
*
message
);
~
ReaderArena
();
CAPNPROTO_DISALLOW_COPY
(
ReaderArena
);
...
...
@@ -168,8 +166,9 @@ public:
void
reportReadLimitReached
()
override
;
private
:
std
::
unique_ptr
<
ReaderContext
>
context
;
MessageReader
*
message
;
ReadLimiter
readLimiter
;
bool
ignoreErrors
;
// Optimize for single-segment messages so that small messages are handled quickly.
SegmentReader
segment0
;
...
...
@@ -180,7 +179,7 @@ private:
class
BuilderArena
final
:
public
Arena
{
public
:
BuilderArena
(
std
::
unique_ptr
<
BuilderContext
>
context
);
BuilderArena
(
MessageBuilder
*
message
);
~
BuilderArena
();
CAPNPROTO_DISALLOW_COPY
(
BuilderArena
);
...
...
@@ -204,7 +203,7 @@ public:
void
reportReadLimitReached
()
override
;
private
:
std
::
unique_ptr
<
BuilderContext
>
context
;
MessageBuilder
*
message
;
ReadLimiter
dummyLimiter
;
SegmentBuilder
segment0
;
...
...
c++/src/capnproto/encoding-test.c++
View file @
9c3cb05f
...
...
@@ -227,78 +227,80 @@ void checkMessage(Reader reader) {
}
TEST
(
Encoding
,
AllTypes
)
{
M
essage
<
TestAllTypes
>::
Builder
builder
;
M
allocMessage
Builder
builder
;
initMessage
(
builder
.
initRoot
());
checkMessage
(
builder
.
getRoot
());
checkMessage
(
builder
.
getRoot
().
asReader
());
initMessage
(
builder
.
initRoot
<
TestAllTypes
>
());
checkMessage
(
builder
.
getRoot
<
TestAllTypes
>
());
checkMessage
(
builder
.
getRoot
<
TestAllTypes
>
().
asReader
());
Message
<
TestAllTypes
>::
Reader
reader
(
builder
.
getSegmentsForOutput
());
SegmentArrayMessage
Reader
reader
(
builder
.
getSegmentsForOutput
());
checkMessage
(
reader
.
getRoot
());
checkMessage
(
reader
.
getRoot
<
TestAllTypes
>
());
ASSERT_EQ
(
1u
,
builder
.
getSegmentsForOutput
().
size
());
checkMessage
(
Message
<
TestAllTypes
>::
readTrusted
(
builder
.
getSegmentsForOutput
()[
0
].
begin
()));
checkMessage
(
readMessageTrusted
<
TestAllTypes
>
(
builder
.
getSegmentsForOutput
()[
0
].
begin
()));
}
TEST
(
Encoding
,
AllTypesMultiSegment
)
{
M
essage
<
TestAllTypes
>::
Builder
builder
(
newFixedWidthBuilderContext
(
0
)
);
M
allocMessageBuilder
builder
(
0
,
AllocationStrategy
::
FIXED_SIZE
);
initMessage
(
builder
.
initRoot
());
checkMessage
(
builder
.
getRoot
());
checkMessage
(
builder
.
getRoot
().
asReader
());
initMessage
(
builder
.
initRoot
<
TestAllTypes
>
());
checkMessage
(
builder
.
getRoot
<
TestAllTypes
>
());
checkMessage
(
builder
.
getRoot
<
TestAllTypes
>
().
asReader
());
Message
<
TestAllTypes
>::
Reader
reader
(
builder
.
getSegmentsForOutput
());
SegmentArrayMessage
Reader
reader
(
builder
.
getSegmentsForOutput
());
checkMessage
(
reader
.
getRoot
());
checkMessage
(
reader
.
getRoot
<
TestAllTypes
>
());
}
TEST
(
Encoding
,
Defaults
)
{
AlignedData
<
1
>
nullRoot
=
{{
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
}};
ArrayPtr
<
const
word
>
segments
[
1
]
=
{
arrayPtr
(
nullRoot
.
words
,
1
)};
Message
<
TestDefaults
>::
Reader
reader
(
arrayPtr
(
segments
,
1
));
SegmentArrayMessage
Reader
reader
(
arrayPtr
(
segments
,
1
));
checkMessage
(
reader
.
getRoot
());
checkMessage
(
Message
<
TestDefaults
>::
readTrusted
(
nullRoot
.
words
));
checkMessage
(
reader
.
getRoot
<
TestDefaults
>
());
checkMessage
(
readMessageTrusted
<
TestDefaults
>
(
nullRoot
.
words
));
}
TEST
(
Encoding
,
DefaultInitialization
)
{
M
essage
<
TestDefaults
>::
Builder
builder
;
M
allocMessage
Builder
builder
;
checkMessage
(
builder
.
getRoot
());
// first pass initializes to defaults
checkMessage
(
builder
.
getRoot
().
asReader
());
checkMessage
(
builder
.
getRoot
<
TestDefaults
>
());
// first pass initializes to defaults
checkMessage
(
builder
.
getRoot
<
TestDefaults
>
().
asReader
());
checkMessage
(
builder
.
getRoot
());
// second pass just reads the initialized structure
checkMessage
(
builder
.
getRoot
().
asReader
());
checkMessage
(
builder
.
getRoot
<
TestDefaults
>
());
// second pass just reads the initialized structure
checkMessage
(
builder
.
getRoot
<
TestDefaults
>
().
asReader
());
Message
<
TestDefaults
>::
Reader
reader
(
builder
.
getSegmentsForOutput
());
SegmentArrayMessage
Reader
reader
(
builder
.
getSegmentsForOutput
());
checkMessage
(
reader
.
getRoot
());
checkMessage
(
reader
.
getRoot
<
TestDefaults
>
());
}
TEST
(
Encoding
,
DefaultInitializationMultiSegment
)
{
M
essage
<
TestDefaults
>::
Builder
builder
(
newFixedWidthBuilderContext
(
0
)
);
M
allocMessageBuilder
builder
(
0
,
AllocationStrategy
::
FIXED_SIZE
);
checkMessage
(
builder
.
getRoot
());
// first pass initializes to defaults
checkMessage
(
builder
.
getRoot
().
asReader
());
// first pass initializes to defaults
checkMessage
(
builder
.
getRoot
<
TestDefaults
>
());
checkMessage
(
builder
.
getRoot
<
TestDefaults
>
().
asReader
());
checkMessage
(
builder
.
getRoot
());
// second pass just reads the initialized structure
checkMessage
(
builder
.
getRoot
().
asReader
());
// second pass just reads the initialized structure
checkMessage
(
builder
.
getRoot
<
TestDefaults
>
());
checkMessage
(
builder
.
getRoot
<
TestDefaults
>
().
asReader
());
Message
<
TestDefaults
>::
Reader
reader
(
builder
.
getSegmentsForOutput
());
SegmentArrayMessage
Reader
reader
(
builder
.
getSegmentsForOutput
());
checkMessage
(
reader
.
getRoot
());
checkMessage
(
reader
.
getRoot
<
TestDefaults
>
());
}
TEST
(
Encoding
,
DefaultsFromEmptyMessage
)
{
AlignedData
<
1
>
emptyMessage
=
{{
4
,
0
,
0
,
0
,
0
,
0
,
0
,
0
}};
ArrayPtr
<
const
word
>
segments
[
1
]
=
{
arrayPtr
(
emptyMessage
.
words
,
1
)};
Message
<
TestDefaults
>::
Reader
reader
(
arrayPtr
(
segments
,
1
));
SegmentArrayMessage
Reader
reader
(
arrayPtr
(
segments
,
1
));
checkMessage
(
reader
.
getRoot
());
checkMessage
(
Message
<
TestDefaults
>::
readTrusted
(
emptyMessage
.
words
));
checkMessage
(
reader
.
getRoot
<
TestDefaults
>
());
checkMessage
(
readMessageTrusted
<
TestDefaults
>
(
emptyMessage
.
words
));
}
}
// namespace
...
...
c++/src/capnproto/message-internal.h
deleted
100644 → 0
View file @
fe29fa08
// Copyright (c) 2013, Kenton Varda <temporal@gmail.com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// This header contains internal interfaces relied upon by message.h and implemented in message.c++.
// These declarations should be thought of as being part of message.h, but I moved them here to make
// message.h more readable. The problem is that the interface people really care about in
// message.h -- namely, Message -- has to be declared after internal::Message. Having an internal
// interface appear in the middle of the header ahead of the public interface was distracting and
// confusing.
#ifndef CAPNPROTO_MESSAGE_INTERNAL_H_
#define CAPNPROTO_MESSAGE_INTERNAL_H_
#include <cstddef>
#include <memory>
#include "type-safety.h"
#include "wire-format.h"
namespace
capnproto
{
class
ReaderContext
;
class
BuilderContext
;
}
namespace
capnproto
{
namespace
internal
{
// TODO: Move to message-internal.h so that this header looks nicer?
class
ReaderArena
;
class
BuilderArena
;
struct
MessageImpl
{
// Underlying implementation of capnproto::Message. All the parts that don't need to be templated
// are implemented by this class, so that they can be shared and non-inline.
MessageImpl
()
=
delete
;
class
Reader
{
public
:
Reader
(
ArrayPtr
<
const
ArrayPtr
<
const
word
>>
segments
);
Reader
(
std
::
unique_ptr
<
ReaderContext
>
context
);
Reader
(
Reader
&&
other
)
=
default
;
CAPNPROTO_DISALLOW_COPY
(
Reader
);
~
Reader
();
StructReader
getRoot
(
const
word
*
defaultValue
);
private
:
uint
recursionLimit
;
// Space in which we can construct a ReaderArena. We don't use ReaderArena directly here
// because we don't want clients to have to #include arena.h, which itself includes a bunch of
// big STL headers. We don't use a pointer to a ReaderArena because that would require an
// extra malloc on every message which could be expensive when processing small messages,
// particularly when the context itself is freelisted and so no other allocation is necessary.
void
*
arenaSpace
[
15
];
ReaderArena
*
arena
()
{
return
reinterpret_cast
<
ReaderArena
*>
(
arenaSpace
);
}
};
class
Builder
{
public
:
Builder
();
Builder
(
std
::
unique_ptr
<
BuilderContext
>
context
);
Builder
(
Builder
&&
other
)
=
default
;
CAPNPROTO_DISALLOW_COPY
(
Builder
);
~
Builder
();
StructBuilder
initRoot
(
const
word
*
defaultValue
);
StructBuilder
getRoot
(
const
word
*
defaultValue
);
ArrayPtr
<
const
ArrayPtr
<
const
word
>>
getSegmentsForOutput
();
private
:
SegmentBuilder
*
rootSegment
;
// Space in which we can construct a BuilderArena. We don't use BuilderArena directly here
// because we don't want clients to have to #include arena.h, which itself includes a bunch of
// big STL headers. We don't use a pointer to a BuilderArena because that would require an
// extra malloc on every message which could be expensive when processing small messages,
// particularly when the context itself is freelisted and so no other allocation is necessary.
void
*
arenaSpace
[
15
];
BuilderArena
*
arena
()
{
return
reinterpret_cast
<
BuilderArena
*>
(
arenaSpace
);
}
static
SegmentBuilder
*
allocateRoot
(
BuilderArena
*
arena
);
};
};
}
// namespace internal
}
// namespace capnproto
#endif // CAPNPROTO_MESSAGE_INTERNAL_H_
c++/src/capnproto/message.c++
View file @
9c3cb05f
This diff is collapsed.
Click to expand it.
c++/src/capnproto/message.h
View file @
9c3cb05f
This diff is collapsed.
Click to expand it.
c++/src/capnproto/type-safety.h
View file @
9c3cb05f
...
...
@@ -106,6 +106,77 @@ inline ArrayPtr<T> arrayPtr(T* begin, T* end) {
return
ArrayPtr
<
T
>
(
begin
,
end
);
}
template
<
typename
T
>
class
Array
{
// An owned array which will automatically be deleted in the destructor. Can be moved, but not
// copied.
public
:
inline
Array
()
:
ptr
(
nullptr
),
size_
(
0
)
{}
inline
Array
(
std
::
nullptr_t
)
:
ptr
(
nullptr
),
size_
(
0
)
{}
inline
Array
(
Array
&&
other
)
:
ptr
(
other
.
ptr
),
size_
(
other
.
size_
)
{
other
.
ptr
=
nullptr
;
other
.
size_
=
0
;
}
CAPNPROTO_DISALLOW_COPY
(
Array
);
inline
~
Array
()
noexcept
{
delete
[]
ptr
;
}
inline
operator
ArrayPtr
<
T
>
()
{
return
ArrayPtr
<
T
>
(
ptr
,
size_
);
}
inline
ArrayPtr
<
T
>
asPtr
()
{
return
ArrayPtr
<
T
>
(
ptr
,
size_
);
}
inline
std
::
size_t
size
()
const
{
return
size_
;
}
inline
T
&
operator
[](
std
::
size_t
index
)
const
{
CAPNPROTO_DEBUG_ASSERT
(
index
<
size_
,
"Out-of-bounds Array access."
);
return
ptr
[
index
];
}
inline
T
*
begin
()
const
{
return
ptr
;
}
inline
T
*
end
()
const
{
return
ptr
+
size_
;
}
inline
ArrayPtr
<
T
>
slice
(
size_t
start
,
size_t
end
)
{
CAPNPROTO_DEBUG_ASSERT
(
start
<=
end
&&
end
<=
size_
,
"Out-of-bounds Array::slice()."
);
return
ArrayPtr
<
T
>
(
ptr
+
start
,
end
-
start
);
}
inline
bool
operator
==
(
std
::
nullptr_t
)
{
return
ptr
==
nullptr
;
}
inline
bool
operator
!=
(
std
::
nullptr_t
)
{
return
ptr
!=
nullptr
;
}
inline
Array
&
operator
=
(
std
::
nullptr_t
)
{
delete
[]
ptr
;
ptr
=
nullptr
;
size_
=
0
;
return
*
this
;
}
inline
Array
&
operator
=
(
Array
&&
other
)
{
delete
[]
ptr
;
ptr
=
other
.
ptr
;
size_
=
other
.
size_
;
other
.
ptr
=
nullptr
;
other
.
size_
=
0
;
return
*
this
;
}
private
:
T
*
ptr
;
std
::
size_t
size_
;
inline
explicit
Array
(
std
::
size_t
size
)
:
ptr
(
new
T
[
size
]),
size_
(
size
)
{}
template
<
typename
U
>
friend
Array
<
U
>
newArray
(
size_t
size
);
};
template
<
typename
T
>
inline
Array
<
T
>
newArray
(
size_t
size
)
{
return
Array
<
T
>
(
size
);
}
// =======================================================================================
// IDs
...
...
@@ -381,8 +452,8 @@ inline constexpr auto operator*(UnitRatio<Number1, Unit2, Unit> ratio,
// =======================================================================================
// Raw memory types and measures
class
byte
{
uint8_t
content
;
CAPNPROTO_DISALLOW_COPY
(
byte
);
};
class
word
{
uint64_t
content
;
CAPNPROTO_DISALLOW_COPY
(
word
);
};
class
byte
{
uint8_t
content
;
CAPNPROTO_DISALLOW_COPY
(
byte
);
public
:
byte
()
=
default
;
};
class
word
{
uint64_t
content
;
CAPNPROTO_DISALLOW_COPY
(
word
);
public
:
word
()
=
default
;
};
// byte and word are opaque types with sizes of 8 and 64 bits, respectively. These types are useful
// only to make pointer arithmetic clearer. Since the contents are private, the only way to access
// them is to first reinterpret_cast to some other pointer type.
...
...
c++/src/capnproto/wire-format-test.c++
View file @
9c3cb05f
...
...
@@ -264,7 +264,8 @@ static void checkStruct(StructReader reader) {
}
TEST
(
WireFormat
,
StructRoundTrip_OneSegment
)
{
BuilderArena
arena
(
newBuilderContext
());
MallocMessageBuilder
message
;
BuilderArena
arena
(
&
message
);
SegmentBuilder
*
segment
=
arena
.
getSegmentWithAvailable
(
1
*
WORDS
);
word
*
rootLocation
=
segment
->
allocate
(
1
*
WORDS
);
...
...
@@ -298,7 +299,8 @@ TEST(WireFormat, StructRoundTrip_OneSegment) {
}
TEST
(
WireFormat
,
StructRoundTrip_OneSegmentPerAllocation
)
{
BuilderArena
arena
(
newFixedWidthBuilderContext
(
0
));
MallocMessageBuilder
message
(
0
,
AllocationStrategy
::
FIXED_SIZE
);
BuilderArena
arena
(
&
message
);
SegmentBuilder
*
segment
=
arena
.
getSegmentWithAvailable
(
1
*
WORDS
);
word
*
rootLocation
=
segment
->
allocate
(
1
*
WORDS
);
...
...
@@ -333,7 +335,8 @@ TEST(WireFormat, StructRoundTrip_OneSegmentPerAllocation) {
}
TEST
(
WireFormat
,
StructRoundTrip_MultipleSegmentsWithMultipleAllocations
)
{
BuilderArena
arena
(
newFixedWidthBuilderContext
(
8
));
MallocMessageBuilder
message
(
8
,
AllocationStrategy
::
FIXED_SIZE
);
BuilderArena
arena
(
&
message
);
SegmentBuilder
*
segment
=
arena
.
getSegmentWithAvailable
(
1
*
WORDS
);
word
*
rootLocation
=
segment
->
allocate
(
1
*
WORDS
);
...
...
c++/src/capnproto/wire-format.c++
View file @
9c3cb05f
...
...
@@ -612,7 +612,7 @@ struct WireHelpers {
static
CAPNPROTO_ALWAYS_INLINE
(
StructReader
readStructReference
(
SegmentReader
*
segment
,
const
WireReference
*
ref
,
const
word
*
defaultValue
,
int
recursion
Limit
))
{
int
nesting
Limit
))
{
const
word
*
ptr
;
if
(
ref
==
nullptr
||
ref
->
isNull
())
{
...
...
@@ -621,9 +621,9 @@ struct WireHelpers {
ref
=
reinterpret_cast
<
const
WireReference
*>
(
defaultValue
);
ptr
=
ref
->
target
();
}
else
if
(
segment
!=
nullptr
)
{
if
(
CAPNPROTO_EXPECT_FALSE
(
recursion
Limit
==
0
))
{
if
(
CAPNPROTO_EXPECT_FALSE
(
nesting
Limit
==
0
))
{
segment
->
getArena
()
->
reportInvalidData
(
"Message is too deeply-nested or contains cycles."
);
"Message is too deeply-nested or contains cycles.
See capnproto::ReadOptions.
"
);
goto
useDefault
;
}
...
...
@@ -655,25 +655,25 @@ struct WireHelpers {
ref
->
structRef
.
fieldCount
.
get
(),
ref
->
structRef
.
dataSize
.
get
(),
ref
->
structRef
.
refCount
.
get
(),
0
*
BITS
,
recursion
Limit
-
1
);
0
*
BITS
,
nesting
Limit
-
1
);
}
static
CAPNPROTO_ALWAYS_INLINE
(
ListReader
readListReference
(
SegmentReader
*
segment
,
const
WireReference
*
ref
,
const
word
*
defaultValue
,
FieldSize
expectedElementSize
,
int
recursion
Limit
))
{
FieldSize
expectedElementSize
,
int
nesting
Limit
))
{
const
word
*
ptr
;
if
(
ref
==
nullptr
||
ref
->
isNull
())
{
useDefault
:
if
(
defaultValue
==
nullptr
)
{
return
ListReader
(
nullptr
,
nullptr
,
0
*
ELEMENTS
,
0
*
BITS
/
ELEMENTS
,
recursion
Limit
-
1
);
return
ListReader
(
nullptr
,
nullptr
,
0
*
ELEMENTS
,
0
*
BITS
/
ELEMENTS
,
nesting
Limit
-
1
);
}
segment
=
nullptr
;
ref
=
reinterpret_cast
<
const
WireReference
*>
(
defaultValue
);
ptr
=
ref
->
target
();
}
else
if
(
segment
!=
nullptr
)
{
if
(
CAPNPROTO_EXPECT_FALSE
(
recursion
Limit
==
0
))
{
if
(
CAPNPROTO_EXPECT_FALSE
(
nesting
Limit
==
0
))
{
segment
->
getArena
()
->
reportInvalidData
(
"Message is too deeply-nested or contains cycles."
);
"Message is too deeply-nested or contains cycles.
See capnproto::ReadOptions.
"
);
goto
useDefault
;
}
...
...
@@ -780,7 +780,7 @@ struct WireHelpers {
tag
->
structRef
.
fieldCount
.
get
(),
tag
->
structRef
.
dataSize
.
get
(),
tag
->
structRef
.
refCount
.
get
(),
recursion
Limit
-
1
);
nesting
Limit
-
1
);
}
else
{
// The elements of the list are NOT structs.
...
...
@@ -796,7 +796,7 @@ struct WireHelpers {
}
if
(
ref
->
listRef
.
elementSize
()
==
expectedElementSize
)
{
return
ListReader
(
segment
,
ptr
,
ref
->
listRef
.
elementCount
(),
step
,
recursion
Limit
-
1
);
return
ListReader
(
segment
,
ptr
,
ref
->
listRef
.
elementCount
(),
step
,
nesting
Limit
-
1
);
}
else
if
(
expectedElementSize
==
FieldSize
::
INLINE_COMPOSITE
)
{
// We were expecting a struct list, but we received a list of some other type. Perhaps a
// non-struct list was recently upgraded to a struct list, but the sender is using the
...
...
@@ -832,7 +832,7 @@ struct WireHelpers {
}
return
ListReader
(
segment
,
ptr
,
ref
->
listRef
.
elementCount
(),
step
,
FieldNumber
(
1
),
dataSize
,
referenceCount
,
recursion
Limit
-
1
);
dataSize
,
referenceCount
,
nesting
Limit
-
1
);
}
else
{
CAPNPROTO_ASSERT
(
segment
!=
nullptr
,
"Trusted message had incompatible list element type."
);
segment
->
getArena
()
->
reportInvalidData
(
"A list had incompatible element type."
);
...
...
@@ -1028,27 +1028,27 @@ StructReader StructReader::readRootTrusted(const word* location, const word* def
}
StructReader
StructReader
::
readRoot
(
const
word
*
location
,
const
word
*
defaultValue
,
SegmentReader
*
segment
,
int
recursion
Limit
)
{
SegmentReader
*
segment
,
int
nesting
Limit
)
{
if
(
!
segment
->
containsInterval
(
location
,
location
+
REFERENCE_SIZE_IN_WORDS
))
{
segment
->
getArena
()
->
reportInvalidData
(
"Root location out-of-bounds."
);
location
=
nullptr
;
}
return
WireHelpers
::
readStructReference
(
segment
,
reinterpret_cast
<
const
WireReference
*>
(
location
),
defaultValue
,
recursion
Limit
);
defaultValue
,
nesting
Limit
);
}
StructReader
StructReader
::
getStructField
(
WireReferenceCount
refIndex
,
const
word
*
defaultValue
)
const
{
const
WireReference
*
ref
=
refIndex
>=
referenceCount
?
nullptr
:
references
+
refIndex
;
return
WireHelpers
::
readStructReference
(
segment
,
ref
,
defaultValue
,
recursion
Limit
);
return
WireHelpers
::
readStructReference
(
segment
,
ref
,
defaultValue
,
nesting
Limit
);
}
ListReader
StructReader
::
getListField
(
WireReferenceCount
refIndex
,
FieldSize
expectedElementSize
,
const
word
*
defaultValue
)
const
{
const
WireReference
*
ref
=
refIndex
>=
referenceCount
?
nullptr
:
references
+
refIndex
;
return
WireHelpers
::
readListReference
(
segment
,
ref
,
defaultValue
,
expectedElementSize
,
recursion
Limit
);
segment
,
ref
,
defaultValue
,
expectedElementSize
,
nesting
Limit
);
}
Text
::
Reader
StructReader
::
getTextField
(
...
...
@@ -1131,10 +1131,10 @@ ListReader ListBuilder::asReader(FieldNumber fieldCount, WordCount dataSize,
}
StructReader
ListReader
::
getStructElement
(
ElementCount
index
,
const
word
*
defaultValue
)
const
{
if
(
CAPNPROTO_EXPECT_FALSE
((
segment
!=
nullptr
)
&
(
recursion
Limit
==
0
)))
{
if
(
CAPNPROTO_EXPECT_FALSE
((
segment
!=
nullptr
)
&
(
nesting
Limit
==
0
)))
{
segment
->
getArena
()
->
reportInvalidData
(
"Message is too deeply-nested or contains cycles."
);
return
WireHelpers
::
readStructReference
(
nullptr
,
nullptr
,
defaultValue
,
recursion
Limit
);
"Message is too deeply-nested or contains cycles.
See capnproto::ReadOptions.
"
);
return
WireHelpers
::
readStructReference
(
nullptr
,
nullptr
,
defaultValue
,
nesting
Limit
);
}
else
{
BitCount64
indexBit
=
ElementCount64
(
index
)
*
stepBits
;
const
byte
*
structPtr
=
reinterpret_cast
<
const
byte
*>
(
ptr
)
+
indexBit
/
BITS_PER_BYTE
;
...
...
@@ -1142,7 +1142,7 @@ StructReader ListReader::getStructElement(ElementCount index, const word* defaul
segment
,
structPtr
,
reinterpret_cast
<
const
WireReference
*>
(
structPtr
+
structDataSize
*
BYTES_PER_WORD
),
structFieldCount
,
structDataSize
,
structReferenceCount
,
indexBit
%
BITS_PER_BYTE
,
recursion
Limit
-
1
);
nesting
Limit
-
1
);
}
}
...
...
@@ -1150,7 +1150,7 @@ ListReader ListReader::getListElement(
WireReferenceCount
index
,
FieldSize
expectedElementSize
)
const
{
return
WireHelpers
::
readListReference
(
segment
,
reinterpret_cast
<
const
WireReference
*>
(
ptr
)
+
index
,
nullptr
,
expectedElementSize
,
recursion
Limit
);
nullptr
,
expectedElementSize
,
nesting
Limit
);
}
Text
::
Reader
ListReader
::
getTextElement
(
WireReferenceCount
index
)
const
{
...
...
c++/src/capnproto/wire-format.h
View file @
9c3cb05f
...
...
@@ -159,11 +159,11 @@ class StructReader {
public
:
inline
StructReader
()
:
segment
(
nullptr
),
data
(
nullptr
),
references
(
nullptr
),
fieldCount
(
0
),
dataSize
(
0
),
referenceCount
(
0
),
bit0Offset
(
0
*
BITS
),
recursion
Limit
(
0
)
{}
referenceCount
(
0
),
bit0Offset
(
0
*
BITS
),
nesting
Limit
(
0
)
{}
static
StructReader
readRootTrusted
(
const
word
*
location
,
const
word
*
defaultValue
);
static
StructReader
readRoot
(
const
word
*
location
,
const
word
*
defaultValue
,
SegmentReader
*
segment
,
int
recursion
Limit
);
SegmentReader
*
segment
,
int
nesting
Limit
);
template
<
typename
T
>
CAPNPROTO_ALWAYS_INLINE
(
...
...
@@ -213,16 +213,16 @@ private:
// instead of the usual zero. This is needed to allow a boolean list to be upgraded to a list
// of structs.
int
recursion
Limit
;
int
nesting
Limit
;
// Limits the depth of message structures to guard against stack-overflow-based DoS attacks.
// Once this reaches zero, further pointers will be pruned.
inline
StructReader
(
SegmentReader
*
segment
,
const
void
*
data
,
const
WireReference
*
references
,
FieldNumber
fieldCount
,
WordCount
dataSize
,
WireReferenceCount
referenceCount
,
BitCount
bit0Offset
,
int
recursion
Limit
)
BitCount
bit0Offset
,
int
nesting
Limit
)
:
segment
(
segment
),
data
(
data
),
references
(
references
),
fieldCount
(
fieldCount
),
dataSize
(
dataSize
),
referenceCount
(
referenceCount
),
bit0Offset
(
bit0Offset
),
recursionLimit
(
recursion
Limit
)
{}
nestingLimit
(
nesting
Limit
)
{}
friend
class
ListReader
;
friend
class
StructBuilder
;
...
...
@@ -306,7 +306,7 @@ public:
inline
ListReader
()
:
segment
(
nullptr
),
ptr
(
nullptr
),
elementCount
(
0
),
stepBits
(
0
*
BITS
/
ELEMENTS
),
structFieldCount
(
0
),
structDataSize
(
0
),
structReferenceCount
(
0
),
recursion
Limit
(
0
)
{}
structReferenceCount
(
0
),
nesting
Limit
(
0
)
{}
inline
ElementCount
size
();
// The number of elements in the list.
...
...
@@ -348,22 +348,22 @@ private:
// only used to check for field presence; the data size is also used to compute the reference
// pointer.
int
recursion
Limit
;
int
nesting
Limit
;
// Limits the depth of message structures to guard against stack-overflow-based DoS attacks.
// Once this reaches zero, further pointers will be pruned.
inline
ListReader
(
SegmentReader
*
segment
,
const
void
*
ptr
,
ElementCount
elementCount
,
decltype
(
BITS
/
ELEMENTS
)
stepBits
,
int
recursion
Limit
)
decltype
(
BITS
/
ELEMENTS
)
stepBits
,
int
nesting
Limit
)
:
segment
(
segment
),
ptr
(
ptr
),
elementCount
(
elementCount
),
stepBits
(
stepBits
),
structFieldCount
(
0
),
structDataSize
(
0
),
structReferenceCount
(
0
),
recursionLimit
(
recursion
Limit
)
{}
nestingLimit
(
nesting
Limit
)
{}
inline
ListReader
(
SegmentReader
*
segment
,
const
void
*
ptr
,
ElementCount
elementCount
,
decltype
(
BITS
/
ELEMENTS
)
stepBits
,
FieldNumber
structFieldCount
,
WordCount
structDataSize
,
WireReferenceCount
structReferenceCount
,
int
recursion
Limit
)
WireReferenceCount
structReferenceCount
,
int
nesting
Limit
)
:
segment
(
segment
),
ptr
(
ptr
),
elementCount
(
elementCount
),
stepBits
(
stepBits
),
structFieldCount
(
structFieldCount
),
structDataSize
(
structDataSize
),
structReferenceCount
(
structReferenceCount
),
recursionLimit
(
recursion
Limit
)
{}
structReferenceCount
(
structReferenceCount
),
nestingLimit
(
nesting
Limit
)
{}
friend
class
StructReader
;
friend
class
ListBuilder
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment