여러 플랫폼에서 snprintf와 C++의 매우 이상한 동작이 있음을 알았습니다. 다음 코드 (관찰 된 동작을 일으키는 최소의 작업 예)를 고려하십시오예기치 않은 snprintf 동작
#include <stdio.h>
char test1[512];
char test2[512];
char test3[1024];
char test4[1024];
int main()
{
snprintf(test1, sizeof(test1), "test1");
snprintf(test2, sizeof(test2), "test2");
snprintf(test3, sizeof(test3), "%s %s", test1, test2);
return 0;
}
= EXP-sgcheck, 다음과 같은 오류가 (3 현재 snprintf 문에 대해)보고 --tool와 Valgrind의 비록 실행 :
==30302== Invalid read of size 1
==30302== at 0x568E4EB: vfprintf (in /lib64/libc-2.19.so)
==30302== by 0x56B7608: vsnprintf (in /lib64/libc-2.19.so)
==30302== by 0x5695209: snprintf (in /lib64/libc-2.19.so)
==30302== by 0x4006AD: main (1.cc:12)
==30302== Address 0x601460 expected vs actual:
==30302== Expected: global array "test1" of size 1,024 in object with soname "NONE"
==30302== Actual: global array "test2" of size 512 in object with soname "NONE"
==30302== Actual: is 0 after Expected
따라서 첫 번째 % s에 대한 인수로 test1을 전달하면 test1 배열의 끝에서 읽기가 발생합니다.
이 동작으로 인해 Windows 드라이버에서 여러 페이지 폴트가 발생했습니다 (예 : 정적 데이터라는 것을 알고 있습니다 ...). 다행히도이 코드는 이식성이 뛰어나며, valgrind가 리눅스로 이식되었을 때 그 오류를보고했다.
하지만 제 지식에 따르면 snprintf는 6 번째 바이트에서 \ 0으로 test1을 종료해야합니다. 그렇다면 왜 test1 배열의 끝에서 세 번째 snprintf 문을 읽게됩니까? 세 번째 snprintf 문을
snprintf(test3, sizeof(test3), "%.512s %s", test1, test2);
으로 변경하면 두 플랫폼 모두에서 문제가 해결됩니다. C 코드 (C++이 아님)로 코드를 컴파일하면 오류가 발생하지 않습니다.
업데이트 : 디버그 정보가 포함 된 코드와 최적화가 비활성화되어 있으면 (gcc의 경우 -g -O0) Linux에서만 오류가 발생합니다.
이 경우에는 차이가 있지만, 소스 파일 이름은 valgrind 출력에서'1.cc'로 호출됩니다. C를 작성하고 C++ 컴파일러로 컴파일하는 이유가 있습니까? – Blrfl
'valgrind --tool = exp-sgcheck'로 여러분의 코드를 테스트했지만 오류가보고되지 않았습니까?'valgrind'의 버전과'glibc'의 버전은 무엇입니까? 또한 리눅스 배포판은 무엇입니까? –
조금 더 말씀해 주시겠습니까? 예 : 플랫폼, 컴파일러 버전, 코드 컴파일 방법. – nos