Note that there are some explanatory texts on larger screens.

plurals
  1. POC++, an "impossible" behavior
    text
    copied!<p>If you've been programming for a while then you probably noticed something completely impossible occurs every now and then for which you are convinced there is no possible explanation ("IT'S A COMPILER BUG!!"). After you find out what it was caused by though you are like "oooohhh".</p> <p>Well, it just happened to me :(</p> <p>Here AuthDb is <strong>NOT</strong> NULL but a valid pointer:</p> <pre><code>SingleResult sr(AuthDb, format("SELECT Id, Access, Flags, SessionKey, RealmSplitPreference FROM accounts WHERE Name = '%s'") % Escaped(account_name)); </code></pre> <p>Here it mysteriously becomes NULL:</p> <pre><code>struct SingleResult : public BaseResult { SingleResult(Database *db, const boost::format&amp; query) { _ExecuteQuery(db, query.str()); } } </code></pre> <p>Notice that it's the immediate next call. It can be explained much better with two screenshots: <a href="http://img187.imageshack.us/img187/5757/ss1zm.png" rel="nofollow noreferrer">http://img187.imageshack.us/img187/5757/ss1zm.png</a><br> <a href="http://img513.imageshack.us/img513/5610/ss2b.png" rel="nofollow noreferrer">http://img513.imageshack.us/img513/5610/ss2b.png</a> </p> <p>EDIT: AuthDb is a global variable. It itself keeps pointing to the right thing; but the copy of the ptr Database *db points at NULL.</p> <hr> <p>ASM code (unfortunately I don't even know how to read it :/)</p> <p><strong>Of the first screenshot</strong></p> <pre><code>01214E06 mov eax,dword ptr [ebp-328h] 01214E0C push eax 01214E0D push offset string "SELECT Id, Access, Flags, Sessio"... (13C6278h) 01214E12 lea ecx,[ebp-150h] 01214E18 call boost::basic_format&lt;char,std::char_traits&lt;char&gt;,std::allocator&lt;char&gt; &gt;::basic_format&lt;char,std::char_traits&lt;char&gt;,std::allocator&lt;char&gt; &gt; (11A3260h) 01214E1D mov dword ptr [ebp-32Ch],eax 01214E23 mov ecx,dword ptr [ebp-32Ch] 01214E29 mov dword ptr [ebp-330h],ecx 01214E2F mov byte ptr [ebp-4],2 01214E33 mov ecx,dword ptr [ebp-330h] 01214E39 call boost::basic_format&lt;char,std::char_traits&lt;char&gt;,std::allocator&lt;char&gt; &gt;::operator%&lt;Snow::Escaped&gt; (11A3E18h) 01214E3E push eax 01214E3F mov edx,dword ptr [__tls_index (144EC40h)] 01214E45 mov eax,dword ptr fs:[0000002Ch] 01214E4B mov ecx,dword ptr [eax+edx*4] 01214E4E mov edx,dword ptr [ecx+12A3Ch] 01214E54 push edx 01214E55 lea ecx,[sr] 01214E58 call Snow::SingleResult::SingleResult (11A27D4h) 01214E5D mov byte ptr [ebp-4],4 // VS GREEN ARROW IS HERE 01214E61 lea ecx,[ebp-150h] 01214E67 call boost::basic_format&lt;char,std::char_traits&lt;char&gt;,std::allocator&lt;char&gt; &gt;::~basic_format&lt;char,std::char_traits&lt;char&gt;,std::allocator&lt;char&gt; &gt; (11A1DBBh) 01214E6C mov byte ptr [ebp-4],5 01214E70 lea ecx,[ebp-170h] 01214E76 call Snow::Escaped::~Escaped (11A42D2h) const bool account_found = !sr.Error(); 01214E7B lea ecx,[sr] 01214E7E call Snow::BaseResult::Error (11A2964h) 01214E83 movzx eax,al 01214E86 test eax,eax 01214E88 sete cl 01214E8B mov byte ptr [account_found],cl if (!account_found) { 01214E8E movzx edx,byte ptr [account_found] 01214E92 test edx,edx 01214E94 jne AuthSession+1C0h (1214F10h) client.Kill(format("%s: Attempted to login with non existant account `%s'") % client % account_name, true); </code></pre> <p><strong>Second screenshot</strong></p> <pre><code>011A8E7D mov dword ptr [ebp-10h],ecx 011A8E80 mov ecx,dword ptr [this] 011A8E83 call Snow::BaseResult::BaseResult (11A31D9h) 011A8E88 mov dword ptr [ebp-4],0 011A8E8F lea eax,[ebp-30h] 011A8E92 push eax 011A8E93 mov ecx,dword ptr [query] 011A8E96 call boost::basic_format&lt;char,std::char_traits&lt;char&gt;,std::allocator&lt;char&gt; &gt;::str (11A1E01h) 011A8E9B mov dword ptr [ebp-34h],eax 011A8E9E mov ecx,dword ptr [ebp-34h] 011A8EA1 mov dword ptr [ebp-38h],ecx 011A8EA4 mov byte ptr [ebp-4],1 011A8EA8 mov edx,dword ptr [ebp-38h] 011A8EAB push edx 011A8EAC mov eax,dword ptr [db] 011A8EAF push eax 011A8EB0 mov ecx,dword ptr [this] 011A8EB3 call Snow::SingleResult::_ExecuteQuery (124F380h) 011A8EB8 mov byte ptr [ebp-4],0 // VS GREEN ARROW HERE 011A8EBC lea ecx,[ebp-30h] 011A8EBF call std::basic_string&lt;char,std::char_traits&lt;char&gt;,std::allocator&lt;char&gt; &gt;::~basic_string&lt;char,std::char_traits&lt;char&gt;,std::allocator&lt;char&gt; &gt; (11A2C02h) 011A8EC4 mov dword ptr [ebp-4],0FFFFFFFFh 011A8ECB mov eax,dword ptr [this] 011A8ECE mov ecx,dword ptr [ebp-0Ch] 011A8ED1 mov dword ptr fs:[0],ecx 011A8ED8 pop edi 011A8ED9 add esp,38h 011A8EDC cmp ebp,esp 011A8EDE call _RTC_CheckEsp (12B4450h) 011A8EE3 mov esp,ebp 011A8EE5 pop ebp 011A8EE6 ret 8 </code></pre> <hr> <p><strong>UPDATE</strong> Following the suggestion of peterchen, I added <code>ASSERT(AuthDb);</code> here:</p> <pre><code>ASSERT(AuthDb); SingleResult sr(AuthDb, format("SELECT Id, Access, Flags, SessionKey, RealmSplitPreference FROM accounts WHERE Name = '%s'") % Escaped(account_name)); </code></pre> <p>And it failed O.o And yet the debugger keeps insisting that it's not NULL.. It's not shadowed by a local</p> <p><strong>UPDATE2*</strong> <code>cout &lt;&lt; AuthDb;</code> is 0 in there even if the debugger says it's not</p> <hr> <p><strong>FOUND THE PROBLEM</strong></p> <p><code>Database *AuthDb = NULL, *GameDb = NULL;</code> in a .cpp</p> <p><code>extern thread Database *AuthDb, *GameDb;</code> in a .h</p> <p>The variable was marked thread (TLS - Thread local storage) in the header, but not TLS in the definition...</p> <p>Countless hours wasted on this super stupid mistake, no warnings or hints or anything from the compiler that I feel like killing right now. :( Oh well, like I said for each impossible behavior there is a solution that once known seems obvious :)</p> <p>Thanks to everyone who helped, I was really desperate!</p>
 

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