One option I see which would sidestep this entirely is to default 
initialise the brokenCapFactory to something that performs a read with a 
stronger load. You'd still need to use explicit atomic loads to not trigger 
UB, of course, but you could have something like


class UninitializedBrokenCapFactoryImpl: public _::BrokenCapFactory { 
public: 
kj::Own<ClientHook> newBrokenCap(kj::StringPtr description) override { 
  auto realFactory = atomic_load(brokenCapFactory, acquire);
  KJ_REQUIRE(realFactory != this, "must initialise...");
  return realFactory->newBrokenCap(description);
} 
...
} 

static UninitializedBrokenCapFactoryImpl uninitializedBrokenCapFactory;
static BrokenCapFactory* brokenCapFactory = &uninitializedBrokenCapFactory;


On Tuesday, October 13, 2020 at 12:15:26 PM UTC+2 Erin Shepherd wrote:

> > I think that ThreadSanitizer is having trouble recognizing that the 
> initialization of `brokenCapFactory` is thread-safe, due to the awkward way 
> in which it is initialized. It may end up being initialized by multiple 
> threads, but all threads will initialize it to the same value, hence no 
> atomics are necessary when reading it later.
>
> This doesn't hold unless every thread reading it also once wrote it. If it 
> might be written by T1 and read (but never initialised) by T2, then 
> appropriate write/read barriers need to be in place (e.g. acquire/release).
>
> Erin
>
> On Friday, October 9, 2020 at 6:48:06 PM UTC+2 [email protected] 
> wrote:
>
>> I think that ThreadSanitizer is having trouble recognizing that the 
>> initialization of `brokenCapFactory` is thread-safe, due to the awkward way 
>> in which it is initialized. It may end up being initialized by multiple 
>> threads, but all threads will initialize it to the same value, hence no 
>> atomics are necessary when reading it later.
>>
>> Maybe we should use atomic reads anyway, to make ThreadSanitizer happy. 
>> Doing so should be free, at least on x86.
>>
>> (The reason for the weird initialization is that the factory is 
>> implemented in libcapnp-rpc.so, yet needs to be callable from libcapnp.so 
>> -- but only if RPC is in use.)
>>
>> -Kenton
>>
>> On Fri, Oct 9, 2020 at 8:37 AM Vitali Lovich <[email protected]> wrote:
>>
>>> I'm trying to do a basic in-process connection of the servers & running 
>>> that under TSAN but I feel like this is some nuance of the APIs I'm missing 
>>> or using the API totally incorrectly outright, so I would appreciate some 
>>> feedback if possible. I'm sure the bug must be in my code rather than 
>>> cap'n'proto. I don't have a helpful standalone piece of code to demonstrate 
>>> this issue at the moment (but if it's really critical I can work on 
>>> providing that). I've provided brief snippets of what the threads do (the 
>>> threads themselves are really that simple, it's just the schema & the 
>>> threads using various helper internal libraries that make it harder to post 
>>> a working standalone example).
>>>
>>> Full TSAN (to avoid spamming the list): https://pastebin.com/hSkVDgsU
>>>
>>> For context, the main thread does 
>>> auto ioContext = kj::setupAsyncIo();
>>> auto serverThread = ioContext.provider->newPipeThread(...);
>>> auto serverPtr = <wait for CV state from T1>;
>>> capnp::TwoPartyClient rpcClient(*serverThread.pipe);
>>> auto client = rpcClient.bootstrap().castAs<MyServer>();
>>> auto connectedResponse = 
>>> client.connectRequest().send().wait(ioContext.waitScope); *<-- this is 
>>> the problematic TSAN line *
>>>
>>> T1 (taking AsyncIoProvider&, AsyncIoStream& stream, kj::WaitScope& 
>>> waitScope):
>>> capnp::TwoPartyVatNetwork network(stream, 
>>> capnp::rpc::twoparty::Side::SERVER);
>>> auto myServer = kj::heap<MyServerImpl>();
>>> auto myServerPtr = myServer.get()
>>> auto rpcServer = capnp::makeRpcServer(network, kj::mv( myServer));
>>> <publish myServerPtr to main thread using CV>  
>>> network.onDisconnect().wait(waitScope);* <- problematic TSAN line*
>>>
>>> SUMMARY: ThreadSanitizer: data race 
>>> capnproto/c++/src/capnp/layout.c++:2188:5 in 
>>> capnp::_::WireHelpers::readCapabilityPointer(capnp::_::SegmentReader*, 
>>> capnp::_::CapTableReader*, capnp::_::WirePointer const*, int)
>>>
>>>   Read of size 8 at 0x0000016673e0 by main thread:
>>>     #0 
>>> capnp::_::WireHelpers::readCapabilityPointer(capnp::_::SegmentReader*, 
>>> capnp::_::CapTableReader*, capnp::_::WirePointer const*, int) 
>>> capnproto/c++/src/capnp/layout.c++:2188:5 (ld-2.26.so+0x809e60)
>>>     #1 capnp::_::PointerReader::getCapability() const 
>>> capnproto/c++/src/capnp/layout.c++:2705 (ld-2.26.so+0x809e60)
>>>     #2 
>>> capnp::AnyPointer::Reader::getPipelinedCap(kj::ArrayPtr<capnp::PipelineOp 
>>> const>) const capnproto/c++/src/capnp/any.c++:53:18 (ld-2.26.so
>>> +0x7ff4a7)
>>>     #3 capnp::_::(anonymous 
>>>
>>>   Previous atomic write of size 8 at 0x0000016673e0 by thread T1:
>>>     #0 __tsan_atomic64_store <null> (ld-2.26.so+0x6911ee)
>>>     #1 
>>> capnp::_::setGlobalBrokenCapFactoryForLayoutCpp(capnp::_::BrokenCapFactory&)
>>>  
>>> capnproto/c++/src/capnp/layout.c++:45:3 (ld-2.26.so+0x800d12)
>>>     #2 
>>> capnp::ReaderCapabilityTable::ReaderCapabilityTable(kj::Array<kj::Maybe<kj::Own<capnp::ClientHook>
>>>  
>>> > >) capnproto/c++/src/capnp/capability.c++:951:3 (ld-2.26.so+0x6f32cc)
>>>     #3 capnp::_::(anonymous 
>>> namespace)::RpcConnectionState::RpcCallContext::RpcCallContext(capnp::_::(anonymous
>>>  
>>> namespace)::RpcConnectionState&, unsigned int, 
>>> kj::Own<capnp::IncomingRpcMessage>&&, 
>>> kj::Array<kj::Maybe<kj::Own<capnp::ClientHook> > >, 
>>> capnp::AnyPointer::Reader const&, bool, kj::Own<kj::PromiseFulfiller<void> 
>>> >&&, unsigned long, unsigned short) capnproto/c++/src/capnp/rpc.c++:2144:11 
>>> (ld-2.26.so+0x754bea)
>>>
>>> -- 
>>> 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 [email protected].
>>> To view this discussion on the web visit 
>>> https://groups.google.com/d/msgid/capnproto/19bac31b-6f11-43d1-886e-93d6bc32557an%40googlegroups.com
>>>  
>>> <https://groups.google.com/d/msgid/capnproto/19bac31b-6f11-43d1-886e-93d6bc32557an%40googlegroups.com?utm_medium=email&utm_source=footer>
>>> .
>>>
>>

-- 
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 [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/capnproto/3aac00f9-4c66-4e03-b2e4-332a94aef006n%40googlegroups.com.

Reply via email to