Pergunta

Na minha aplicação, tenho alguns pontos vazios (isso se deve a razões históricas, a aplicação foi originalmente escrita em p puro). Em um dos meus módulos, sei que os pontos vazios apontam para casos de classes que poderiam herdar de uma classe base conhecida, mas não posso ter 100% de certeza. Portanto, fazer um Dynamic_cast no void-pointer pode causar problemas. Possivelmente, o ponto vazio aponta até uma estrutura simples (para que nenhum VPTR na estrutura).

Gostaria de investigar os 4 primeiros bytes da memória que o ponto vazio está apontando, para ver se esse é o endereço do vtable válido. Sei que essa é a plataforma, talvez até específica do compilador, mas poderia me ajudar a avançar o aplicativo e se livrar de todos os pontos de vazio por um período de tempo limitado (digamos 3 anos).

Existe uma maneira de obter uma lista de todos os vtables no aplicativo, ou uma maneira de verificar se um ponteiro aponta para um vtable válido e se essa instância apontando para o vtable herda de uma classe base conhecida?

Foi útil?

Solução

Gostaria de investigar os 4 primeiros bytes da memória que o ponto vazio está apontando, para ver se esse é o endereço do vtable válido.

Você pode fazer isso, mas não tem garantias de que funcionará. Y nem sabe se o vazio* apontará para o vtable. A última vez que analisei isso (mais de 5 anos atrás) acredito que algum compilador armazenou o ponteiro VTable antes da o endereço apontado pela instância*.

Eu sei que essa é a plataforma, talvez até específica do compilador, específica,

Também pode ser específica de opções de compilador, dependendo das otimizações que você usa e assim por diante.

Mas isso poderia me ajudar a avançar o aplicativo e me livrar de todos os pontos vazios por um período limitado (digamos 3 anos).

Essa é a única opção que você pode ver para impulsionar o aplicativo? Você já considerou os outros?

Existe uma maneira de obter uma lista de todos os vtables no aplicativo,

Não :(

ou uma maneira de verificar se um ponteiro aponta para um vtable válido,

Nenhuma maneira padrão. O que você pode fazer é abrir alguns ponteiros de classe em seu depurador favorito (ou lançar a memória para bytes e registrá -lo em um arquivo) e compará -lo e ver se faz sentido. Mesmo assim, você não tem garantias de que nenhum de seus dados (ou outros ponteiros no aplicativo) não pareça o suficiente (quando fundido como bytes) para confundir o código que você quiser.

E se essa instância apontando para o vtable herda de uma classe base conhecida?

De novo não.

Aqui estão algumas perguntas (você já pode ter considerado elas). As respostas a estes podem oferecer mais opções ou podem nos dar outras idéias para propor:

  • Qual é o tamanho da base do código? É viável introduzir mudanças globais ou a funcionalidade está se espalhando para isso?

  • Você trata todos os ponteiros uniformemente (ou seja: existem pontos comuns em seu código -fonte em que você pode conectar e adicionar seus próprios metadados?)

  • O que você pode mudar no seu SourCecode? (Se você tiver acesso às suas sub -rotinas de alocação de memória ou poderá conectar o seu, por exemplo, poderá conectar seus próprios metadados).

  • Se diferentes tipos de dados forem lançados para anular* em várias partes do seu código, como você decide mais tarde o que há nesses indicadores? Você pode usar o código que discrimina o vazio* para decidir se são aulas ou não?

  • Sua base de código permite a refatoração de metodologias? (Refatoração em pequenas iterações, conectando implementações alternativas para partes do seu código, depois removendo a implementação inicial e testando tudo)

Editar (solução proposta):

Faça as seguintes etapas:

  • Defina uma classe de metadados (base)

  • Substitua suas rotinas de alocação de memória pelos personalizados que se referem às rotinas padrão / antigas (e verifique se seu código ainda funciona com as rotinas personalizadas).

  • Em cada alocação, aloque the requested size + sizeof(Metadata*) (e verifique se seu código ainda funciona).

  • substitua o primeiro sizeof(Metadata*) Bytes da sua alocação com uma sequência de bytes padrão que você pode testar facilmente (sou parcial para 0xdeadbeef: d). Então, retorne [allocated address] + sizeof(Metadata*) para o aplicativo. Na desalocação, pegue o ponteiro recebido, diminua -o por `sizeof (metadados*) e ligue para o sistema / rotina anterior para executar a desalocação. Agora, Você tem um buffer extra alocado em seu código, especificamente para metadados em cada alocação.

  • Nos casos em que você está interessado em ter metadados, criar/obter um ponteiro de classe de metadados e, em seguida, defina -o na zona 0xdeadbeef. Quando você precisa verificar os metadados, reinterpret_cast<Metadata*>([your void* here]), diminua -o e verifique se o valor do ponteiro é 0xDeadBeef (sem metadados) ou outra coisa.

Observe que esse código só deve estar lá para refatorar - para o código de produção, é lento, propenso a erros e geralmente outras coisas ruins que você não deseja que seu código de produção seja. Eu faria todo esse código dependente de alguns REFACTORING_SUPPORT_ENABLED Macro que nunca permitiria que sua aula de metadados visse a luz de uma liberação de produção (exceto para testes, talvez).

Outras dicas

Eu diria que não é possível sem referência relacionada (declaração de cabeçalho).

Se você deseja substituir esses ponteiros vazios para corrigir o tipo de interface, aqui está o que eu acho para automatizá -lo:

  1. Passe pela sua base de código para obter uma lista de todas as classes com funções virtuais, você pode fazer isso rápido escrevendo script, como Perl

  2. Escreva uma função que pegue um ponteiro de vazio* como entrada e itera sobre essas classes, tenta dinâmico_castá -lo e registrar informações se for bem -sucedido, como tipo de interface, linha de código

  3. Chame essa função em qualquer lugar em que você usou o Void* Pointer, talvez você possa embrulhá -lo com uma macro para que você possa obter o arquivo, informações de linha fáceis

  4. Execute uma automação completa (se tiver) e analise a saída.

A maneira mais fácil seria sobrecarregar operator new para sua classe base específica. Dessa forma, se você conhece seus indicadores de vazio* para acumular objetos, também pode com 100% de certeza determinar se eles estão apontando para o seu objeto.

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