2013-08-30 2 views
6

strncat의 Microsoft 구현과 관련된 흥미로운 문제점을 발견했습니다. 그것은 소스 버퍼를 1 바이트 넘어 닿는다. 다음 코드를 고려Microsoft의 strncat이 소스 버퍼 경계를 넘어 바이트를 읽음

#include <stdio.h> 
#include <stdlib.h> 
#include <memory.h> 
#include <string.h> 

void main() 
{ 
    char dstBuf[1024]; 
    char* src = malloc(112); 
    memset(src, 'a', 112); 
    dstBuf[0] = 0; 
    strncat(dstBuf, src, 112); 
} 

strncat 1 바이트 후의 112 바이트의 블록을 판독한다. 따라서 잘못된 페이지 경계에 할당 할만큼 운이 없다면 응용 프로그램이 충돌합니다. 대형 응용 프로그램은 이러한 장소에서 일시적으로 중단 될 수 있습니다. (이러한 조건 GFLAGS에 pageheap 설정하여 시뮬레이션 될 수 있음에 유의 블록 크기 적절한 정렬 포인터 크기로 나눌 수 있습니다.)

이 예상 된 동작이나 버그? 그걸 확인하는 어떤 링크?

업데이트 (증거에 대한 질문에 대답) (... 나는 strncat의 몇 가지 설명을 읽을 수 있지만 그들은 마음의 초기 설정에 따라 두 가지 방법으로 해석 될 수있다) : 나는 그것이 분명하지 않은 경우 사과 위의 텍스트이지만 실험적인 사실입니다. strncat 주소 src + srcBufSize에서 애플리케이션의 간헐적 인 충돌이 발생합니다. 이 작은 예제에서는 과 함께 gflags PageHeap 충돌시 일관되게 (100 %) 재생산합니다. 그래서 내가 볼 수있는 한, 증거는 매우 견고합니다.

업데이트 2 (컴파일러 정보) MS Visual Studio 2005 버전 8.0.50727.867. 빌드 플랫폼 : 64 비트 릴리스 (32 비트의 경우 repro 없음). 충돌을 재현하는 데 사용되는 OS : Windows Server 2008 R2.

업데이트 3 문제는 MS 비주얼 스튜디오에 내장 된 바이너리로 재현 2012 11.0.50727.1

업데이트 4Link to issue on Microsoft Connect; link to discussion on MSDN Forums

업데이트 5 문제는 다음 VS 릴리스에서 수정 될 예정입니다. 이전 버전에 대한 수정은 계획되어 있지 않습니다. 위의 "Microsoft Connect"링크를 참조하십시오.

+0

는이 주장에 대한 증거가 무엇입니까? – EJP

+0

에게 아이디어를 :'memcpy()' – Dariusz

+0

나는 사랑한다. 이런 식으로 행동하는 바이너리를보십시오. 또한, 어떤 버전의 컴파일러/라이브러리를 사용하고 있습니까? –

답변

3

documentation for strncat 상태 :

SRC - 널 종료 바이트 문자열에 대한 포인터 따라서, 구현이 src 입력 매개 변수가 사실 NUL 있다고 가정 할 수

복사하기 심지어는 count 자보다 길어도 끝나야합니다. 더 확인

, Microsoft's own documentation 상태 :

strSource

널 종료 소스 문자열.한편

, 같은 actual C standard 상태 뭔가 :

strncat 기능 이상 n 문자 (null 문자과이 추가되지 않습니다 따라 문자)으로부터되지 추가 배열 에 의해 의 끝에 가리키는 문자열 s1에 의해 지적했다.

바와 같이 이것은 배열 아닌 NUL 종료 문자열로 제 s2 파라미터를 식별하고, 아래에 주석을 지적했다. 그러나이 문서는 s2에서 읽을 때 함수의 동작보다는 s1의 궁극적 인 영향을 설명하기 때문에 원래 질문과 관련하여 여전히 모호합니다.

물론 이것은 특정 C 런타임 라이브러리 소스 코드를 참조하여 Microsoft에서 구현할 수 있습니다.

+1

내가 이것을 사는지 확실하지 않습니다. "** strncat ** 함수는 strSource *에서 * strDest *까지의 첫 번째 * 카운트 * 문자를 추가합니다." –

+2

@JonathonReinhart : 결과 * 동작 *이지만 입력 된 'src'문자열은 그럼에도 불구하고 null로 종료 될 것으로 예상됩니다. –

+0

@JonathonReinhart - 당신이 무엇을 기대 하는가에 대한 연결을 수행하기 위해 null이 아닌 종료 문자열을 제공한다면? 이 대답은 완벽합니다 –

1

영어는 더욱 그렇다 C.

보다

문서는 (내 강조) "가장 n 개의 문자로"라고, 불완전한 언어입니다. strncat이 112 문자 이상을 복사한다는 증거는 없습니다. 당신이 믿는 이유는 무엇입니까?

strncat의 코드는 오프셋 112를 넘어 인덱스 할 수 있지만 실제로 스토리지 오프셋을 일으킬 수있는 오프셋 113을 참조하지는 않습니다. 이 PTR 동작은 K & R.

마지막으로, 다시이 영어/추론 문제가, 문서 아마 말하는가 널 종료 문자열에 허용으로 정의된다. 하지만 실제로, 문자열이 null로 종료되었다고 말하는 것이 중복되지 않습니까? 그것들은 정의에 의한 것이고, 그렇지 않으면 문자의 배열이됩니다. 따라서 문서가 모호하고 비특이적입니다. 프로그래머는 줄 사이를 읽어야합니다. 소프트웨어 문서는 법적 문서가 아니며, 기술 분야에서 숙련 된 사람이 이해할 수있는 설명입니다.

+0

_ 소프트웨어 문서는 합법적 인 것이 아닙니다 _ ←하지만 표준은 실제로는 법적인 형식입니다. C 표준은 소스 인수를 배열로 취급합니다. 'strn *'함수는 _fixed size records_와 함께 작동하도록 설계되었으므로, 마치 주제가 문자열 일 때와 똑같이 동작하지 않습니다. – ninjalj

+0

@ninjalj, 나는 그들이 당신이 고정 된 크기의 레코드이고 n이 그 레코드의 길이를 결정한다는 것에 동의한다. C는 배열 끝을지나 1을 가리 키도록 허용/정의됩니다. 그래서 for (etc; i ++)가 작동합니다! – JackCColeman

2

s2strncat(s1, s2, n)하지은 "문자열"입니다.

Microsoft가 패스 n 바이트를 읽는 중이라면 C11과 호환되지 않습니다.

C11 7.24.2.3.1 strcat()
는 "S1 가리키는 문자열의 끝 (널 종료 문자를 포함 함)는 S2 가리키는 문자열의 복사본을 추가"언급한다.

C11 7.24.2.3.2 strncat
는 "함수 역시 함수의 끝에 (S2)에 의해
가 가리키는 배열에서 더 많은 n 자보다 (이 추가되지 않습니다에 따라 널 문자와 문자를)하지 추가 말한다 s1이 가리키는 문자열. ...널 종료 문자 항상 결과에 추가되는 "분명 strncat 경우

, s2는 것으로 간주된다"s1에 부가되는 정도에 캐릭터와 같은 제약이 어레이 ". 따라서, 연결 동안이다 필요가 절대적으로 필요한 것보다 s2 더 많은 검사가 없습니다. 최종 작성 \0는 코드에서 제공하지 s2.

이전 C99 표준에 대해 알고하지 마십시오.