Pergunta

Minha mente estava vagando hoje sobre o tema de ponteiros de função, e eu vim com o seguinte cenário na minha cabeça:

__stdcall int function (int)
{
    return 0;
}

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

AFAIK este código iria corromper a pilha, de modo que tipos de questões que eu poderia estar olhando se eu corri este código?

Eu faria esta investigando me no entanto estou longe de minha máquina dev por uma semana.

EDIT: Espere um segundo, eu estive pensando um pouco mais. Como tem sido observado nos comentários, a intenção deste código era para ter um parâmetro deixado na pilha quando tudo estiver dito e feito (puts chamador dois params na pilha, receptor - esperando apenas um param - pops apenas um off ). No entanto, desde o meu elenco não faz menção a convenção de chamada, estou lançando de stdcall, pelo menos do ponto de vista do autor da chamada? função int (int) ainda irá aparecer um param fora da pilha, mas não a reversão chamador para pensar a função é __cdecl (o padrão) por causa do elenco? (Ou seja, três parâmetros totais estalado?)

EDIT2: A resposta a essa segunda questão, como foi confirmado por Rob, é sim. Eu teria que restate __stdcall se eu queria deixar um param na pilha:

(*(__stdcall int(*)(char*,char*))function)("thought", "experiment");
Foi útil?

Solução

Você está chamando a função como se fosse _cdecl que significa que o chamador empurra os argumentos e limpa a pilha.

A função de receber é _stdcall que implica os limpa callee a pilha. O receptor está esperando um único argumento tão pop 4 bytes na pilha.

Quando a função retorna o chamador, em seguida, pop off dois ponteiros (tendo anteriormente empurrado em dois ponteiros), assim que sua pilha está sendo corrompido por 4 bytes.

Os dois convenções de chamada usar o mesmo mecanismo de retorno, e têm as mesmas regras de registro (eax, ecx e edx não são preservados). Consulte wikipedia para mais detalhes.

Dependendo da disposição quadro de pilha e alinhamento esse descompasso pode causar uma série de efeitos. Se você tiver sorte, então você fugir com ele. Se não você pode atrapalhar o endereço de retorno de sua função principal, fazendo com que o programa deixe de funcionar quando se ramos para sabe-se lá onde. Se o compilador injetou algum tipo de guarda de pilha à corrupção captura, em seguida, ele provavelmente irá detectar isso e abortará o programa.

Outras dicas

Não, definitivamente não vai causar uma tela azul. No processo do modo de usuário é capaz de fazer isso. Mesmo se tal bug estavam no código de modo kernel, o BSOD iria ocorrer somente após acessar memória inválida ou passar argumentos errados para uma função.

Você está simplesmente corromper a memória privada do seu processo, ea corrupção pode (ou não) mais tarde resultar em uma operação inválida (ex. Dereferencing um ponteiro que aponta para a memória inválido). Quando isso acontece, o sistema operacional termina o seu processo, mas não antes.

Eu acho que você teria 'um comportamento indefinido' neste caso.

A partir da C padrão: (Eu diria que é a mesma em C ++)

768 Se um ponteiro convertido é usado para ligar para uma função cujo tipo não é compatível com o apontado para digitar, o comportamento é indefinido.

Edit: Na maioria sistema operacional, este tipo de erro não iria causar problemas em seu sistema operacional inteiro. Mas ele poderia causar problemas indefinidos em seu programa. Seria muito difícil para um programa de modo de usuário para ser capaz de causar uma tela azul.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top