문제

오늘 내 마음은 함수 포인터라는 주제로 방황했고, 내 머릿속에는 다음과 같은 시나리오가 떠올랐습니다.

__stdcall int function (int)
{
    return 0;
}

int main()
{
    (*(int(*)(char*,char*))function)("thought", "experiment");
    return 0;
}

AFAIK 이 코드는 스택을 손상시킬 수 있는데, 이 코드를 실행하면 어떤 유형의 문제가 나타날 수 있습니까?

나는 이 조사를 스스로 할 것이지만 일주일 동안 내 개발 컴퓨터에서 떨어져 있습니다.

편집하다:잠깐만요, 좀 더 생각하고 있어요.주석에서 관찰된 바와 같이, 이 코드의 의도는 모든 작업이 완료될 때 스택에 매개변수를 남겨 두는 것이었습니다(호출자는 스택에 두 개의 매개변수를 놓고, 피호출자는 하나의 매개변수만 기대하며 하나만 꺼냅니다. ).그러나 내 캐스트가 호출 규칙을 언급하지 않기 때문에 적어도 호출자의 관점에서 stdcall을 폐기하고 있습니까? int 함수(int) 여전히 스택에서 매개변수를 팝하지만 호출자는 캐스트 때문에 함수가 __cdecl(기본값)이라고 생각하게 됩니까?(즉.총 3개의 매개변수가 터졌나요?)

편집2:Rob이 확인한 두 번째 질문에 대한 대답은 '예'입니다.스택에 매개변수를 남기려면 __stdcall을 다시 작성해야 합니다.

(*(__stdcall int(*)(char*,char*))function)("thought", "experiment");
도움이 되었습니까?

해결책

호출자가 인수를 푸시하고 스택을 정리한다는 의미인 _cdecl인 것처럼 함수를 호출합니다.

수신 함수는 호출 수신자가 스택을 정리함을 의미하는 _stdcall입니다.호출 수신자는 단일 인수를 기대하므로 스택에서 4바이트를 팝합니다.

함수가 반환되면 호출자는 두 개의 포인터(이전에 두 개의 포인터를 푸시한 후)를 팝업하므로 스택이 4바이트만큼 손상됩니다.

두 호출 규칙 모두 동일한 반환 메커니즘을 사용하고 동일한 등록 규칙을 갖습니다(eax, ecx 및 edx는 유지되지 않음).보다 위키피디아 상세 사항은.

스택 프레임 레이아웃 및 정렬에 따라 이러한 불일치로 인해 여러 가지 영향이 발생할 수 있습니다.운이 좋다면 그걸로 도망칠 수 있습니다.그렇지 않으면 주 함수의 반환 주소가 엉망이 되어 프로그램이 who-knows-where로 분기될 때 충돌이 발생할 수 있습니다.컴파일러가 손상을 포착하기 위해 일종의 스택 가드를 삽입한 경우 이를 감지하고 프로그램을 중단할 가능성이 높습니다.

다른 팁

아니요, 블루 스크린이 발생하지는 않습니다.어떤 사용자 모드 프로세스도 이를 수행할 수 없습니다.이러한 버그가 커널 모드 코드에 있더라도 BSOD는 유효하지 않은 메모리에 액세스하거나 잘못된 인수를 함수에 전달한 후에만 발생합니다.

단순히 프로세스의 개인 메모리가 손상되었으며 손상으로 인해 나중에 잘못된 작업이 발생할 수 있습니다(예:유효하지 않은 메모리를 가리키는 포인터를 역참조함).이런 일이 발생하면 OS는 프로세스를 종료하지만 더 빨리 종료하지는 않습니다.

이 경우 당신은 '정의되지 않은 행동'을 가질 것이라고 생각합니다.

로부터 C 표준: (C ++에서 동일하다고 생각합니다)

768 변환 된 포인터를 사용하여 유형을 가리키는 유형과 호환되지 않는 함수를 호출하는 경우 동작이 정의되지 않습니다.

편집 : 대부분의 운영 체제에서 이러한 유형의 오류는 전체 운영 체제에서 문제를 일으키지 않습니다. 그러나 프로그램에서 정의되지 않은 문제가 발생합니다. 사용자 모드 프로그램이 파란색 스크린을 유발할 수있는 것은 매우 어려울 것입니다.

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