0

I have an app crashing some times because the MS _purecall is being called but the data I see on the crash dump is not what I expected.

I have CSocket derived from CConnection, the latter has a pure virtual function named DoRead and the app crashes when an instance of CSocket calls this function in a worker thread.

Following the register values and how Microsoft implements C++ virtual tables and calls, I see RCX has the correct this value, the first quad-word points to the v-table and the v-table is correct so the call to _purecall should not happen.

But after seeing how the constructor is implemented, I see CConnection constructor sets up the pointer to the v-table which includes the call to _purecall and then, CSocket's constructor overwrites this value with the correct/derived v-table.

This is what I suspect is happening:

  1. A thread calls to new CSocket.
  2. Before CSocket constructor is called and the v-table modified, the worker thread reads some memory near the pointer (probably because it is processing an operation of other CSocket instance) and that memory page is "cached" by the processor.
  3. The thread creating CSocket continues its execution finishing CSocket construction.
  4. When the worker thread accesses the v-table, reads the value from the "cached" page instead of the real memory containing the correct v-table.

At first glance there is no memory barrier inserted by the compiler to avoid this.

Am I correct in my assumption? Is it possible to happen or the compiler/processor has a mechanism to avoid this?

Mauro H. Leggieri
  • 1,084
  • 11
  • 25
  • are you calling a member function, before the object is fully constructed? Can you provide a [mcve]? – 463035818_is_not_an_ai Sep 28 '19 at 11:10
  • No, the constructors just initializes some internal variables. Also the object is not being destructed. I have no example but a dump. Basically the main thread creates the `CSocket` object, calls `connect` and then calls to `PostQueuedCompletionStatus` with a custom code so the IOCP worker thread makes the initial call to `WSARecv` implemented in the derived `DoRead` method. – Mauro H. Leggieri Sep 28 '19 at 11:18
  • Generally speaking, if one thread is modifying an object or the memory representing (including constructing the object) then it is necessary to ensure another thread doesn't access or modify that same object. No, the compiler does not ensure that happens - you need to take care of it. For example, don't start the worker until after the object is constructed. Or avoid passing information to the worker thread that it will use to access the object, unless the object is fully constructed. – Peter Sep 28 '19 at 12:36
  • Heap corruption can cause some strange side effects. Does a debug build behave the same? See https://support.microsoft.com/en-us/help/154753/description-of-the-default-c-and-c-libraries-that-a-program-will-link – Andrew Henle Sep 28 '19 at 13:53
  • 1
    @AndrewHenle couldn't repro locally in neither Debug or Release builds. – Mauro H. Leggieri Sep 28 '19 at 17:45
  • @Peter My current best shot is to add some memory barriers. – Mauro H. Leggieri Sep 28 '19 at 17:45

0 Answers0