Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <h2>The Answer</h2> <p>The compiler was, in fact, calculating an incorrect address for some of the class members. The culprit turned out to be a <strong><code>#pragma pack 1</code></strong> directive hidden in an obscure header file that was <code>#included</code> in some of the source files.</p> <h2>How I found it</h2> <p>50% persistence, 50% luck, and 10% math skills. :-)</p> <p>I came across a very simple class with few methods and members, most of which were defined in the header file, including:</p> <pre><code>typedef int BOOL; // Legacy, makes my skin crawl; don't ask. BOOL isConnected() { return m_bConnected; }; BOOL m_bConnected; </code></pre> <p>...and the function returned <code>false</code> when I <em>knew</em>&nbsp; <code>m_bConnected</code> was <code>true</code>:</p> <ul> <li>The watch window showed the correct value. Programmatic changes to <code>m_bConnected</code> were reflected in the window.</li> <li>A watch on <code>&amp;m_bConnected</code> showed that it began 8 bytes into the class.</li> <li>The raw memory window showed the correct value. Programmatic changes to <code>m_bConnected</code> were reflected there as well.</li> <li>The 4 bytes before <code>m_bConnected</code> were all <code>0</code>, which I interpreted to be padding.</li> <li>Stepping the debugger through the code clearly showed a return value of <code>false</code>!</li> </ul> <p>So I checked the disassembly window and found this (comments are mine):</p> <pre><code>mov eax,dword ptr [this] ; address of the class instance mov eax,dword ptr [eax+4] ; offset to m_bConnected </code></pre> <p>In other words, the compiler calculated the offset as 4, when it should have been 8.</p> <h2>Aha!</h2> <p>Interestingly, when I removed the definition of <code>isConnected()</code> from the header and placed it into my source file, <em>the address was calculated correctly</em>! That convinced me that it was, indeed, a packing problem, and a search of the code base for <code>#pragma pack</code> quickly identified the culprit, an ancient header file that (legitimately) required alignment on 1-byte boundaries but never reset the packing to the default.</p> <h2>The Fix</h2> <p>The solution was as easy as enclosing the offending header like this:</p> <pre><code>#pragma pack(push) // original code here #pragma pack(pop) </code></pre> <p>Thanks for your interest. And Sara, if you're reading, I'm about to <a href="https://stackoverflow.com/questions/183469/how-do-you-reward-yourself-when-youve-overcome-a-monster-task">dance on my desk</a>!</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload