문제

아래 프로그램을 고려하십시오

    char str[5];
    strcpy(str,"Hello12345678");
    printf("%s",str);

이 프로그램을 실행할 때이 프로그램은 분할 결함을 제공합니다.

그러나 strcpy가 다음으로 교체되면 프로그램은 잘 실행됩니다.

strcpy(str,"Hello1234567");

따라서 질문은 5 숯이 넘는 다른 문자열에 복사하려고 할 때 충돌해야한다는 것입니다.

따라서 "hello1234567"에 충돌하지 않는 이유는 "hello12345678"의 길이 13 이상 13 이상의 문자열에만 충돌하는 이유.

이 프로그램은 32 비트 머신에서 실행되었습니다.

도움이 되었습니까?

해결책

관심을 가져야 할 표준 행동에는 세 가지 유형이 있습니다.

1/ 정의 된 행동. 이것은 모든 준수 구현에서 작동합니다. 이것을 자유롭게 사용하십시오.

2/ 구현 정의 된 동작. 언급 한 바와 같이, 그것은 구현에 따라 다르지만 적어도 여전히 정의되어 있습니다. 이 경우 구현이 필요합니다. 이식성에 관심이없는 경우 이것을 사용하십시오.

3/ 정의되지 않은 행동. 모든 것이 일어날 수 있습니다. 그리고 우리는 의미합니다 아무것, 전체 컴퓨터를 알몸의 특이점으로 무너지고 스스로 삼키는 것까지, 당신과 많은 비율의 노동자들. 이것을 사용하지 마십시오. 항상! 진지하게! 나를 저기로 오게하지 마세요.

4 자 이상과 제로 바이트를 char[5] 정의되지 않은 행동입니다.

진지하게, 당신의 프로그램이 14 자로 충돌하는지는 중요하지 않지만 13자가 아닌 것은 중요하지 않으며, 스택에 대한 몇 가지 비 이루어지는 정보를 덮어 쓰고 있으며 프로그램은 어쨌든 잘못된 결과를 얻을 가능성이 높습니다. 사실, 충돌은 최소한 나쁜 효과에 의존하는 것을 막기 때문에 충돌이 더 좋습니다.

배열의 크기를 더 적합한 것으로 늘리십시오 (char[14] 이 경우 사용 가능한 정보의 경우) 또는 대처할 수있는 다른 데이터 구조를 사용하십시오.


업데이트:

여분의 7자가 문제를 일으키지 않지만 8자가하는 이유를 찾는 데 관심이있는 것처럼 보이므로 입력에 대한 스택 레이아웃을 구상하겠습니다. main(). 실제 레이아웃은 컴파일러가 사용하는 통화 규칙에 따라 "가능"이라고 말합니다. C 스타트 업 코드가 호출 된 이후 main() ~와 함께 argc 그리고 argv, 시작시 스택 main(), 공간을 할당 한 후 char[5], 다음과 같이 보일 수 있습니다.

+------------------------------------+
| C start-up code return address (4) |
| argc (4)                           |
| argv (4)                           |
| x = char[5] (5)                    |
+------------------------------------+

바이트를 쓸 때 Hello1234567\0 와 함께:

strcpy (x, "Hello1234567");

에게 x, 그것은 그것을 덮어 씁니다 argc 그리고 argv 그러나 돌아 왔을 때 main(), 괜찮아요. 구체적으로 Hello 채워집니다 x, 1234 채워집니다 argv 그리고 567\0 채워집니다 argc. 만약 당신이 실제로 시도하지 않는다면 사용 argc 및/또는 argv 그 후에는 괜찮을 것입니다 :

+------------------------------------+ Overwrites with:
| C start-up code return address (4) |
| argc (4)                           |   '567<NUL>'
| argv (4)                           |   '1234'
| x = char[5] (5)                    |   'Hello'
+------------------------------------+

그러나 글을 쓰면 Hello12345678\0 (여분의 "8") x, 그것은 그것을 덮어 씁니다 argc 그리고 argv 그리고 또한 반환 주소의 1 바이트가 main() C 스타트 업 코드로 돌아 가려고 시도하면 대신 요정 땅으로 나옵니다.

+------------------------------------+ Overwrites with:
| C start-up code return address (4) |   '<NUL>'
| argc (4)                           |   '5678'
| argv (4)                           |   '1234'
| x = char[5] (5)                    |   'Hello'
+------------------------------------+

다시 말하지만, 이것은 전적으로 컴파일러의 호출 규칙에 달려 있습니다. 다른 컴파일러는 항상 배열을 4 바이트의 배수로 패드 할 수 있으며 다른 세 문자를 작성할 때까지 코드가 실패하지 않을 수 있습니다. 동일한 컴파일러조차도 정렬이 만족되도록 스택 프레임에 변수를 다르게 할당 할 수 있습니다.

그것이 그들이 정의되지 않은 의미입니다. 당신은 알다 무슨 일이 일어날 지.

다른 팁

스택에 복사하고 있으므로 컴파일러가 스택에 배치 한 내용에 따라 프로그램을 충돌시키는 데 필요한 추가 데이터의 양에 따라 다릅니다.

일부 컴파일러는 버퍼 크기에 걸쳐 단일 바이트 만 충돌하는 코드를 생성 할 수 있습니다. 동작이 무엇인지 정의되지 않습니다.

크기 13은 반환 주소를 덮어 쓰기에 충분하거나 기능이 반환 될 때 충돌하는 유사한 주소를 덮어 쓰기에 충분합니다. 그러나 다른 컴파일러 또는 다른 플랫폼은 길이가 다른 길이로 충돌 할 수 있습니다.

또한 덜 중요한 것이 덮어 쓰고 있다면 더 오랜 시간 동안 실행되면 프로그램이 다른 길이로 충돌 할 수 있습니다.

32 비트 인텔 플랫폼의 경우 설명이 다음과 같습니다. CHAR [5]를 쌓아 놓을 때 컴파일러는 정렬로 인해 실제로 8 바이트를 할당합니다. 그런 다음 기능이 다음과 같은 프롤로그를 갖는 것이 일반적입니다.

push ebp
mov ebp, esp

이렇게하면 스택에서 EBP 레지스트리 값을 저장 한 다음 ESP 값을 ESP 값을 사용하여 매개 변수에 액세스하기 위해 ESP 값을 EBP로 이동합니다. 이로 인해 스택에 4 바이트가 추가로 EBP 값으로 점유됩니다.

에필로그 EBP에서는 복원되지만 그 값은 일반적으로 스택-합산 기능 매개 변수에 액세스하는 데만 사용되므로 대부분의 경우 상처를 덮지 않을 수 있습니다.

따라서 다음 레이아웃이 있습니다 (스택은 인텔에서 아래쪽으로 자랍니다) : 배열의 경우 8 바이트, EBP의 경우 4 바이트, 일반적으로 리턴 주소입니다.

그렇기 때문에 프로그램 충돌을 위해 최소 13 바이트를 덮어 써야합니다.

위의 답변에 추가하려면 : 다음과 같은 도구로 이와 같은 버그를 테스트 할 수 있습니다. Valgrind. 창문에 있다면 살펴보십시오 이 스레드.

"str"배열 후 스택에 무엇이 있는지에 따라 다릅니다. 당신은 그 많은 캐릭터를 복사 할 때까지 중요한 것을 짓밟 지 않아야합니다.

따라서 기능의 다른 내용, 사용하는 컴파일러 및 컴파일러 옵션에 따라 다릅니다.

13은 5 + 8이며, STR 배열 후 두 개의 비 임계 단어가 있음을 제안한 다음 중요한 것 (아마도 반환 주소).

그것이 정의되지 않은 행동 (UB)의 순수한 아름다움입니다. 정의되지 않았습니다.

코드 :

char str[5];
strcpy(str,"Hello12345678");

14 바이트/숯을 작성합니다 str 5 바이트/숯 만 담을 수 있습니다. 이것은 UB를 호출합니다.

Q : "hello1234567"에 충돌하지 않는 이유는 "hello12345678"의 길이 13 이상 13 이상의 문자열에만 충돌하는 이유입니다.

행동이 정의되지 않기 때문입니다. strncpy를 사용하십시오. 이 페이지를 참조하십시오 http://en.wikipedia.org/wiki/strcpy자세한 내용은.

strncpy는 소스 문자열에 길이> = n이있는 경우 null 종료를 추가하지 않기 때문에 안전하지 않습니다. 여기서 n은 대상 문자열의 크기입니다.

char s[5];
strncpy(s,5,"test12345");
printf("%s",s); // crash

우리는 항상 이것을 완화하기 위해 strlcpy를 사용합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top