terminate called after throwing an instance of 'std::length_error'



  • Hallo, ich hab ein Problem:
    Mein Programm stürtz immer mit folgender Zeile ab:

    terminate called after throwing an instance of 'std::length_error'
      what():  basic_string::_S_create
    Decoding.Aborted
    

    Haken ist nur das ich ihn mir nicht erklären kann, da das Programm
    1.unter MinGW funktionierd, der Fehler nur unter Linux kommt.
    2.ich mir nicht vorstellen kann, das ich den String überfordere, da ich lediglich ca. 9kB darin speicher.
    Ich konnte den Fehler auf die folgenden Zeilen eingrenzen:

    printf("Decoding.");
            if(i!=page.npos) page.erase(page.begin(),page.begin()+i);
            for(int x=0; x<5; x++)
            {
                i=page.find(std::string(">"));
                printf(".");
                if(i!=page.npos) page.erase(0,i+1);
            }
    

    weis jedoch nicht was daran falsch sein soll.
    Hoffe jemand weis mehr.
    Ich hab mir jetzt mal page.max_size() ausgeben lassen.
    Das ist jedoch größer als die Daten die rein sollen.

    MFG Thalhammer


  • Mod

    Bitte zeige ein compilierbares Minimalbeispiel und insbesondere den Inhalt des Strings. An dem Codefragment das du gezeigt hast, kann man aber schon einmal festmachen, dass du anscheinend C- und C++-Standardbibliothek mischt, etwas was fast immer schief geht, wenn man sich nicht genau auskennt. Auf jeden Fall kann in dem gezeigten Ausschnitt auch kein length_error geworfen werden, denn erase und find können keine length_error-Exception erzeugen.

    Mit Linux-Windows hat das sicherlich nur indirekt zu tun. Du wirst nicht sauber programmiert haben und dadurch undefiniertes oder implementierungsabhängiges Verhalten erzeugt haben.



  • Hier mal der ganze source, zum erstellen braucht man allerdings libcurl.

    #include <stdio.h>
    #include <stdlib.h>
    #include <string>
    #include <cstring>
    
    #include <curl/curl.h>
    
    struct MemoryStruct
    {
        char *memory;
        size_t size;
    };
    
    static size_t
    WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp)
    {
        size_t realsize = size * nmemb;
        struct MemoryStruct *mem = (struct MemoryStruct *)userp;
    
        mem->memory = (char*)realloc(mem->memory, mem->size + realsize + 1);
        if (mem->memory == NULL)
        {
            /* out of memory! */
            printf("not enough memory (realloc returned NULL)\n");
            exit(EXIT_FAILURE);
        }
    
        memcpy(&(mem->memory[mem->size]), contents, realsize);
        mem->size += realsize;
        mem->memory[mem->size] = 0;
    
        return realsize;
    }
    
    #define FROM    "<admin@mail.dothal.de>"
    #define TO      "<admin@mail.dothal.de>"
    #define CC      "<root@dothal.de>"
    
    #define Subject_line 5
    #define Content_line 7
    
    char *payload_text[]=
    {
        "Date: Mon, 29 Nov 2010 21:54:29 +1100\n",
        "To: " TO "\n",
        "From: " FROM "(Example User)\n",
        "Cc: " CC "(Another example User)\n",
        "Message-ID: <dcd7cb36-11db-487a-9f3a-e652a9458efd@rfcpedant.example.org>\n",
        "Subject: SMTP TLS example message\n",
        "\n", /* empty line to divide headers from body, see RFC5322 */
        "The body of the message starts here.\n\nIt could be a lot of lines, could be MIME encoded, whatever.\nCheck RFC5322.\n",
        NULL
    };
    
    struct upload_status
    {
        int lines_read;
    };
    
    static size_t payload_source(void *ptr, size_t size, size_t nmemb, void *userp)
    {
        struct upload_status *upload_ctx = (struct upload_status *)userp;
        const char *data;
    
        if ((size == 0) || (nmemb == 0) || ((size*nmemb) < 1))
        {
            return 0;
        }
    
        data = payload_text[upload_ctx->lines_read];
    
        if (data)
        {
            size_t len = strlen(data);
            memcpy(ptr, data, len);
            upload_ctx->lines_read ++;
            return len;
        }
        return 0;
    }
    
    int sendmail(char* subject,char* content)
    {
        payload_text[Subject_line]=subject;
        payload_text[Content_line]=content;
    
        CURL *curl;
        CURLcode res;
        struct curl_slist *recipients = NULL;
        struct upload_status upload_ctx;
    
        upload_ctx.lines_read = 0;
    
        curl = curl_easy_init();
        if (curl)
        {
            /* This is the URL for your mailserver. Note the use of port 587 here,
             * instead of the normal SMTP port (25). Port 587 is commonly used for
             * secure mail submission (see RFC4403), but you should use whatever
             * matches your server configuration. */
            curl_easy_setopt(curl, CURLOPT_URL, "smtp://dothal.de:25");
    
            /* In this example, we'll start with a plain text connection, and upgrade
             * to Transport Layer Security (TLS) using the STARTTLS command. Be careful
             * of using CURLUSESSL_TRY here, because if TLS upgrade fails, the transfer
             * will continue anyway - see the security discussion in the libcurl
             * tutorial for more details. */
            curl_easy_setopt(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_ALL);
    
            /* If your server doesn't have a valid certificate, then you can disable
             * part of the Transport Layer Security protection by setting the
             * CURLOPT_SSL_VERIFYPEER and CURLOPT_SSL_VERIFYHOST options to 0 (false).*/
            curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
            curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
            /* That is, in general, a bad idea. It is still better than sending your
            * authentication details in plain text though.
            * Instead, you should get the issuer certificate (or the host certificate
            * if the certificate is self-signed) and add it to the set of certificates
            * that are known to libcurl using CURLOPT_CAINFO and/or CURLOPT_CAPATH. See
            * docs/SSLCERTS for more information.
            */
            //curl_easy_setopt(curl, CURLOPT_CAINFO, "/path/to/certificate.pem");
    
            /* A common reason for requiring transport security is to protect
             * authentication details (user names and passwords) from being "snooped"
             * on the network. Here is how the user name and password are provided: */
            curl_easy_setopt(curl, CURLOPT_USERNAME, "admin@mail.dothal.de");
            curl_easy_setopt(curl, CURLOPT_PASSWORD, "------");
    
            /* value for envelope reverse-path */
            curl_easy_setopt(curl, CURLOPT_MAIL_FROM, FROM);
            /* Add two recipients, in this particular case they correspond to the
             * To: and Cc: addressees in the header, but they could be any kind of
             * recipient. */
            recipients = curl_slist_append(recipients, TO);
            recipients = curl_slist_append(recipients, CC);
            curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients);
    
            /* In this case, we're using a callback function to specify the data. You
             * could just use the CURLOPT_READDATA option to specify a FILE pointer to
             * read from.
             */
            curl_easy_setopt(curl, CURLOPT_READFUNCTION, payload_source);
            curl_easy_setopt(curl, CURLOPT_READDATA, &upload_ctx);
    
            /* Since the traffic will be encrypted, it is very useful to turn on debug
             * information within libcurl to see what is happening during the transfer.
             */
            curl_easy_setopt(curl, CURLOPT_VERBOSE, 0L);
    
            /* send the message (including headers) */
            res = curl_easy_perform(curl);
    
            /* free the list of recipients and clean up */
            curl_slist_free_all(recipients);
            curl_easy_cleanup(curl);
        }
        return 0;
    }
    
    int main(void)
    {
        int mail_val = 982000;
        while(1)
        {
            CURL *curl_handle;
    
            struct MemoryStruct chunk;
    
            chunk.memory = (char*)malloc(1);  /* will be grown as needed by the realloc above */
            chunk.size = 0;    /* no data at this point */
            printf("Downloading.");
            curl_global_init(CURL_GLOBAL_ALL);
            printf(".");
            /* init the curl session */
            curl_handle = curl_easy_init();
            printf(".");
            /* specify URL to get */
            curl_easy_setopt(curl_handle, CURLOPT_URL, "http://www.facebook.com/spieletipps.de");
            printf(".");
            curl_easy_setopt(curl_handle, CURLOPT_AUTOREFERER, 1L);
            printf(".");
            curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1L);
            printf(".");
            curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:10.0.2) Gecko/20100101 Firefox/10.0.2");
            printf(".");
            /* send all data to this function  */
            curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
            printf(".");
            /* we pass our 'chunk' struct to the callback function */
            curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk);
            printf(".");
            /* some servers don't like requests that are made without a user-agent
               field, so we provide one */
            curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0");
            printf(".");
            /* get it! */
            curl_easy_perform(curl_handle);
            printf(".");
            /* cleanup curl stuff */
            curl_easy_cleanup(curl_handle);
            printf(".[done]\n");
            printf("%lu bytes retrieved\n", (long)chunk.size);
            if(chunk.size>9000) printf("Warning, too big Document!\n");
            // Prozess Page
            std::string page=chunk.memory;
            unsigned int i=page.find(std::string("<span class=\"mfss fcg\"><span class=\"mfss fcg\">Spiele/Spielzeuge</span><br /><span class=\"mfss fcg\">"));
            printf("%i",chunk.size>page.max_size());
            printf("Decoding.");
            if(i<page.size()) page.erase(page.begin(),page.begin()+i);
            for(int x=0; x<5; x++)
            {
                i=page.find(std::string(">"));
                printf(".");
                if(i<page.size()) page.erase(0,i+1);
            }
            i=page.find(std::string(" "));
            printf(".");
            if(i<page.size()) page.erase(i,std::string::npos);
            i=page.find(std::string("."));
            printf(".");
            if(i<page.size()) page.erase(i,1);
            printf("[done]\n");
            printf("Likes:%s\n",page.c_str());
            if(chunk.memory)
                free(chunk.memory);
            int likes=atoi(page.c_str());
            /* we're done with libcurl, so clean it up */
            curl_global_cleanup();
            if(likes>=mail_val)
            {
                printf("Sending Email.");
                std::string message="Hallo Dominik,\nDie Facebook Like der SpieleTippsseite haben soeben eine neue Marke über schritten.\n";
                message+="Es sind nun schon ";
                message+=page;
                message+=" Stück!\n\n";
                message+="MFG FBLN";
                sendmail("Subject: FBLN Update\n",const_cast<char*>(message.c_str()));
                printf(".[done]\n");
                mail_val+=1000;
            }
            Sleep(10000);
        }
        return 0;
    }
    

    Hoffe es bringt was.
    Der Inhalt für den String kommt aus dem Internet und ist im Normalfall 8563 bytes lang.
    Es ist nicht der Code den ich vorhin hatte, da ich schon weiterprobiert hab, aber bis auf die Abfragen ob das ergebnis von find hinter der Länge liegt hat sich nichts geändert.
    Das oben läuft perfekt auf unter Windows und unter Linux eben nicht.
    Das ich die C funktion printf anstt der iostream bibliothek nutze hat einfach den Grund das ich für Libcurl ohnehin C einbauen muss und die iostream bibl. selbst unter release mit fast 900kB zu buche schlägt.


  • Mod

    Ich kann deinen Fehler nicht nachvollziehen. Der Code ist natürlich nicht so schön (auch in C darf man sauber programmieren), aber ich sehr nichts offensichtlich falsches. Der Compiler bringt keine ernsthaften Warnungen, das Programm läuft ('Tschuldigung für die Spammail) und valgrind schmeißt keine Fehler.

    edit: Benutzt du die libcurl auch richtig? Ich kenne mich mit curl nicht aus, aber wenn man das Programm unterbricht, dann meldet valgrind lauter fehlende Freigaben im curl-Code (hauptsächlich das global_init in Zeile 174 und das easy_perform in 199, aber auch ein paar andere). Das sieht so aus, als würde irgendeine Art Handle nicht sauber aufgeräumt. Denk dran, dass diese Inits bei jedem Schleifendurchgang ausgeführt werden.



  • Also der Curl code ist fast ausschlieslich aus den offizielen Beispielen der Curlseite, sollte also schon correct sein.
    Ja, ich bin mir bewusst, das es weder schön programmiert noch performance optimiert ist, da ich es mir nur schnell in 30minuten zsammengebastelt hab, da es eh keine dauerhafte Lösung ist, sondern nur als notifier für ein Gewinnspiel gebraucht wird.
    So wie ich das sehe giebt es valgrind nur für Linux, heist das es läuft bei unter Linux ohne Probleme ?
    Wenn ja: kann es dran liegen, das mein Linux PC nur ein Vserver ist, also virtualisiert ?


  • Mod

    Nein, das wird keine Betriebssystemsache sein. Geh das Programm doch einfach mal im Debugger durch und guck wo und warum der Fehler auftritt. Da du nirgendwo Abfragen durchführst, habe ich den Verdacht, dass irgendein Aufruf fehlschlägt und du dann auf irgendwelchem Datenmüll arbeitest.



  • Könnte es denn nicht wenigstens ein Compiler Fehler sein? 🕶



  • Ne sollte es eigentlich nicht sein, da ich die den g++ aus den Debian paketquellen hab und er auch nichts unnormales ausgiebt.



  • 🕶 Ich meinte ein Fehler im Compiler... es sollte eigentlich ein Scherz sein... typischerweise liegt der Fehler im eigenen Code und weder im OS noch im Compiler, noch im... Kann natürlich sein, ist aber ungemein unwahrscheinlicher.


Anmelden zum Antworten