View Issue Details
ID | Project | Category | View Status | Date Submitted | Last Update |
---|---|---|---|---|---|
0004591 | The Dark Mod | Coding | public | 29.07.2017 04:45 | 09.03.2020 04:16 |
Reporter | stgatilov | Assigned To | stgatilov | ||
Priority | normal | Severity | minor | Reproducibility | always |
Status | resolved | Resolution | fixed | ||
Product Version | TDM 2.06 | ||||
Target Version | TDM 2.06 | Fixed in Version | TDM 2.06 | ||
Summary | 0004591: Debug build crashes on exit | ||||
Description | As said in the title. | ||||
Steps To Reproduce | Having e.g. svn revision 7046, build any debug configuration, start TDM from MSVC, then quit game immediately. You'll get a crash. | ||||
Tags | No tags attached. | ||||
Fixed in revisions 7047-7050. Among all the problems encountered, the hardest one was MFC-related (see rev 7050). It took me several days to understand what the hell was going on, and what may help. Even reading the weird description of MFC internals did not help immediately: http://www.programering.com/a/MjM0YDNwATI.html I must admit that MFC is a very hacky thing: it strongly relies on global variables and static initialization/destruction. As you guess, this does not play nicely with DLL-s. During execution, MFC requires process state, thread state, module state, and thread-module state to be set properly. And as you guessed, these states must be properly switched when you change thread/module; and module switching must be done manually sometimes. All of this can be called "state hell" ! The crash on exit in debug configurations was caused by double destruction of thread-module state. Debug heap fills freed memory with 0xFEEE, so thread-module state was incorrect during second destruction, which caused access violation. This problem did not happen before Duzenko's recent refactoring, because MFC was statically linked into TDM. Now it is linked dynamically. Reverting to static linkage is a bad option, because it forces to link CRT statically too =( In MFC, each application must have exactly one CWinApp object, defined as a global variable. And this is how things work with static MFC linkage: there is only "CRadiantApp theApp". However, when MFC is linked dynamically, the second hidden CWinApp appears: it is defined as global variable mfc120d.dll!_afxOleWinApp (defined in MFC sources). When ExitProcess is called, all global variables are destroyed, including both CWinApp-s. The _afxOleWinApp is destroyed first, and it destroys its own module state (also a global variable mfc120d.dll!_afxBaseModuleState). Then CRadiantApp is destroyed, but due to some reason it tries to destroy the same module state, so double destruction happens. In order to work properly, CRadiantApp must point to its own module state, since TheDarkMod.exe and mfc120d.dll are different modules. I don't know exactly why this happens. Normally, MFC application starts with a built-in WinMain function, which initializes all the states for the CWinApp. In case of Doom 3, custom WinMain function is defined, so built-in initialization does not happen. Trying to copy the steps from appmodul.cpp caused some weird linking errors... So I tried to simply create module state myself (radiantState) and point "CRadiantApp theApp" to it directly. Strangely, one change did not suffice, so I had to do two: 1. Assign theApp.m_pModuleState = &radiantState manually. Very hacky. 2. Call AfxSetModuleState after _afxOleWinApp is destroyed but before theApp is destroyed (this happens during globals destruction, so it has to be done in CRadiantApp's destructor). Now it works. But frankly speaking, I wish MFC would be eradicated from TDM one day. |
|
Date Modified | Username | Field | Change |
---|---|---|---|
29.07.2017 04:45 | stgatilov | New Issue | |
29.07.2017 04:45 | stgatilov | Status | new => assigned |
29.07.2017 04:45 | stgatilov | Assigned To | => stgatilov |
29.07.2017 05:04 | stgatilov | Note Added: 0009036 | |
29.07.2017 05:06 | stgatilov | Note Edited: 0009036 | |
29.07.2017 05:06 | stgatilov | Note Edited: 0009036 | |
29.07.2017 05:06 | stgatilov | Status | assigned => resolved |
29.07.2017 05:06 | stgatilov | Resolution | open => fixed |
09.03.2020 04:16 | stgatilov | Fixed in Version | => TDM 2.06 |