Segmentation fault: 11 bei delete



  • Hallo,

    ich bekomme bei einem Aufruf von delete einen Programmabbruch mit der Fehlermeldung "Segmentation fault: 11". Eine kurze Recherche zu dem Fehler bringt mich zu der bedeutung "Signal 11, or officially know as "segmentation fault", means that the program accessed a memory location that was not assigned."

    Leider kann ich die Stelle bei der ich auf nicht assignedten Speicher zugreife nicht erkennen.

    auszug ATSTelephonyObserver.mm:

    std::vector<ATSCmd*> cmdVector;
    
    ATSSms* readSMS(CFDictionaryRef userInfo){
      ...
      return new ATSSms(senderNumber.UTF8String,smsText.UTF8String);
    }
    
    void ATSTelephonyObserver::callback(CFStringRef name){
      NSString * nsname = ( NSString *)name;
      if([nsname isEqualToString:@"kCTMessageReceivedNotification"]){
        ATSSms* sms = readSMS(userInfo);
        try{
          ATSCmd*  cmd = sms->toATSCmd(self->satsData);
          cmdVector.push_back(cmd);
        }catch(char const* ch){
          std::cout << "sms keine atsSMS weil: " << ch;
        }
        delete sms;
      }else if([nsname isEqualToString:@"kCTRegistrationNetworkSelectedNotification"]){
        while(cmdVector.back()!=0){
          ATSCmd* cmd = cmdVector.back();
          cmd->proceed();
          cmdVector.pop_back();
          delete cmd; //<---------- hier kommt der "Segmentation fault: 11"
        }
      }
    }
    

    ATSSms.h:

    #ifndef __ATSSmsCmd_H_
    #define __ATSSmsCmd_H_
    
    #include <iostream>
    #include "ATSData.h"
    #include "ATSCmd.h"
    
    class ATSSms {
        public:
            ATSSms(std::string number, std::string txt){
                this->number = number;
                this->txt = txt;
            };
            std::string getNumber(){return this->number;};
            std::string getText(){return this->txt;};
            ATSCmd* toATSCmd(ATSData &atsData);
        private:
            std::string number;
            std::string txt;
    };
    
    #endif //__ATSSmsCmd_H_
    

    ATSSms.mm:

    #include "../headers/ATSSms.h"
    #include "../headers/functions.h"
    
    ATSCmd* ATSSms::toATSCmd(ATSData &atsData) {
    
        std::string txt = this->txt;
        std::string val = ":";
    
        int dpcount = countPartStr(txt, val);
        if (!(dpcount >= 2)) {
            throw "double dot count < 2";
        }
        std::string part = txt.substr(0, 4);
        if ((part.compare("ats:"))) {
            throw "no ats sms";
        }
        int pos = txt.find(val, 4);
        part = txt.substr(4, pos - 4);
        if((part.compare("1234"))){
            throw "ats-command password wrong";
        }
        if ((dpcount == 2)) {
            part = txt.substr(pos+1);
        }else{
            int pos2 = txt.find(val, pos+1);
            part = txt.substr(pos+1, pos2-pos-1);
        }
        if(part.length()<1){
            throw "ats-command-string lenth 0";
        }
    
        //Auswertung:
        if(!(part.compare("locate"))){
            return new ATSSendLocationSmsCmd(this->number);
        } else if(!(part.compare("lock"))) {
            return new ATSLockDevice();
        } else {
            throw "ats-command-string unknown";
        }
    }
    

    ATSCmd.h

    #ifndef __ATSCmd_H_
    #define __ATSCmd_H_
    
    #include <iostream>
    #include <CoreTelephony/CTMessageCenter.h>
    
    /*abstract*/
    class ATSCmd {
    public:
        virtual void proceed()=0;
    };
    
    class ATSSendSmsCmd : public ATSCmd{
    public:
        ATSSendSmsCmd(std::string number,std::string txt){
            this->number = number;
            this->txt = txt;
        };
        void proceed();
        private:
        std::string number;
        std::string txt;
    };
    
    class ATSSendLocationSmsCmd : public ATSCmd {
        public:
            ATSSendLocationSmsCmd(std::string number){this->number = number;};
            void proceed();
        private:
            std::string number;
    };
    
    class ATSLockDevice : public ATSCmd {
        public:
            ATSLockDevice():ATSCmd(){};
            void proceed();
    };
    
    #endif //__ATSCmd_H_
    

    Wenn ich die Zeile "delete cmd;" herrausnehme tritt kein Fehler auf, aber habe ich dann nicht ein memory-leak?

    PS: Es handelt sich um objective c++ code für iOS.

    lg, Phill



  • Edit: Habe dein P.S.: Nicht gesehen.
    Aber trotzdem, falsches Forum, wieso gehst du nicht in ein Forum deiner Programmiersprache?



  • du machst ein delete auf einen zeiger der basis klasse (welche du als ein Interface verwendest).
    Dadurch wird nicht das komplette objekt zerstört, da du keinen virtuellen destruktor in der basis klasse definiert hast.



  • Soahc schrieb:

    std::vector<ATSCmd*> cmdVector;
    /// [...]
        while(cmdVector.back()!=0){
          ATSCmd* cmd = cmdVector.back();
          cmd->proceed();
          cmdVector.pop_back();
          delete cmd; //<---------- hier kommt der "Segmentation fault: 11"
        }
      }
    }
    

    Was ist denn das für eine Laufbedingung? Wäre es nicht interessanter zu wissen, ob noch Elemente im Vektor sind?!



  • while(cmdVector.back()!=0)
    

    Du machst also folgendes:
    -> prüfen ob der letzte Zeiger im Vector ein Nullpointer ist
    -> wenn nicht das letzte Element aus dem Vector entfernen

    Und was passiert wohl, wenn kein Nullpointer im vector drin ist? Ich weiß nicht genau, was für einen Zeiger back() dann zurück liefert, es ist wahrscheinlich einer, der auf Speicherbereich zeigt, der dir nicht gehört.

    Benutz doch einfach for_each und einen reverse_iterator . Oder nimm die gute alte for -Schleife.

    Aber trotzdem, falsches Forum, wieso gehst du nicht in ein Forum deiner Programmiersprache?

    Mal wieder sehr nützlich, weil sich sein Problem auch gar nicht um C++ dreht ist er im falschen Forum. Die Frage kann man, also jeder außer dir, auch ohne Objective C++-Kenntnisse beantworten.



  • Sone schrieb:

    Aber trotzdem, falsches Forum, wieso gehst du nicht in ein Forum deiner Programmiersprache?

    Bei objective c++ kann man sowohl c++ als auch objective c verwenden und auch unter bestimmten Bedingungen mischen. De Abgesehen von ein paar Funtkionsaufrufen und Datentypen ist kaum Objective-C code dabei. Ich habe die Frage hier gepostet, da sich die von mir vermutete Fehlerquelle ausschließlich auf c++ code bezieht.

    firefly schrieb:

    du machst ein delete auf einen zeiger der basis klasse (welche du als ein Interface verwendest).
    Dadurch wird nicht das komplette objekt zerstört, da du keinen virtuellen destruktor in der basis klasse definiert hast.

    du hast mich ertappt. ich komme eigentlich aus der java-fraktion. Ich wollte die basisklasse als eine art interface verwenden und wusste nicht, dass dann der destruktor virtuell sein muss. Mir war nicht mal klar, dass man hier überhaupt einen Destruktoe benötigt, weil die klassen ja keine dynamisch erzeugten Objekte bzw. angeforderten Speicher in form von Zeigern verwalten. Eine kleine Frage dazu. Wenn ich in der Basisklasse den Destruktor virtuell mache, muss er dann auch in allen abgeleitetten Klassen virtuell sein? Also auch wenn sich am Destruktor selber nichts verändern würde.

    Der Tobi schrieb:

    Du machst also folgendes:
    -> prüfen ob der letzte Zeiger im Vector ein Nullpointer ist
    -> wenn nicht das letzte Element aus dem Vector entfernen

    Und was passiert wohl, wenn kein Nullpointer im vector drin ist? Ich weiß nicht genau, was für einen Zeiger back() dann zurück liefert, es ist wahrscheinlich einer, der auf Speicherbereich zeigt, der dir nicht gehört.

    Benutz doch einfach for_each und einen reverse_iterator . Oder nimm die gute alte for -Schleife.

    Ich habe bisher leider nur sehr wenig mit der STL gearbeitet und muss da wohl noch einiges lernen. ich hatte mir die Referenz der Back-Methode des Vectors unter http://www.cplusplus.com/reference/stl/vector/back/ angesehen und dort wird als Beispiel das gezeigt, was teil meines codes ist.
    Aber danke für den Tip, ich werde den code gleich anpassen. 🙂

    lg Phill



  • Soahc schrieb:

    du hast mich ertappt. ich komme eigentlich aus der java-fraktion. Ich wollte die basisklasse als eine art interface verwenden und wusste nicht, dass dann der destruktor virtuell sein muss. Mir war nicht mal klar, dass man hier überhaupt einen Destruktoe benötigt, weil die klassen ja keine dynamisch erzeugten Objekte bzw. angeforderten Speicher in form von Zeigern verwalten. Eine kleine Frage dazu. Wenn ich in der Basisklasse den Destruktor virtuell mache, muss er dann auch in allen abgeleitetten Klassen virtuell sein? Also auch wenn sich am Destruktor selber nichts verändern würde.

    Die destruktoren der abgeleiteten Klassen sind automatisch auch virtual, wenn der Destruktor der Basis virtuell ist.



  • Und wenn Du ein vererbtes Objekt über den Basisklassenzeiger (statischer Typ == Basisklasse) löscht, dann brauchst Du eben auch dann einen virtuellen destructor, wenn es keine dynamisch verwalteten Elemente gibt - um Deine Erkenntnis nochmal zu bestätigen.



  • Soahc schrieb:

    Ich habe bisher leider nur sehr wenig mit der STL gearbeitet und muss da wohl noch einiges lernen. ich hatte mir die Referenz der Back-Methode des Vectors unter http://www.cplusplus.com/reference/stl/vector/back/ angesehen und dort wird als Beispiel das gezeigt, was teil meines codes ist.

    Dort passiert mit dem Vector aber etwas völlig anderes als bei dir. 🙂
    Im Beispiel wird der Vector durch die Schleife stets vergrößert bis halt irgendwann "0" als letztes Element enthalten ist. Also ist "myvector.back()" auch stets ein valider Aufruf.

    Bei dir wird der Vector mit jeder Iteration verkleinert (gedacht ist wohl bis keine Elemente mehr enthalten sind). Wenn der Vector leer ist, ist "cmdVector.back()" nicht mehr valide, es gibt ja kein letztes Element. 😉

    Abgesehen von "for" oder "for_each" kannst du natürlich auch einfach die Bedingung der while-Schleife ändern in:

    while (!cmdVector.empty()) {
        // ...
    }
    


  • Vielen Dank für die Tips und Erklärungen... das Programm läuft inzwischen ohne Fehler durch. Ich bin wirklich erstaunt über die Hilfsbereitschaft der Mitglieder dieses Forums.


Anmelden zum Antworten