Frage

Beim Aufrufen kommt es in einigen Teilen meines Codes zu seltsamen, zeitweiligen Datenabbrüchen (< 5 % der Zeit). memset().Das Problem besteht darin, dass dies normalerweise nicht geschieht, es sei denn, der Code läuft ein paar Tage lang, sodass es schwierig ist, ihn auf frischer Tat zu ertappen.

Ich verwende den folgenden Code:

char *msg = (char*)malloc(sizeof(char)*2048);
char *temp = (char*)malloc(sizeof(char)*1024);
memset(msg, 0, 2048);
memset(temp, 0, 1024);
char *tempstr = (char*)malloc(sizeof(char)*128);

sprintf(temp, "%s %s/%s %s%s", EZMPPOST, EZMPTAG, EZMPVER, TYPETXT, EOL);
strcat(msg, temp);

//Add Data
memset(tempstr, '\0', 128);
wcstombs(tempstr, gdevID, wcslen(gdevID));
sprintf(temp, "%s: %s%s", "DeviceID", tempstr, EOL);
strcat(msg, temp);

Wie Sie sehen, versuche ich nicht, Memset mit einer Größe zu verwenden, die größer ist als ursprünglich zugewiesen malloc()

Kann jemand sehen, was daran falsch sein könnte?

War es hilfreich?

Lösung

malloc kann zurückkehren NULL wenn kein Speicher verfügbar ist.Das überprüfen Sie nicht.

Andere Tipps

Es gibt ein paar Dinge.Du verwendest sprintf was von Natur aus unsicher ist;Sofern Sie nicht zu 100 % sicher sind, dass Sie die Größe des Puffers nicht überschreiten werden, sollten Sie dies fast tun stets bevorzugen snprintf.Gleiches gilt für strcat;bevorzuge die sicherere Alternative strncat.

Offensichtlich wird dadurch möglicherweise nichts behoben, aber es funktioniert lang Dies trägt dazu bei, Fehler zu erkennen, die ansonsten sehr lästig wären.

Malloc kann Null zurückgeben, wenn kein Speicher verfügbar ist.Sie überprüfen nicht.

Du hast Recht...Darüber habe ich nicht nachgedacht, da ich den Speicher überwachte und feststellte, dass genügend frei war.Gibt es eine Möglichkeit, dass auf dem System Speicher verfügbar ist, Malloc jedoch fehlschlägt?

Ja, wenn der Speicher fragmentiert ist.Wenn Sie außerdem „Speicher überwachen“ sagen, gibt es möglicherweise etwas auf dem System, das gelegentlich viel Speicher verbraucht und ihn dann wieder freigibt, bevor Sie es bemerken.Wenn Sie anrufen malloc Tritt dann ein Fehler auf, ist kein Speicher mehr verfügbar.-- Joel

So oder so ... ich werde diesen Scheck hinzufügen :)

wcstombs erhält nicht die Größe des Ziels, daher kann es theoretisch zu einem Pufferüberlauf kommen.

Und warum verwenden Sie sprintf mit dem, was ich annehme, sind Konstanten?Benutz einfach:

EZMPPOST" " EZMPTAG "/" EZMPVER " " TYPETXT EOL

C und C++ kombinieren String-Literal-Deklarationen in einem einzigen String.

Haben Sie versucht, Valgrind zu verwenden?Dies ist normalerweise der schnellste und einfachste Weg, diese Art von Fehlern zu beheben.Wenn Sie außerhalb der Grenzen des zugewiesenen Speichers lesen oder schreiben, wird dies für Sie gekennzeichnet.

Sie verwenden Sprintf, das von Natur aus unsicher ist.Wenn Sie nicht zu 100% positiv sind, dass Sie die Größe des Puffers nicht überschreiten, sollten Sie SNPRINTF fast immer bevorzugen.Dasselbe gilt für strcat;Bevorzugen Sie die sicherere alternative Strncat.

