Pergunta

Estou recebendo alguns abortos de dados estranhos e intermitentes (<5% do tempo) em alguns dos meus códigos, ao chamar memset().O problema é que isso geralmente não acontece, a menos que o código esteja em execução por alguns dias, por isso é difícil detectá-lo em flagrante.

Estou usando o seguinte código:

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

Como você pode ver, não estou tentando usar o memset com um tamanho maior do que o originalmente alocado malloc()

Alguém vê o que pode estar errado com isso?

Foi útil?

Solução

malloc pode retornar NULL se não houver memória disponível.Você não está verificando isso.

Outras dicas

Há algumas coisas.Você está usando sprintf que é inerentemente inseguro;a menos que você tenha 100% de certeza de que não excederá o tamanho do buffer, você deve quase sempre prefiro snprintf.O mesmo se aplica a strcat;prefira a alternativa mais segura strncat.

Obviamente, isso pode não resolver nada, mas é um longo maneira de ajudar a detectar o que de outra forma poderia ser muito irritante para detectar bugs.

Malloc pode retornar nulo se nenhuma memória estiver disponível.Você não está verificando isso.

Certo você está...Não pensei nisso porque estava monitorando a memória e havia espaço suficiente.Existe alguma maneira de haver memória disponível no sistema, mas o malloc falhar?

Sim, se a memória estiver fragmentada.Além disso, quando você diz "monitorando memória", pode haver algo no sistema que ocasionalmente consome muita memória e a libera antes que você perceba.Se a sua chamada para malloc ocorrer então, não haverá memória disponível.-- Joel

De qualquer forma ... vou adicionar esse cheque :)

wcstombs não obtém o tamanho do destino, portanto pode, em teoria, estourar o buffer.

E por que você está usando sprintf com o que presumo serem constantes?Apenas use:

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

C e C++ combinam declarações literais de string em uma única string.

Você já tentou usar o Valgrind?Essa geralmente é a maneira mais rápida e fácil de depurar esse tipo de erro.Se você estiver lendo ou escrevendo fora dos limites da memória alocada, isso será sinalizado para você.

Você está usando o Sprintf, que é inerentemente inseguro;A menos que você esteja 100% positivo de que você não exceda o tamanho do buffer, quase sempre preferirá o SNPRINTF.O mesmo se aplica ao strcat;prefira o strncat alternativo mais seguro.

Sim.....Ultimamente, uso principalmente .NET e velhos hábitos são difíceis de morrer.Provavelmente retirei esse código de outra coisa que foi escrita antes do meu tempo ...

Mas tentarei não usá-los no futuro;)

Você sabe que pode nem ser o seu código ...Há algum outro programa em execução que possa ter vazamento de memória?

Pode ser o seu processador.Algumas CPUs não podem endereçar bytes únicos e exigem que você trabalhe em palavras ou tamanhos de blocos, ou tenham instruções que só podem ser usadas em dados alinhados por palavras ou blocos.

Normalmente, o compilador fica ciente disso e trabalha em torno deles, mas às vezes você pode fazer o malloc de uma região como bytes e, em seguida, tentar endereçá-la como uma estrutura ou um campo mais largo que um byte, e o compilador não irá capturá-la. , mas o processador lançará uma exceção de dados posteriormente.

Isso não aconteceria a menos que você estivesse usando uma CPU incomum.ARM9 fará isso, por exemplo, mas i686 não.Vejo que está marcado como Windows Mobile, então talvez você tenha esse problema de CPU.

Em vez de fazer malloc seguido pela memset, você deveria estar usando calloc o que limpará a memória recém-alocada para você.Fora isso, faça o que Joel disse.

NB pegou emprestados alguns comentários de outras respostas e integrou-os em um todo.O código é todo meu...

  • Verifique seus códigos de erro.Por exemplo.malloc pode retornar NULL se não houver memória disponível.Isso pode estar causando a interrupção dos seus dados.
  • sizeof(char) é 1 por definição
  • Use snprintf e não sprintf para evitar saturação de buffer
    • Se EZMPPOST etc são constantes, então você não precisa de uma string de formato, você pode apenas combinar vários literais de string como STRING1 " " STRING2 " " STRING3 e strcat o lote inteiro.
  • Você está usando muito mais memória do que precisa.
  • Com uma pequena alteração, você não precisa chamar o memset em primeiro lugar.Nada realmente requer zero inicialização aqui.

Esse código faz a mesma coisa, com segurança, roda mais rápido e usa menos memória.

    // 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);
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top