문제

호출할 때 일부 코드에서 이상하고 간헐적인 데이터 중단(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()

누구든지 이것에 무엇이 문제가 있는지 알 수 있습니까?

도움이 되었습니까?

해결책

malloc 돌아올 수 있다 NULL 사용할 수 있는 메모리가 없는 경우.당신은 그것을 확인하지 않습니다.

다른 팁

몇 가지가 있습니다.당신은 사용하고 있습니다 sprintf 이는 본질적으로 안전하지 않습니다.버퍼 크기를 초과하지 않을 것이라고 100% 확신하지 않는 한 거의 언제나 선호하다 snprintf.동일하게 적용됩니다 strcat;더 안전한 대안을 선호하다 strncat.

분명히 이것은 아무것도 해결하지 못할 수도 있지만 버그를 발견하는 데 매우 짜증나는 일을 발견하는 데 도움이 되는 방법입니다.

메모리를 사용할 수없는 경우 Malloc은 NULL을 반환 할 수 있습니다.당신은 그것을 확인하지 않습니다.

그렇죠 당신은...메모리를 모니터링하고 있는데 여유 공간이 충분해서 그런 생각은 하지 못했습니다.시스템에 사용 가능한 메모리가 있지만 malloc이 실패할 수 있는 방법이 있습니까?

예, 메모리가 단편화된 경우입니다.또한 "메모리 모니터링"이라고 하면 시스템에 가끔 많은 메모리를 소비하다가 알아차리기 전에 해제하는 무언가가 있을 수 있습니다.귀하의 전화가 malloc 그러면 사용 가능한 메모리가 없게 됩니다.-- 조엘

어느 쪽이든... 해당 수표를 추가하겠습니다 :)

wcstombs 대상의 크기를 얻지 못하므로 이론적으로 버퍼 오버플로가 발생할 수 있습니다.

그리고 왜 사용하고 있나요? sprintf 내가 상수라고 가정하는 것은 무엇입니까?그냥 사용:

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

C 및 C++에서는 문자열 리터럴 선언을 단일 문자열로 결합합니다.

Valgrind를 사용해 보셨나요?이는 일반적으로 이러한 종류의 오류를 디버깅하는 가장 빠르고 쉬운 방법입니다.할당된 메모리 범위 밖에서 읽거나 쓰는 경우 플래그가 지정됩니다.

본질적으로 안전하지 않은 Sprintf를 사용하고 있습니다.버퍼의 크기를 초과하지 않을 것이라는 100% 양수가 아니라면 거의 항상 snprintf를 선호해야합니다.strcat에도 동일하게 적용됩니다.더 안전한 대체 strncat을 선호하십시오.

응.....요즘에는 주로 .NET을 사용하는데 오래된 습관은 쉽게 사라지지 않습니다.그 코드는 내가 살기 전에 작성된 다른 코드에서 가져온 것 같습니다...

하지만 앞으로는 그런 것들을 사용하지 않으려고 노력하겠습니다 ;)

당신의 코드가 아닐 수도 있다는 것을 알고 있습니다 ...메모리 누수가 발생할 수 있는 다른 프로그램이 실행되고 있습니까?

귀하의 프로세서가 될 수 있습니다.일부 CPU는 단일 바이트를 처리할 수 없으며 단어 또는 청크 크기로 작업해야 하거나 단어 또는 청크 정렬 데이터에만 사용할 수 있는 명령이 있어야 합니다.

일반적으로 컴파일러는 이를 인식하고 주변에서 작동하지만 때로는 영역을 바이트로 malloc한 다음 이를 구조 또는 바이트보다 넓은 필드로 처리하려고 시도하면 컴파일러가 이를 포착하지 못합니다. , 그러나 프로세서는 나중에 데이터 예외를 발생시킵니다.

특이한 CPU를 사용하지 않는 한 이런 일은 일어나지 않을 것입니다.예를 들어 ARM9는 그렇게 하지만 i686은 그렇지 않습니다.Windows Mobile이라는 태그가 붙은 것을 보니 CPU 문제가 있을 수도 있습니다.

하는 대신 malloc 이어서 memset, 당신은 사용해야합니다 calloc 그러면 새로 할당된 메모리가 지워집니다.그 외에는 조엘이 말한 대로 하세요.

NB는 다른 답변에서 일부 의견을 빌려 전체로 통합했습니다.코드는 다 내꺼야...

  • 오류 코드를 확인하세요.예:malloc은 사용 가능한 메모리가 없으면 NULL을 반환할 수 있습니다.이로 인해 데이터가 중단될 수 있습니다.
  • sizeof(char)는 정의상 1입니다.
  • 버퍼 오버런을 방지하려면 sprintf가 아닌 snprintf를 사용하세요.
    • 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);
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top