memset () вызывает прерывание данных

Я получаю некоторые странные прерывистые прерывания данных (<5% времени) в некоторых моих кодах при вызове 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()

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

22.08.2008 14:17:01
10 ОТВЕТОВ
РЕШЕНИЕ

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

21
22.08.2008 14:21:43
Также обратите внимание, что из-за оптимистичного распределения, это не потому, что maloc () возвращает ненулевое значение, что у вас достаточно памяти. Он потерпит неудачу при первом реальном доступе к памяти, которая будет здесь ... memset ().
Ben 24.07.2009 07:44:45
@Ben: Вы очень подходите для таких ОС, как настольный Linux. Но я сомневаюсь, что мобильные ОС, такие как Windows Mobile, обладают оптимистичным распределением. Это не имеет большого смысла в системе с ограниченной оперативной памятью и без виртуальной памяти.
Zan Lynx 21.09.2010 23:37:59

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

0
22.08.2008 14:18:58

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

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

4
22.08.2008 14:26:14
Нет, не используйте strncat. Он заполняет весь буфер. Это снижает производительность, если вы используете большой буфер. Он достиг вершины моего графика профилировщика в одном проекте, который использовал буфер 8 КБ для URL.
Zan Lynx 30.07.2009 03:40:34
@Zan Lynx: что является альтернативой strncat?
Cristian Ciupitu 21.09.2010 22:23:36
@Cristian: strlcat - один из вариантов. Возможно, вам придется скопировать код в ваш проект, хотя это не всегда в среде разработчиков. Отслеживание длины строки (или использование указателей для буферизации начала, текущей позиции и конца буфера) в источнике и в пункте назначения и использование memcpy - мой любимый метод.
Zan Lynx 21.09.2010 23:35:48
@Zan Lynx: strlcatможет быть лучше, чем strncatс семантической точки зрения, но я до сих пор не понимаю, как его производительность может быть лучше. В документе, в котором представлены strlcpy и strlcat, упоминается только strncpy: «Наконец, strncpy () обнуляет оставшуюся часть строки назначения, что приводит к снижению производительности». Кстати, моя strncatстраница руководства по Linux ничего не говорит о снижении производительности.
Cristian Ciupitu 22.09.2010 01:36:42
@ Кристиан: D'Oh. Просто сейчас, когда ты пишешь это, я вижу, что я имел в виду strncpy все время. Этого вам следует избегать, и мой предыдущий комментарий теперь глупый.
Zan Lynx 22.09.2010 01:40:11

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

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

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

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

3
22.08.2008 14:42:05

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

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

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

0
22.08.2008 14:28:36

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

0
22.08.2008 14:28:47

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

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

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

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

1
3.07.2012 15:02:03

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

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

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

0
20.09.2008 06:40:13

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

0
20.09.2008 06:46:06

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
24.07.2009 07:33:15