Unger3eimtheit bei der Speicheranforderung



  • Hallo Leute,

    ich schreibe momentan eine (Server)-Anwendung in C. Der Haupteil läuft in der Funktion Communicate() ab, die ein Handle auf einen geöffneten Socket und eine geöffnete DB-Verbindung als Parameter kriegt. Das ist auch alles kein Problem.
    Aber: In der Funktion selber wird, je nachdem, was über den Socket eingelesen wird die 2., Funktion GetArzt() aufgerufen oder ein "unknown command" zurückgesendet. Wenn GetArzt() aufgerufen wird kriegt der Pointer *str die Addresse eines in GetArzt erzeugten char* das dort mit realloc etc. angepasst wird. In diesem Fall (GetArzt() wurde aufgerufen) wird der String, der an der Speicheraddresse beginnt, die GetArzt() zurückgibt, an den Client zurückgesendet.
    Und hier ist ein Fehler. Wenn ich Server und Client gestartet habe und "a" an den Server sende bekomme ich ein "unknown command" wie erwartet zurück. Schicke ich danach ein "arzt" erkennt das Communicate() und ruft GetArzt() auf, dass einen "String" aus der DB erzeugt. Geht auch. Krieg ich auch beim Clienten zu sehen. Ich kann jetzt sooft ich will "arzt" senden und es funktioniert immer, aber wenn ich von nun an einmal einen unknown command durch senden eines Wertes != "arzt" erzeuge und dann wieder "arzt" sende, kann GetArzt() an der Stelle, wo printf("-5-") in der Fehlerbehandlung erzeugt wird, keinen Speicher mehr allozieren.
    Außerdem scheint das "Server"-Programm hier in einer Schleife o.ä. zu hängen, auch wenn der Client abgeschoßen ist, wird der Prozess immer größer, normalerweise ist er nie mehr als 2mb groß.
    Die Datenmenge, die angefordert ist ist auch nie so groß, momentan ist sie, weil ich ja noch alles teste immer genau gleich (die DB wird halt noch nicht verändert), nämlich genau 17379bytes, das ist also die speichergröße, die für meinen pointer angefordert werden muss.

    ich habe hier die beiden hauptfunktionen mal gepostet, vielleicht sieht ja jemand den fehler, an einigen stellen ist der code evtl. etwas "unordentlich" das liegt daran, dass ich hier schon seit stunden alles mögliche ausprobiere und nicht auf die lösung komme. falls jemand was auffällt, oder verbesserungsvorschläge hat (hab bisher noch nie mit dynamischen arrays gearbeitet) sind diese natürlich immer willkommen 🙂

    vielen dank schonmal im vorraus
    david.

    int Communicate(SOCKET MySock,MYSQL *dbHandle)
    {
            char buffer[BUFFER_SIZE];
            int bytes;
            char *str;
            for(;;)
            {
                    free(str);
                    printf("Receiving...");
                    if((bytes=recv(MySock,buffer,sizeof(buffer)-1,0))==-1)
                    {
                            printf("recv() failed, %lu\n", (unsigned long) GetLastError());
                            return 1;
                    }
    
                    printf("Finished! Got %s...\n",buffer);
    
                    if(strcmp(buffer,"arzt")==0)
                    {
                            str=GetArzt(dbHandle);
                    }
                    else
                    {
                            str=(char *)realloc(str,(strlen("Unknown command\n\r")+1)*sizeof(char));
                            if(buffer!=NULL)
                            sprintf(str,"Unknown command\n\r");
                    }
                    str=(char *)realloc(str,(strlen(str)+1+1)*sizeof(char));
                    if(str!=NULL)
                    strcat(str,":");
                    printf("Sending...");
                    if((bytes=send(MySock,str,strlen(str),0))==-1)
                    {
                            printf("send() failed, %lu\n", (unsigned long) GetLastError());
                            return 2;
                    }
                    printf("finished.\n");
            }
            return 0;
    }
    
    char *GetArzt(MYSQL *dbHandle)
    {
            char *buffer=(char *)malloc(0);
            char query[BUFFER_SIZE];
            unsigned long *fieldLengths;
            unsigned int i, fieldNumbers;
            MYSQL_RES *dbResult;
            MYSQL_ROW dbRow;
    
            sprintf(query,"SELECT CONCAT(id,' ',vorname,' ',nachname) AS showe FROM aerzte WHERE nachname LIKE '%%' ORDER BY id ASC");
            if (mysql_query(dbHandle, query)!=0)
            {
                    buffer=(char *)realloc(buffer,(strlen("Query was not successful\n\r")+1)*sizeof(char));
                    if(buffer!=NULL)sprintf(buffer,"Query was not successful\n\r");
                    else
                    {
                            printf("-1-\n");
                            free(buffer);
                            buffer=NULL;
                            return NULL;
                    }
            }
            else
            {
                    dbResult = mysql_store_result(dbHandle);
                    if (dbResult==0)
                    {
                            buffer=(char *)realloc(buffer,(strlen("Problem with the result.\n\r")+1)*sizeof(char));
                            if(buffer!=NULL)sprintf(buffer,"Problem with the result.\n\r");
                            else
                            {
                                    printf("-2-\n");
                                    free(buffer);
                                    buffer=NULL;
                                    return NULL;
                            }
                    }
                    else
                    {
                            buffer=(char *)realloc(buffer,sizeof(char));
                            if(buffer!=NULL)buffer[0]='\0';
                            else
                            {
                                    printf("-3-\n");
                                    free(buffer);
                                    buffer=NULL;
                                    return NULL;
                            }
                            fieldNumbers = mysql_num_fields(dbResult);
                            while ((dbRow = mysql_fetch_row(dbResult)))
                            {
                                    fieldLengths = mysql_fetch_lengths(dbResult);
    
                                    for(i = 0; i < fieldNumbers; i++)
                                    {
                                            if (dbRow[i]==0)
                                            {
                                                    buffer=(char *)realloc(buffer,(strlen(buffer)+8+1)*sizeof(char));
                                                    if(buffer!=NULL)strcat(buffer," (null) ");
                                                    else
                                                    {
                                                            printf("-4-\n");
                                                            free(buffer);
                                                            buffer=NULL;
                                                            return NULL;
                                                    }
                                            }
                                            else
                                            {
                                                    buffer=(char *)realloc(buffer,(strlen(buffer)+strlen(dbRow[i])+1)*sizeof(char));
                                                    if(buffer!=NULL)strcat(buffer,dbRow[i]);
                                                    else
                                                    {
                                                            printf("-5-\n");
                                                            free(buffer);
                                                            buffer=NULL;
                                                            return NULL;
                                                    }
                                            }
                                    }
                                    buffer=(char *)realloc(buffer,(strlen(buffer)+2+1)*sizeof(char));
                                    if(buffer!=NULL)strcat(buffer,"\n\r");
                                    else
                                    {
                                            printf("-6-\n");
                                            free(buffer);
                                            buffer=NULL;
                                            return NULL;
                                    }
                            }
                    }
                    mysql_free_result(dbResult);
            }
            return &buffer[0];
    }
    


  • folgendes:

    free(str); //free() war schon da...
    str=NULL; //diese Zeile hab ich neu eingefügt.
    

    (in der Communicate()-Funktion)

    hat die Lösung gebracht. Ich verstehe aber nicht ganz warum sich das auf die Speicherreservierung in GetArzt() auswirkt. Wenn ich in GetArzt() mit char* buffer... im Heap Speicher reserviere, ist es doch egal, ob "str" in Communicate noch auf nicht mehr reservierten Speicher im Heap zeigt oder ob es explicit NULL gesetzt worden ist, oder nicht?

    Bitte erklärt mir! 🙂

    david.



  • kann es sein, dass du vielleicht 2 mal free aufrufst für die Variable? Deswegen hat das str=NULL; das Problem gelöst.

    Naja, den Code guck ich mir eh nicht durch, da der mir zu lang ist, für einen Foren Beitrag 🙄



  • Kann es sein das beim ersten Durchlauf der for-schleife in "Communicate"
    str ein undefinierter Zustand hat?



  • ja...beim ersten Durchlauf der for-Schleife hat ist *str nur ein Zeiger auf eine Speicheradresse. Hab aber auch schon "char *str=(char *)malloc(0);" probiert gehabt mit keinem anderen Ergebnis.
    Macht das denn einen Unterschied? Bzw. muss die Variable schon irgendwie in den Heap zeigen (durch Zuweisung von malloc z.B.) damit man ihr die Addresse eines Speicherbereichs im Heap zuweisen kann? Aber bei der 1. initialisierung einer Variablen mit malloc() ist das doch dann auch nicht anders...



  • @kingruedi:
    ich rufe free() für jeden schleifenaufruf in Communicate() genau einmal auf und zwar am Anfang , weil ich dannach ja das, was da noch von einem evtl. vorherigen Aufruf stehen könnte, nicht mehr brauche und somit wieder freigeben kann. Ist es denn problematisch, free() zweimal hintereinander aufzurufen? Hab in der Funktionsbschreibung nichts derartiges gefunden.

    Vielleicht sollte ich noch erwähnen, dass ich das unter Windows mache.


Log in to reply