IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

Segmentation fault sur new[] et delete[]


Sujet :

C++

  1. #1
    Membre du Club
    Inscrit en
    Avril 2004
    Messages
    46
    Détails du profil
    Informations forums :
    Inscription : Avril 2004
    Messages : 46
    Points : 46
    Points
    46
    Par défaut Segmentation fault sur new[] et delete[]
    J'ai un souci dans une application C++ sous Linux.

    J'ai ce genre d'erreurs avec gdb :

    Program received signal SIGSEGV, Segmentation fault.
    [Switching to Thread -1211122768 (LWP 24151)]
    0xb7d61543 in free () from /lib/tls/i686/cmov/libc.so.6
    (gdb) bt
    #0 0xb7d61543 in free () from /lib/tls/i686/cmov/libc.so.6
    #1 0xb7d633b1 in malloc () from /lib/tls/i686/cmov/libc.so.6
    #2 0xb7f124c5 in operator new () from /usr/lib/libstdc++.so.6
    #3 0xb7f125fc in operator new[] () from /usr/lib/libstdc++.so.6
    Une ligne typique qui fait ce genre d'erreurs :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    char * buffer = new char[bufLen];
    J'ai vérifié, les dimensions sont OK (de l'ordre d'une centaine d'octets). Le seul truc un peu "spécial" de mon appli, c'est simplement que tout s'exécute dans un nouveau thread que je crée ainsi :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
        // Create the thread
        int err = pthread_create(&m_pThreadRecv, NULL, threadRecvProc, this);
     
        if (err != 0)
        {
            cerr << "pthread_create() failed (error " << err << ")." << endl;
            return false;
        }
    Si je ne m'abuse, la mémoire par défaut pour un thread c'est 8 Mo non ? enfin bref c'est largement supérieur à 100 octets, je comprend vraiment pas pourquoi un bête new[] peut tout faire planter...

    EDIT:

    J'ai le même souci avec delete[] :

    *** glibc detected *** double free or corruption (!prev): 0x080e7588 ***

    Program received signal SIGABRT, Aborted.
    [Switching to Thread -1211245648 (LWP 24897)]
    0xffffe410 in __kernel_vsyscall ()
    (gdb) bt
    #0 0xffffe410 in __kernel_vsyscall ()
    #1 0xb7d089d1 in raise () from /lib/tls/i686/cmov/libc.so.6
    #2 0xb7d0a2e9 in abort () from /lib/tls/i686/cmov/libc.so.6
    #3 0xb7d3c70a in __fsetlocking () from /lib/tls/i686/cmov/libc.so.6
    #4 0xb7d42f74 in malloc_trim () from /lib/tls/i686/cmov/libc.so.6
    #5 0xb7d432ea in free () from /lib/tls/i686/cmov/libc.so.6
    #6 0xb7ef2c71 in operator delete () from /usr/lib/libstdc++.so.6
    #7 0xb7ef2ccc in operator delete[] () from /usr/lib/libstdc++.so.6
    Je ne fais qu'un seul free, ça c'est sûr. Mais j'ai aucune idée de la nature de la "corruption", j'ai pasl'impression que ce soit un dépassement de tampon pourtant, j'écris itérativement dans le buffer et je compare à la fin l'index avec la quantité de mémoire allouée.

  2. #2
    Rédacteur

    Avatar de Matthieu Brucher
    Profil pro
    Développeur HPC
    Inscrit en
    Juillet 2005
    Messages
    9 810
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations professionnelles :
    Activité : Développeur HPC
    Secteur : Industrie

    Informations forums :
    Inscription : Juillet 2005
    Messages : 9 810
    Points : 20 970
    Points
    20 970
    Par défaut
    Tu ne donnes pas assez d'information ou de code pour qu'on puisse t'aider, je crois

  3. #3
    Membre du Club
    Inscrit en
    Avril 2004
    Messages
    46
    Détails du profil
    Informations forums :
    Inscription : Avril 2004
    Messages : 46
    Points : 46
    Points
    46
    Par défaut
    Le problème touche toutes les portions où ya de la mémoire dynamique, et le code est volumineux, donc je préférais expliquer, mais je peux faire un résumé avec juste la partie Linux qui pose problème :

    Le programme principal crée un serveur UDP et rien d'autre :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
        // Platform-dependant server
        PosixCobraServer server;
     
        // Infinite loop
        while(true)
        {
            // The server receives packets in its thread
            sleep(60);
        }
    La classe PosixCobraServer est une implémentation Posix de mon serveur générique :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    // POSIX implementation of CobraServer
    class PosixCobraServer : public CobraServer
    {
    public:
        // Default constructor of PosixCobraServer
        PosixCobraServer(unsigned short port = COBRA_SERVER_PORT);
     
    protected:
        // Copy constructor
        PosixCobraServer(const PosixCobraServer & cobraServer);
     
    protected:
        // Start the server on the specified port
        virtual bool startServer(unsigned short port);
     
        // Thread procedure which receives requests
        static void * threadRecvProc(void * lpParam);
     
        // Thread handle which receives requests
        pthread_t m_pThreadRecv;
    };
    startServer est appelée dans le constructeur :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    // Start the server on the specified port
    bool PosixCobraServer::startServer(unsigned short port)
    {
        // Start UDP Server
        if (!CobraServer::startServer(port))
        {
            cerr << "CobraServer::startServer() failed." << endl;
            return false;
        }
     
        // Create the thread
        int err = pthread_create(&m_pThreadRecv, NULL, threadRecvProc, this);
     
        if (err != 0)
        {
            cerr << "pthread_create() failed (error " << err << ")." << endl;
            return false;
        }
        else
        {
            cout << "Cobra Server listening on UDP port " << port << "..." << endl;
        }
     
        return true;
    }
    Quand à la fonction du thread, la voici :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    // Thread which receives requests
    void * PosixCobraServer::threadRecvProc(void * lpParam)
    {
        PosixCobraServer server(*(PosixCobraServer*)lpParam);
        threadRequestsHandler(&server);
        return NULL;
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
     
    // Thread which receives requests
    // 'arg' is the address of a CobraServer object
    void CobraServer::threadRequestsHandler(void * arg)
    {
        CobraServer * server = (CobraServer *)arg;
     
        byte buffer[CobraPacket::DP_SIZE] = {0};
        struct sockaddr_in addr_client;
        socklen_t addr_client_size = sizeof(addr_client);
     
        while (true)
        {
            cout << "attente de paquet..." << endl;
            // Clean buffer
            memset(buffer, 0, sizeof(buffer));
            // Receive packet
            int nBytes = recvfrom(server->m_socket, (char *)buffer, sizeof(buffer), 0, 
                (sockaddr*)&addr_client, &addr_client_size);
     
            if (nBytes > 0)
            {
                try
                {
                    cout << "paquet recu, construction de CobraPacket." << endl;
                    CobraPacket packet(buffer, nBytes);
                    cout << "CobraPacket construit, traitement..." << endl;
                    server->handleRequest(packet, addr_client);
                }
                catch (string s)
                {
                    cerr << s << endl;
                }
            }
        }
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
     
    // Main request handler
    bool CobraServer::handleRequest(const CobraPacket& request, sockaddr_in addr_client)
    {
        string order = request.getDataName();
     
        map<string, handler>::iterator it = m_handlers.find(order);
     
        if (it != m_handlers.end())
        {
            // Displays IP address of client
            char * ip_addr = inet_ntoa(addr_client.sin_addr);
            cout << '"' << order << '"' << " received from " 
                << (ip_addr ? ip_addr : "(error)") << endl;
            // Handle request
            return (this->*it->second)(request, addr_client);
        }
        else
        {
            cerr << "Requete inconnue : " << order << endl
                << "Details du paquet recu :" << endl << request << endl;
        }
     
        return false;
    }
    J'ai un handler par type de message. En gros les handlers ne manipulant pas la mémoire dynamique marchent, les autres plantent avec des SIGSEGV et co... J'espère que c'est pas trop long comme message, j'ai essayé de faire au plus court.

  4. #4
    Rédacteur

    Avatar de Matthieu Brucher
    Profil pro
    Développeur HPC
    Inscrit en
    Juillet 2005
    Messages
    9 810
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations professionnelles :
    Activité : Développeur HPC
    Secteur : Industrie

    Informations forums :
    Inscription : Juillet 2005
    Messages : 9 810
    Points : 20 970
    Points
    20 970
    Par défaut
    J'ai pas trop vu de mémoire dynamique dans ce que tu as donné...
    Il y a combien de threads qui tournent en // ? Chacun gère une classe ? Est-ce que ces classes partagent des variables ? Est-ce que ces variables partagées ne sont pas désallouées plusieurs fois ?
    Pour ce genre de choses, les boost::shared_ptr sont pas mal, au besoin.

  5. #5
    Membre du Club
    Inscrit en
    Avril 2004
    Messages
    46
    Détails du profil
    Informations forums :
    Inscription : Avril 2004
    Messages : 46
    Points : 46
    Points
    46
    Par défaut
    J'ai enfin trouvé ! (enfin je crois, il me reste à corriger le problème maintenant )

    J'explique ma démarche si jamais quelqu'un rencontre un problème identique.

    Les opérateurs new et delete ont la facheuse tendance de planter dès lors qu'on corrompt les tables de malloc. Pour trouver d'où venaient ces corruptions (elles sont à des années-lumières des appels à new et delete), j'ai installé une librairie qui remplace malloc : Electric Fence (merci google)

    Cette lib fait planter l'exécutable au moindre buffer overflow, ce qui m'a montré que le problème vient des appels à la fonction mbstowcs(), qui convertit des char * en wchar_t *.

    Le truc c'est que j'ai fixé la taille de wchar_t à 2 octets, parce que ça m'arrangeait bien étant donné que les chaines Unicode que je reçois sur le serveur sont codés sur 2 octets. Mais j'avais pas pensé que les appels système de conversion unicode->ascii gardent le comportement par défaut, à savoir qu'un wchar_t est codé sur 4 octets ^^

    Effectivement j'aurais du préciser ce détail, je te remercie néanmoins énormément d'avoir lu et répondu à mon sujet.

    Je teste ça vite fait et si ça marche je met le tag Résolu.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 9
    Dernier message: 24/01/2008, 12h53
  2. Segmentation fault sur mon serveur
    Par zoullou dans le forum Administration système
    Réponses: 2
    Dernier message: 06/04/2007, 10h17
  3. Segmentation fault sur script PHP
    Par zoullou dans le forum Langage
    Réponses: 1
    Dernier message: 03/04/2007, 09h32
  4. Segmentation Fault sur un fclose
    Par Beush dans le forum C
    Réponses: 9
    Dernier message: 30/11/2005, 19h30
  5. Segmentation fault sur un gethostbyname ?
    Par Mitox dans le forum Réseau
    Réponses: 9
    Dernier message: 25/11/2005, 16h17

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo