Debug vs. Release



  • Hi, ich habe ein Programm geschrieben, das in der Debug-Version tadellos läuft, nur in der Release-Version stürzt es sofort ab:

    Die Anweisung 0x0000004e verweist auf Speicher 0x0000004e und der Vorgang read konnte dadrauf nicht ausgelöst werden.
    [Die Adressen stimmen übrigens ;)]

    Leider ist das Problem etwas subtiler, ich habe bis jetzt aber den Fehler zumindest schon mal auf einen Funktionsaufruf eingrenzen können (s. u., groß markiert)

    //
    // Wichtig ist eigentlich nur der eingerahmte Methodenaufruf mit InsertItem
    //
    // Es soll eigentlich nur ein TreeCtrl vorbereitet werden,
    // das Einträge hat, die aus einem Text und einem Icon bestehen
    // (wie z.B. Baumansicht im Explorer)
    //
    //
    
    BOOL DefaultDlg::OnInitDialog()
    {
      CDialog::OnInitDialog();
    
      ...
    
      //  
      // Imageliste anlegen und in TreeCtrl einfügen
      //
      CBitmap book, openbook, note;
    
      // Image-Liste für 24-Bit 18x18 Icons mit 0 Images und Wachstum 4 initialisieren
      m_images.Create(18, 18, ILC_COLOR24, 0, 4);        // -> CImageList m_images;
    
      // Icons für Image-Liste für TreeCtrl aus Ressourcen laden
      book.LoadBitmap(IDB_BOOK);
      openbook.LoadBitmap(IDB_OPENBOOK);
      note.LoadBitmap(IDB_NOTE);
    
      // Icons zur Image-Liste hinzufügen
      m_images.Add(&book, RGB(0, 0, 0));
      m_images.Add(&openbook, RGB(0, 0, 0));
      m_images.Add(&note, RGB(0, 0, 0));
    
      // Image-Liste an TreeCtrl anhängen
      m_database.SetImageList(&m_images, TVSIL_NORMAL);  // -> CTreeCtrl m_database
    
                                                         // (genauer gesagt ist m_database eigentlich public von CTreeCtrl abgeleitet
                                                         // und um ein paar Methoden ergänzt, aber das spielt glaube ich keine Rolle...)
    
    //************ *HIER* steigt er aus: ****************************
    
      // Anlegen des Root-Eintrags der TreeCtrl
      m_database.InsertItem(TVIF_TEXT | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE,  // UINT nMask
                            "Wurzel",  // LPCTSTR lpszItem
                            0,         // int nImage
                            0,         // int nSelectedImage
                            0,         // UINT nState
                            0,         // UINT nStateMask
                            0,         // LPARAM lParam
                            NULL,      // HTREEITEM hParent
                            TVI_SORT); // HTREEITEM hInsertAfter
    
    //***************************************************************
    
      ...
    
      return TRUE;
    }
    

    So, ich hoffe, ihr könnt was damit anfangen. In der MSDN bin ich leider nicht besonders schlau geworden zum Thema TreeCtrl etc., deswegen nehme ich wie gesagt an, dass da der Fehler liegt, debuggen geht ja leider nicht 😞



  • Andi schrieb:

    [Die Adressen stimmen übrigens ;)]

    In welcher Hinsicht?

    Du kannst in den Projektoptionen einstellen, dass Debuginformationen erstellt werden sollen in deiner Release-Projektkonfiguration. Dann bleiben Präprozessormakros oder sonstige Dinge erhalten aber du kannst trotzdem debuggen. Denkbar wäre zum Beispiel ein Fehler ausgelöst durch einen Funktionsaufruf in einem Assert-Makro, der bei einer Releasekompilierung natürlich komplett verschwindet.



  • [Die Adressen stimmen übrigens ;)]

    In welcher Hinsicht?

    Ich habe die Adressen abgetippt -> Win2k beschwert sich jedesmal mit diesem 0x0004e.

    du kannst trotzdem debuggen

    Ich habe unter Project Settings -> C/C++ -> General -> Debug Info "Program Database for Edit and Continue" eingestellt, aber bisher hat VC 6.0 nur Assembler-Code präsentiert mit lauter Fragezeichen 😞

    Denkbar wäre zum Beispiel ein Fehler ausgelöst durch einen Funktionsaufruf in einem Assert-Makro, der bei einer Releasekompilierung natürlich komplett verschwindet

    Die Debug-Version funktioniert vollkommen korrekt und liefert keine Assert-Unterbrechungen.



  • Naja, ich kann dazu nicht viel sagen, weil mir Visual Studio 6 in der Hinsicht nicht bekannt ist. Bei Visual Studio 7 gibt es da sowohl "Programmdatenbank" als auch "Programmdatenbank zum Bearbeiten und Fortfahren" wobei in dem Fall die erste Option die richtige wäre, denke ich.

    Andi schrieb:

    Denkbar wäre zum Beispiel ein Fehler ausgelöst durch einen Funktionsaufruf in einem Assert-Makro, der bei einer Releasekompilierung natürlich komplett verschwindet

    Die Debug-Version funktioniert vollkommen korrekt und liefert keine Assert-Unterbrechungen.

    Damit meinte ich, dass ein eventuelles

    assert( WichtigeFunktionDieBoolZurueckgibt() );
    

    in der Releasekonfiguration nicht nur nicht überprüft wird sondern der Funktionsaufruf auch verschwindet.



  • Da gibts schon was in der FAQ!!

    Eine Fehler in der Release musst du immer mit eigener Debugausgabe (MessageBox,etc.) suchen.



  • Und dann ist da noch DER Klassiker:
    http://www.codeproject.com/debug/survivereleasever.asp
    🙂



  • Erstmal Danke für die Hilfe. Weiß denn vielleicht doch jemand, ob ich in OnInitDialog (Code s.o.) einen Fehler gemacht habe?

    Ich habe leider noch nie vorher mit CTreeCtrl gearbeitet und ich finde diese Klasse auch etwas kryptisch und die MSDN war hier wie gesagt ziemlich spartanisch in Sachen Erklärungen.



  • Ich kann dir zwar nicht sagen, ob das mit deinem Absturz zu tun hat,
    wenn du jedoch einen Wurzeleintrag in ein TreeView Control einfügen willst, so solltest du als Parent Eintrag ( hParent ) TVI_ROOT nehmen.

    Lt. COMMCTRL.H ist TVI_ROOT wie folgt definiert:

    #define TVI_ROOT                ((HTREEITEM)0xFFFF0000)
    

    //************ *HIER* steigt er aus: ****************************

    // Anlegen des Root-Eintrags der TreeCtrl
    m_database.InsertItem(TVIF_TEXT | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE, // UINT nMask
    "Wurzel", // LPCTSTR lpszItem
    0, // int nImage
    0, // int nSelectedImage
    0, // UINT nState
    0, // UINT nStateMask
    0, // LPARAM lParam
    NULL, // HTREEITEM hParent -> Hier TVI_ROOT verwenden
    TVI_SORT); // HTREEITEM hInsertAfter

    //***************************************************************

    Du verwendest als Parent Eintrag NULL welches nicht für Root-Einträge geeignet ist.



  • Das wars leider auch nicht 😞

    Hat es vielleicht etwas damit zu tun, dass ich das TreeCtrl mit dem VC 6.0-Editor erstellt habe und der Austausch mit dem zugehörigen Objekt (m_database) nur über DoDataExchange() via

    void DefaultDlg::DoDataExchange(CDataExchange *pDX)
    {
      CDialog::DoDataExchange(pDX);
    
      DDX_Control(pDX, IDC_IDENTIFIKATION_DES_TREE_CTRLS, m_database);
    
    }
    

    abläuft? Ich hätte eigentlich erwartet, dass man sowas machen muss wie

    MeinTreeCtrlObjekt.AttachControl(IDC_IDENTIFIKATION_DES_RESSOURCEN_CTRLS)
    

    damit das Windows-Control und mein Objekt wissen, dass sie "zusammen gehören", aber das gibt's ja gar nicht. Ich hoffe, das oben ist ausreichend 🙂



  • Der vom Classwizzard eingefügte Code DDX_Control macht genau das was du meinst. Er ordnet das Windows Fensterobjekt dem C++ Objekt zu. Das und das Ersetzen der WndProc nennt man Subclassing.

    Ich glaube nicht, dass es daran liegt, dass dein Programm abstürzt.
    Die Ursachen für Abstürze in der Release, die nicht in der Debug-Version auftreten, sind vielfältig. Eine andere Möglichkeit wären z.B. casts auf Funktionspointer, wie sie z.B von der MessageMap verwendet werden. Hast du in den Zeilen zwischen BEGIN_MESSAGE_MAP und END_MESSAGE_MAP manuell etwas geändert oder hinzugefügt ?
    Wenn die Parameterliste von deinen Funktionen nicht mit denen übereinstimmen, die in der Doku definiert sind, wird der Stack nicht korrekt aufgeräumt -> Absturz.

    Vielleicht hilft es auch, die Absturzstelle näher zu untersuchen und mal zu überprüfen, ob irgendwelche Variablen ( z.B. Zähler ) auf dem Wert 0x4e stehen. Damit kann man die Fehlerursache etwas eingrenzen.

    Um an entsprechende Abstürze zu kommen, können Tools helfen, die Aufrufe von API-FUnktionen und den Stack untersuchen. Beispiele hierfür wären IBM Purify oder Compuware Boundschecker. Beide haben ihre Stärken und Schwächen. Es gibt von beiden Testversionen.

    Ich wünsche Dir viel Erfolg bei der Fehlersuche. 🙂


Anmelden zum Antworten