MODE C ++ / CLI Crashing: Corruption du tas dans ATexit (enregistrement de destructeur statique)

StackOverflow https://stackoverflow.com/questions/4928763

Question

Je travaille sur le déploiement d'un programme et la base de code est un mélange de C ++ / CLI et C #. Le C ++ / CLI est disponible dans toutes les saveurs: native, mixte (/clr), et en toute sécurité (/clr:safe). Dans mon environnement de développement, je crée une DLL de tout le code C ++ / CLI et référence à celle du code C # (EXE). Cette méthode fonctionne parfaitement.

Pour mes sorties, je souhaite libérer un seul exécutable (en indiquant simplement que "Pourquoi ne pas simplement avoir une DLL et une exe séparées?" N'est pas acceptable).

Jusqu'à présent, j'ai réussi à compiler l'EXE avec toutes les différentes sources. Cependant, lorsque je l'exécute, je reçois la boîte de dialogue "XXXX a cessé de fonctionner" avec des options pour vérifier en ligne, fermer et déboguer. Les détails du problème sont les suivants:

Problem Event Name:       APPCRASH
Fault Module Name:        StackHash_8d25
Fault Module Version:     6.1.7600.16559
Fault Module Timestamp:   4ba9b29c
Exception Code:           c0000374
Exception Offset:         000cdc9b
OS Version:               6.1.7600.2.0.0.256.48
Locale ID:                1033
Additional Information 1: 8d25
Additional Information 2: 8d25552d834e8c143c43cf1d7f83abb8
Additional Information 3: 7450
Additional Information 4: 74509ce510cd821216ce477edd86119c

Si je débogue et l'envoie à Visual Studio, il rapporte:

Unhandled exception at 0x77d2dc9b in XXX.exe: A heap has been corrupted

Choisir la rupture des résultats en s'arrêtant sur ntdll.dll! 77d2dc9b () sans aucune information supplémentaire. Si je dis à Visual Studio de continuer, le programme démarre bien et semble fonctionner sans incident, probablement car un débogueur est maintenant attaché.

Que faites-vous de cela? Comment éviter cette corruption de tas? Le programme semble bien fonctionner, sauf pour cela.

Mon script de compilation abrégé est le suivant (j'ai omis mon erreur de vérification pour la concision):

@set TARGET=x86
@set TARGETX=x86
@set OUT=%TARGETX%
@call "%VS90COMNTOOLS%\..\..\VC\vcvarsall.bat" %TARGET%

@set WIMGAPI=C:\Program Files\Windows AIK\SDKs\WIMGAPI\%TARGET%

set CL=/Zi /nologo /W4 /O2 /GS /EHa /MD /MP /D NDEBUG /D _UNICODE /D UNICODE /D INTEGRATED /Fd%OUT%\ /Fo%OUT%\
set INCLUDE=%WIMGAPI%;%INCLUDE%
set LINK=/nologo /LTCG /CLRIMAGETYPE:IJW /MANIFEST:NO /MACHINE:%TARGETX% /SUBSYSTEM:WINDOWS,6.0 /OPT:REF /OPT:ICF /DEFAULTLIB:msvcmrt.lib
set LIB=%WIMGAPI%;%LIB%
set CSC=/nologo /w:4 /d:INTEGRATED /o+ /target:module

:: Compiling resources omitted

@set CL_NATIVE=/c /FI"stdafx-native.h"
@set CL_MIXED=/c /clr /LN /FI"stdafx-mixed.h"
@set CL_PURE=/c /clr:safe /LN /GL /FI"stdafx-pure.h"

@set NATIVE=...
@set MIXED=...
@set PURE=...

cl %CL_NATIVE% %NATIVE%
cl %CL_MIXED% %MIXED%
cl %CL_PURE% %PURE%
link /LTCG /NOASSEMBLY /DLL /OUT:%OUT%\core.netmodule %OUT%\*.obj

csc %CSC% /addmodule:%OUT%\core.netmodule /out:%OUT%\GUI.netmodule /recurse:*.cs

link /FIXED /ENTRY:GUI.Program.Main /OUT:%OUT%\XXX.exe ^
/ASSEMBLYRESOURCE:%OUT%\core.resources,XXX.resources,PRIVATE /ASSEMBLYRESOURCE:%OUT%\GUI.resources,GUI.resources,PRIVATE ^
/ASSEMBLYMODULE:%OUT%\core.netmodule %OUT%\gui.res %OUT%\*.obj %OUT%\GUI.netmodule

Mise à jour 1

En compilant cela avec des symboles de débogage et en essayant à nouveau, j'obtiens en fait plus d'informations. La pile d'appels est:

msvcr90d.dll!_msize_dbg(void * pUserData, int nBlockUse)  Line 1511 + 0x30 bytes
msvcr90d.dll!_dllonexit_nolock(int (void)* func, void (void)* * * pbegin, void (void)* * * pend)  Line 295 + 0xd bytes
msvcr90d.dll!__dllonexit(int (void)* func, void (void)* * * pbegin, void (void)* * * pend)  Line 273 + 0x11 bytes
XXX.exe!_onexit(int (void)* func)  Line 110 + 0x1b bytes
XXX.exe!atexit(void (void)* func)  Line 127 + 0x9 bytes
XXX.exe!`dynamic initializer for 'Bytes::Null''()  Line 7 + 0xa bytes
mscorwks.dll!6cbd1b5c()
[Frames below may be incorrect and/or missing, no symbols loaded for mscorwks.dll]
...

La ligne de mon code qui «provoque» ceci (initialiseur dynamique pour Bytes::Null) est:

Bytes Bytes::Null;

Dans l'en-tête qui est déclaré:

class Bytes { public: static Bytes Null; }

J'ai également essayé de faire un externe mondial dans l'en-tête comme tel:

extern Bytes Null; // header
Bytes Null; // cpp file

Qui a échoué de la même manière.

Il semble que le CRT atexit La fonction est responsable, étant requise par inadvertance en raison de l'initialisateur statique.


Réparer

Comme Ben Voigt l'a souligné l'utilisation de toutes les fonctions CRT (y compris les initialiseurs statiques natifs) nécessite une initialisation appropriée du CRT (qui se produit dans mainCRTStartup, WinMainCRTStartup, ou _DllMainCRTStartup). J'ai ajouté un fichier C ++ / CLI mixte qui a un C ++ main ou WinMain:

using namespace System;
[STAThread] // required if using an STA COM objects (such as drag-n-drop or file dialogs)
int main() { // or "int __stdcall WinMain(void*, void*, wchar_t**, int)" for GUI applications
    array<String^> ^args_orig = Environment::GetCommandLineArgs();
    int l = args_orig->Length - 1; // required to remove first argument (program name)
    array<String^> ^args = gcnew array<String^>(l);
    if (l > 0) Array::Copy(args_orig, 1, args, 0, l);
    return XXX::CUI::Program::Main(args); // return XXX::GUI::Program::Main(args);
}

Après cela, le programme devient maintenant un peu plus loin, mais a toujours des problèmes (qui seront traités ailleurs):

  • Lorsque le programme est uniquement en C #, cela fonctionne bien, avec chaque fois qu'il s'agit simplement d'appeler des méthodes C ++ / CLI, d'obtenir des propriétés C ++ / CLI et de créer des objets C ++ / CLI gérés
  • Les événements ajoutés par C # dans le code C ++ / CLI ne tirent jamais (même s'ils le devraient)
  • Une autre erreur étrange est qu'une exception se produit est un dicton invalidcastException ne peut pas couler de x à x (où x est le même que x ...)

Cependant, puisque la corruption du tas est fixée (en faisant initialiser le CRT), la question est faite.

Pas de solution correcte

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top