Domanda

Ricevo alcune strane interruzioni intermittenti dei dati (< 5% delle volte) in alcuni codici quando chiamo memset().Il problema è che di solito ciò non accade a meno che il codice non venga eseguito per un paio di giorni, quindi è difficile coglierlo sul fatto.

Sto usando il seguente codice:

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);

Come puoi vedere, non sto cercando di utilizzare memset con una dimensione maggiore di quella originariamente allocata malloc()

Qualcuno ha visto cosa potrebbe esserci di sbagliato in questo?

È stato utile?

Soluzione

malloc può ritornare NULL se non è disponibile memoria.Non lo stai controllando.

Altri suggerimenti

Ci sono un paio di cose.Stai usando sprintf che è intrinsecamente pericoloso;a meno che tu non sia sicuro al 100% di non superare la dimensione del buffer, dovresti quasi Sempre preferire snprintf.Lo stesso vale per strcat;preferire l'alternativa più sicura strncat.

Ovviamente questo potrebbe non risolvere nulla, ma va bene lungo modo per aiutare a individuare ciò che altrimenti potrebbe essere molto fastidioso individuare i bug.

Malloc può restituire null se non è disponibile alcuna memoria.Non lo stai verificando.

Hai ragione...Non ci ho pensato mentre stavo monitorando la memoria e ce n'era abbastanza libera.Esiste un modo per avere memoria disponibile sul sistema ma che malloc fallisca?

Sì, se la memoria è frammentata.Inoltre, quando dici "monitoraggio della memoria", potrebbe esserci qualcosa nel sistema che occasionalmente consuma molta memoria e quindi la rilascia prima che tu te ne accorga.Se la tua chiamata a malloc si verifica, non ci sarà memoria disponibile.-- Gioele

In ogni caso... aggiungerò quel controllo :)

wcstombs non ottiene la dimensione della destinazione, quindi può, in teoria, buffer overflow.

E perché lo stai usando sprintf con quello che presumo siano costanti?Basta usare:

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

C e C++ combinano dichiarazioni di valori letterali di stringa in un'unica stringa.

Hai provato ad usare Valgrind?Di solito questo è il modo più semplice e veloce per eseguire il debug di questo tipo di errori.Se stai leggendo o scrivendo al di fuori dei limiti della memoria allocata, te lo segnalerà.

Stai usando Sprintf che è intrinsecamente non sicuro;A meno che tu non sia positivo al 100% di non superare le dimensioni del buffer, dovresti quasi sempre preferire Snprintf.Lo stesso vale per strcat;Preferisci il più sicuro alternativo strncat.

Sì.....Ultimamente utilizzo principalmente .NET e le vecchie abitudini sono dure a morire.Probabilmente ho estratto quel codice da qualcos'altro che è stato scritto prima del mio tempo...

Ma cercherò di non usarli in futuro ;)

Sai che potrebbe non essere nemmeno il tuo codice...Ci sono altri programmi in esecuzione che potrebbero avere una perdita di memoria?

Potrebbe essere il tuo processore.Alcune CPU non possono indirizzare singoli byte e richiedono di lavorare in parole o dimensioni di blocchi o di avere istruzioni che possono essere utilizzate solo su dati allineati a parole o blocchi.

Di solito il compilatore ne è consapevole e lavora attorno ad essi, ma a volte puoi eseguire il malloc di una regione come byte e quindi provare a indirizzarla come una struttura o un campo più largo di un byte e il compilatore non lo rileverà , ma il processore genererà un'eccezione di dati in seguito.

Ciò non accadrebbe a meno che non si utilizzi una CPU insolita.ARM9 lo farà, ad esempio, ma i686 no.Vedo che è contrassegnato con Windows Mobile, quindi forse hai questo problema con la CPU.

Invece di fare malloc seguito da memset, dovresti usare calloc che cancellerà la memoria appena allocata per te.A parte questo, fai quello che ha detto Joel.

NB ha preso in prestito alcuni commenti da altre risposte e li ha integrati nel loro insieme.Il codice è tutto mio...

  • Controlla i codici di errore.Per esempio.malloc può restituire NULL se non è disponibile memoria.Ciò potrebbe causare l'interruzione dei dati.
  • sizeof(char) è 1 per definizione
  • Utilizzare snprintf e non sprintf per evitare sovraccarichi del buffer
    • Se EZMPPOST ecc. sono costanti, non è necessaria una stringa di formato, puoi semplicemente combinare diversi valori letterali di stringa come STRING1 " " STRING2 " " STRING3 e strcat il tutto.
  • Stai utilizzando molta più memoria del necessario.
  • Con una piccola modifica, non è necessario chiamare memset in primo luogo.Niente richiede davvero zero inizializzazione qui.

Questo codice fa la stessa cosa, in modo sicuro, viene eseguito più velocemente e utilizza meno memoria.

    // 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);
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top