Ja.....Ich arbeite in letzter Zeit hauptsächlich mit .NET und alte Gewohnheiten lassen sich nur schwer ablegen.Ich habe diesen Code wahrscheinlich aus etwas anderem entnommen, das vor meiner Zeit geschrieben wurde ...

Aber ich werde versuchen, diese in Zukunft nicht mehr zu verwenden ;)

Sie wissen, dass es möglicherweise nicht einmal Ihr Code ist ...Laufen noch andere Programme, bei denen ein Speicherverlust auftreten könnte?

Es könnte Ihr Prozessor sein.Einige CPUs können keine einzelnen Bytes adressieren und erfordern die Arbeit in Wörtern oder Blockgrößen oder verfügen über Anweisungen, die nur für wort- oder blockausgerichtete Daten verwendet werden können.

Normalerweise wird der Compiler darauf aufmerksam gemacht und umgeht sie, aber manchmal können Sie einen Bereich als Bytes mallocieren und dann versuchen, ihn als Struktur oder ein Feld zu adressieren, das breiter als ein Byte ist, und der Compiler wird ihn nicht erkennen , aber der Prozessor löst später eine Datenausnahme aus.

Dies würde nicht passieren, es sei denn, Sie verwenden eine ungewöhnliche CPU.ARM9 wird das zum Beispiel tun, i686 jedoch nicht.Ich sehe, dass es mit „Windows Mobile“ gekennzeichnet ist. Vielleicht haben Sie also dieses CPU-Problem.

Anstatt es zu tun malloc gefolgt von memset, sollten Sie verwenden calloc Dadurch wird der neu zugewiesene Speicher für Sie gelöscht.Ansonsten tun Sie, was Joel gesagt hat.

NB hat einige Kommentare aus anderen Antworten übernommen und in ein Ganzes integriert.Der Code gehört mir...

  • Überprüfen Sie Ihre Fehlercodes.Z.B.malloc kann NULL zurückgeben, wenn kein Speicher verfügbar ist.Dies könnte zu einem Datenabbruch führen.
  • sizeof(char) ist per Definition 1
  • Verwenden Sie snprintf und nicht sprintf, um Pufferüberläufe zu vermeiden
    • Wenn EZMPPOST usw. Konstanten sind, benötigen Sie keine Formatzeichenfolge. Sie können einfach mehrere Zeichenfolgenliterale als STRING1 " " STRING2 " " STRING3 kombinieren und das Ganze strcaten.
  • Sie verbrauchen viel mehr Speicher als nötig.
  • Mit einer kleinen Änderung müssen Sie memset gar nicht erst aufrufen.Nichts erfordert hier keine Initialisierung von Null.

Dieser Code macht das Gleiche: sicher, läuft schneller und verbraucht weniger Speicher.

    // sizeof(char) is 1 by definition. This memory does not require zero
    // initialisation. If it did, I'd use calloc.
    const int max_msg = 2048;
    char *msg     = (char*)malloc(max_msg);
    if(!msg)
    {
       // Allocaton failure
       return;
    }
    // Use snprintf instead of sprintf to avoid buffer overruns
    // we write directly to msg, instead of using a temporary buffer and then calling
    // strcat. This saves CPU time, saves the temporary buffer, and removes the need
    // to zero initialise msg.
    snprintf(msg, max_msg, "%s %s/%s %s%s", EZMPPOST, EZMPTAG, EZMPVER, TYPETXT, EOL);

   //Add Data
   size_t len = wcslen(gdevID);
   // No need to zero init this
   char* temp = (char*)malloc(len);
   if(!temp)
   {
      free(msg);
      return;
   }
   wcstombs(temp, gdevID, len);
   // No need to use a temporary buffer - just append directly to the msg, protecting 
   // against buffer overruns.
   snprintf(msg + strlen(msg), 
           max_msg - strlen(msg), "%s: %s%s", "DeviceID", temp, EOL);
   free(temp);
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top