Discussion:
[capnproto] Shared memory builder
b***@gmail.com
2018-02-12 20:50:35 UTC
Permalink
Hi,

We are trying to use capnp (0.5.3) for inter-process communication. For
that we are going to use a shared memory organized as a ring buffer
(between C++ and Rust apps).
The allocateSegment() method (in C++) is allocating a chunk of unused
memory and returns it as kj::array.
Unfortunately we noticed that if the underlining memory chunk (which is
reused, as we have a ring buffer) is not nullified, that is memset(0) for
the whole size, capn'p would crash.
Further analysis revealed that the library tries to read from the newly
allocated chunk at the function WireHelpers::zeroObject by putting a read
watch on the newly allocated memory chunk:

#0 0x000000000064af43 in
capnp::_::WireHelpers::zeroObject(capnp::_::SegmentBuilder*,
capnp::_::WirePointer*) ()
#1 0x00000000006468e8 in
capnp::_::PointerBuilder::initStruct(capnp::_::StructSize) ()
#2 0x0000000000425d9c in capnp::_::PointerHelpers<Test,
(capnp::Kind)3>::init (builder=...) at
/sandbox/common/include/capnp/pointer-helpers.h:52
#3 0x00000000004259e6 in capnp::AnyPointer::Builder::initAs<Test>
(this=0x7ffff6b0dd10) at /sandbox/common/include/capnp/any.h:690
#4 0x000000000042557e in capnp::MessageBuilder::initRoot<Test>
(this=0x7ffff6b0ddd0) at /sandbox/common/include/capnp/message.h:432
#5 0x00000000004241c6 in MsgWriterRunner::run (this=0x96bbc8) at
/sandbox/mylib/unittest/capnp_message_test.cpp:246
...

The capnp is simple
struct Test {
name @0 :Text;
number @1 : UInt64;
}

Looking at MallocBuilder we notice the calloc() is actually used, that is
buffers are always zeroed.


Is that an implicit requirement that the memory returned by the overriding
allocateSegment is zeroed?
If so, it would have significant implications on the performance, which is
the reson we chose Capn'p in the first place.

Any assistance appreciated.

A side question: what is the right way to build a debug version of the
libraries on linux? Found no documentation on that; tried .configure with
-DDEBUG but the results are not satisfying - some functions remain inlined.

Thanks,
Roman.
--
You received this message because you are subscribed to the Google Groups "Cap'n Proto" group.
To unsubscribe from this group and stop receiving emails from it, send an email to capnproto+***@googlegroups.com.
Visit this group at https://groups.google.com/group/capnproto.
'Kenton Varda' via Cap'n Proto
2018-02-12 22:35:01 UTC
Permalink
Hi Roman,

Indeed, allocateSegment() is expected to return memory that has been
pre-zero'd. This appears to be missing from its doc comment. :( I've filed
an issue for that: https://github.com/capnproto/capnproto/issues/636

The reason for this is actually performance: Whenever you initialize an
object, it has to start out containing zeros, so if the underlying memory
is known to be zero'd already, then the implementation doesn't have to zero
each object on allocation. Many memory allocators are already guaranteed to
return zero'd memory, so pushing this responsibility to the memory
allocator possibly eliminates an extra zeroing pass.

The reason individual objects have to start out containing zeros is:
1) Part of Cap'n Proto's forwards/backwards-compatibility story is that if
you don't explicitly set a field, it gets set to its default value. Since
field values are XOR'd against the default on the wire, the wire encoding
of the default value is always zero. So zeroing is the same thing as
default-initializing, which is a necessary step.
2) When communicating with a party you don't trust, exposing uninitialized
memory in the message would be a major security flaw. By pre-zeroing
messages we can be more easily assured that that is not a problem.

Regarding debug mode, defining DEBUG should be sufficient. Invoke configure
like:

./configure CXXFLAGS="-g -DDEBUG"

BTW, 0.5.3 is many years old. I strongly recommend updating to 0.6.1.

-Kenton
Post by b***@gmail.com
Hi,
We are trying to use capnp (0.5.3) for inter-process communication. For
that we are going to use a shared memory organized as a ring buffer
(between C++ and Rust apps).
The allocateSegment() method (in C++) is allocating a chunk of unused
memory and returns it as kj::array.
Unfortunately we noticed that if the underlining memory chunk (which is
reused, as we have a ring buffer) is not nullified, that is memset(0) for
the whole size, capn'p would crash.
Further analysis revealed that the library tries to read from the newly
allocated chunk at the function WireHelpers::zeroObject by putting a read
#0 0x000000000064af43 in capnp::_::WireHelpers::zeroObject(capnp::_::SegmentBuilder*,
capnp::_::WirePointer*) ()
#1 0x00000000006468e8 in capnp::_::PointerBuilder::initStruct(capnp::_::StructSize)
()
#2 0x0000000000425d9c in capnp::_::PointerHelpers<Test,
(capnp::Kind)3>::init (builder=...) at /sandbox/common/include/capnp/
pointer-helpers.h:52
#3 0x00000000004259e6 in capnp::AnyPointer::Builder::initAs<Test>
(this=0x7ffff6b0dd10) at /sandbox/common/include/capnp/any.h:690
#4 0x000000000042557e in capnp::MessageBuilder::initRoot<Test>
(this=0x7ffff6b0ddd0) at /sandbox/common/include/capnp/message.h:432
#5 0x00000000004241c6 in MsgWriterRunner::run (this=0x96bbc8) at
/sandbox/mylib/unittest/capnp_message_test.cpp:246
...
The capnp is simple
struct Test {
}
Looking at MallocBuilder we notice the calloc() is actually used, that is
buffers are always zeroed.
Is that an implicit requirement that the memory returned by the overriding
allocateSegment is zeroed?
If so, it would have significant implications on the performance, which is
the reson we chose Capn'p in the first place.
Any assistance appreciated.
A side question: what is the right way to build a debug version of the
libraries on linux? Found no documentation on that; tried .configure with
-DDEBUG but the results are not satisfying - some functions remain inlined.
Thanks,
Roman.
--
You received this message because you are subscribed to the Google Groups
"Cap'n Proto" group.
To unsubscribe from this group and stop receiving emails from it, send an
Visit this group at https://groups.google.com/group/capnproto.
--
You received this message because you are subscribed to the Google Groups "Cap'n Proto" group.
To unsubscribe from this group and stop receiving emails from it, send an email to capnproto+***@googlegroups.com.
Visit this group at https://groups.google.com/group/capnproto.
Loading...