Question

Je reçois des abandons de données étranges et intermittents (<5 % du temps) dans certains de mes codes, lors de l'appel memset().Le problème est que cela ne se produit généralement que si le code est exécuté pendant quelques jours, il est donc difficile de le prendre en flagrant délit.

J'utilise le code suivant :

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

Comme vous pouvez le voir, je n'essaie pas d'utiliser un memset avec une taille supérieure à celle initialement allouée avec malloc()

Quelqu'un voit ce qui ne va pas avec ça ?

Était-ce utile?

La solution

malloc peut revenir NULL si aucune mémoire n'est disponible.Vous ne vérifiez pas cela.

Autres conseils

Il y a plusieurs choses.Vous utilisez sprintf ce qui est intrinsèquement dangereux ;à moins que vous ne soyez sûr à 100 % que vous n'allez pas dépasser la taille du tampon, vous devriez presque toujours préférer snprintf.de même pour strcat;préférez l'alternative la plus sûre strncat.

Évidemment, cela ne résoudra peut-être rien, mais cela long moyen d'aider à repérer ce qui pourrait autrement être très ennuyeux pour repérer les bugs.

Malloc peut retourner null si aucune mémoire n'est disponible.Vous ne vérifiez pas cela.

Tu as raison...Je n'y ai pas pensé car je surveillais la mémoire et il y avait suffisamment de libre.Existe-t-il un moyen d'avoir de la mémoire disponible sur le système mais que malloc échoue ?

Oui, si la mémoire est fragmentée.De plus, lorsque vous parlez de « surveillance de la mémoire », il se peut qu'il y ait quelque chose sur le système qui consomme occasionnellement beaucoup de mémoire et la libère ensuite avant que vous ne vous en rendiez compte.Si votre appel à malloc se produit alors, il n'y aura plus de mémoire disponible.-- Joël

Quoi qu'il en soit... j'ajouterai ce chèque :)

wcstombs n'obtient pas la taille de la destination, il peut donc, en théorie, déborder de la mémoire tampon.

Et pourquoi utilisez-vous sprintf avec ce que je suppose être des constantes ?Utilisez simplement :

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

C et C++ combinent les déclarations littérales de chaîne en une seule chaîne.

Avez-vous essayé d'utiliser Valgrind ?C'est généralement le moyen le plus rapide et le plus simple de déboguer ce type d'erreurs.Si vous lisez ou écrivez en dehors des limites de la mémoire allouée, il le signalera pour vous.

Vous utilisez Sprintf qui est intrinsèquement dangereux;À moins que vous ne soyez à 100% positif que vous n'allez pas dépasser la taille du tampon, vous devriez presque toujours préférer SNPrintf.La même chose s'applique à strcat ;Préférez la strncat alternative la plus sûre.

Ouais.....Je fais principalement du .NET ces derniers temps et les vieilles habitudes ont la vie dure.J'ai probablement extrait ce code de quelque chose d'autre qui a été écrit avant mon arrivée...

Mais j'essaierai de ne pas les utiliser à l'avenir ;)

Vous savez que ce n'est peut-être même pas votre code...Existe-t-il d'autres programmes en cours d'exécution susceptibles de présenter une fuite de mémoire ?

Cela pourrait être votre processeur.Certains processeurs ne peuvent pas traiter des octets uniques et nécessitent que vous travailliez avec des mots ou des tailles de fragments, ou que vous ayez des instructions qui ne peuvent être utilisées que sur des données alignées sur des mots ou des fragments.

Habituellement, le compilateur en est informé et les contourne, mais parfois vous pouvez allouer une région sous forme d'octets, puis essayer de l'adresser comme une structure ou un champ plus large qu'un octet, et le compilateur ne l'attrapera pas. , mais le processeur lancera une exception de données plus tard.

Cela n'arriverait que si vous utilisiez un processeur inhabituel.ARM9 le fera, par exemple, mais pas i686.Je vois qu'il est étiqueté Windows Mobile, alors peut-être avez-vous ce problème de processeur.

Au lieu de faire malloc suivi de memset, vous devriez utiliser calloc ce qui effacera la mémoire nouvellement allouée pour vous.A part ça, faites ce que Joël a dit.

NB a emprunté certains commentaires à d'autres réponses et les a intégrés dans un tout.Le code est entièrement à moi...

  • Vérifiez vos codes d'erreur.Par exemple.malloc peut renvoyer NULL si aucune mémoire n'est disponible.Cela pourrait provoquer l’abandon de vos données.
  • sizeof(char) est 1 par définition
  • Utilisez snprintf et non sprintf pour éviter les dépassements de tampon
    • Si EZMPPOST, etc. sont des constantes, alors vous n'avez pas besoin d'une chaîne de format, vous pouvez simplement combiner plusieurs littéraux de chaîne comme STRING1 " " STRING2 " " STRING3 et strcat le tout.
  • Vous utilisez beaucoup plus de mémoire que nécessaire.
  • Avec un changement mineur, vous n'avez pas besoin d'appeler memset en premier lieu.Rien ne nécessite vraiment une initialisation zéro ici.

Ce code fait la même chose, en toute sécurité, s'exécute plus rapidement et utilise moins de mémoire.

    // 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);
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top