memset () вызывает прерывание данных - PullRequest
4 голосов
/ 22 августа 2008

Я получаю некоторые странные прерывистые прерывания данных (<5% времени) в некоторых моих кодах при вызове <code>memset(). Проблема в том, что обычно этого не происходит, если код не выполняется в течение пары дней, поэтому его трудно уловить.

Я использую следующий код:

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

Как видите, я не пытаюсь использовать memset с размером, большим, чем тот, который изначально выделен для malloc()

Кто-нибудь видит, что может быть не так с этим?

Ответы [ 10 ]

21 голосов
/ 22 августа 2008

malloc может вернуть NULL, если нет доступной памяти. Вы не проверяете это.

4 голосов
/ 22 августа 2008

Есть пара вещей. Вы используете sprintf, что небезопасно; если вы не уверены на 100%, что не собираетесь превышать размер буфера, вы должны почти всегда предпочитать snprintf. То же относится и к strcat; предпочитаю более безопасную альтернативу strncat.

Очевидно, что это может ничего не исправить, но это длинный способ помочь обнаружить то, что в противном случае могло бы быть очень раздражающим, чтобы обнаружить ошибки.

3 голосов
/ 22 августа 2008

malloc может вернуть NULL, если нет памяти имеется в наличии. Вы не проверяете что.

Правильно, ты ... Я не думал об этом, поскольку я следил за памятью, и там было достаточно свободного места. Есть ли способ, чтобы в системе была доступная память, но для malloc не получилось?

Да, если память фрагментирована. Кроме того, когда вы говорите «мониторинг памяти», в системе может быть что-то, что иногда занимает много памяти, а затем освобождает ее, прежде чем вы заметите. Если ваш звонок на malloc произойдет, памяти не будет. - Джоэл

В любом случае ... Я добавлю эту проверку:)

1 голос
/ 22 августа 2008

wcstombs не получает размер места назначения, поэтому теоретически может переполнить буфер.

И почему вы используете sprintf с тем, что я предполагаю, являются константами? Просто используйте:

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

C и C ++ объединяют объявления строковых литералов в одну строку.

0 голосов
/ 24 сентября 2008

NB позаимствовал некоторые комментарии из других ответов и интегрировал в единое целое. Код весь мой ...

  • Проверьте ваши коды ошибок. Например. malloc может вернуть NULL, если нет доступной памяти. Это может быть причиной сброса данных.
  • sizeof (char) равно 1 по определению
  • Используйте snprintf, а не sprintf, чтобы избежать переполнения буфера
    • Если EZMPPOST и т. Д. Являются константами, вам не нужна строка формата, вы можете просто объединить несколько строковых литералов как STRING1 "" STRING2 "" STRING3 и strcat целиком.
  • Вы используете гораздо больше памяти, чем нужно.
  • С одним небольшим изменением вам не нужно сначала вызывать memset. Ничего такого здесь действительно требуется нулевая инициализация.

Этот код делает то же самое, безопасно, работает быстрее и использует меньше памяти.

    // 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);
0 голосов
/ 20 сентября 2008

Вместо malloc с последующим memset, вы должны использовать calloc, который очистит вновь выделенную память для вас. Кроме этого, делай то, что сказал Джоэл.

0 голосов
/ 20 сентября 2008

Это может быть ваш процессор. Некоторые процессоры не могут адресовать отдельные байты и требуют, чтобы вы работали в словах или размерах блоков, или имеют инструкции, которые можно использовать только для данных, выровненных по словам или фрагментам.

Обычно компилятор узнает об этом и работает вокруг них, но иногда вы можете присвоить региону байты, а затем попытаться адресовать его как структуру или поле размером больше байта, и компилятор победит не поймать это, но процессор будет выдавать исключение данных позже.

Этого не произойдет, если вы не используете необычный процессор. Например, ARM9 сделает это, а i686 - нет. Я вижу, что он помечен Windows Mobile, поэтому, возможно, у вас есть проблема с процессором.

0 голосов
/ 22 августа 2008

Вы знаете, что это может быть даже не ваш код ... Есть ли другие программы, которые могут иметь утечку памяти?

0 голосов
/ 22 августа 2008

Вы используете sprintf, который небезопасно; если вы не на 100% положительно, что вы не собираетесь превышать размер буфера, вы должен почти всегда предпочитать snprintf. То же относится и к strcat; предпочитаю более безопасная альтернатива strncat.

Да ..... В основном, в последнее время я делаю .NET, и старые привычки сильно умирают. Я, вероятно, вытащил этот код из чего-то еще, что было написано до моего времени ...

Но я постараюсь не использовать их в будущем;)

0 голосов
/ 22 августа 2008

Вы пробовали использовать Valgrind? Обычно это самый быстрый и простой способ устранения ошибок такого рода. Если вы читаете или пишете за пределами выделенной памяти, это пометит это для вас.

...