Сведения о вопросе

Electro Full

10:28, 12th August, 2020

Теги

c++   c   memory   windows-mobile    

memset() причина прерывания передачи данных

Просмотров: 450   Ответов: 10

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

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



  Сведения об ответе

DINO

07:44, 26th August, 2020

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


  Сведения об ответе

pumpa

22:39, 25th August, 2020

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

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


  Сведения об ответе

prince

00:14, 2nd August, 2020

malloc может вернуть NULL, если память отсутствует доступный. Ты же не проверяешь его на наличие тот.

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

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

Либо way...I добавлю, что проверить :)


  Сведения об ответе

piter

01:22, 7th August, 2020

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

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

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

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


  Сведения об ответе

SILA

12:11, 4th August, 2020

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


  Сведения об ответе

lats

07:36, 5th August, 2020

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

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

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


  Сведения об ответе

SILA

05:44, 17th August, 2020

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


  Сведения об ответе

+-*/

09:48, 28th August, 2020

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

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

Это не произойдет, если вы не используете необычный CPU. Обработчик ARM9 будет этого делать, например, но i686 в не. Я вижу, что он помечен windows мобильного, так что, возможно, у вас есть эта проблема CPU.


  Сведения об ответе

crush

15:06, 20th August, 2020

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


  Сведения об ответе

ЯЯ__4

17:37, 6th August, 2020

НБ заимствовал некоторые комментарии из других ответов и интегрировал их в единое целое. Этот код полностью принадлежит мне...

  • Проверьте свои коды ошибок. E.g. 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);


Ответить на вопрос

Чтобы ответить на вопрос вам нужно войти в систему или зарегистрироваться