É possível marcar um segmento de memória como "fora dos limites" para que o gerente de heap não aloque dele?

StackOverflow https://stackoverflow.com/questions/4274058

Pergunta

Hoje cedo eu perguntei essa questão.

Depois de passar algum tempo investigando esse problema, descobri o que está acontecendo. Estou postando isso como uma nova pergunta, porque acho interessante o suficiente para rastrear como um problema separado. Vou atualizar essa pergunta com a resposta (e um link para este).

Teste de unidade de lançamento do depurador

// Construct object
Object* pObject = new Object(...);
// Pointer value of pObject == 0x05176960

// Lots of other code
// ...

// Destroy object
delete pObject;

// Construct object again
pObject = new Object(...);
// Pointer value of pObject == 0x05560194     /* Different memory location */

Lançamento do teste de unidade da linha de comando

// Construct object
Object* pObject = new Object(...);
// Pointer value of pObject == 0x05176960

// Lots of other code
// ...

// Destroy object
delete pObject;

// Construct object again
pObject = new Object(...);
// Pointer value of pObject == 0x05176960     /* Same memory location */

Resumindo:

  • Ao iniciar o teste de unidade a partir do linha de comando, chamadas subsequentes para new para alocar um Object (deleteing the anterior Object antes de alocar um novo) sempre retorne o mesmo endereço na memória.
  • Ao iniciar o teste de unidade a partir do Depurador, chamadas subsequentes para new para alocar um Object (deleteing the anterior Object antes de alocar um novo) sempre retorne um único endereço na memória.

O problema é isso porque as alocações de Object Sempre obtenha o mesmo endereço na memória ao iniciar a linha de comando, um mapa que estou acessando que armazenou o velho O ponteiro ainda pode ser usado e o teste não falha. Mas quero que meu teste de unidade falhe quando a correção do defeito não estiver no lugar, para garantir que ela não falhe silenciosamente e o defeito não volte.

Existem 2 partes na minha pergunta:

  1. Por que o gerente Heap reutilizaria a mesma parte da memória ao iniciar um teste de unidade a partir da linha de comando, mas não quando inicio o teste da unidade do depurador?

  2. Existe uma configuração do compilador que eu poderia usar no meu chicote de teste ou um método que posso ligar para impedir que o gerente de heap reusuga uma seção de memória que excluí, para me permitir escrever corretamente meu teste de unidade? 1


1Obviamente, uma maneira de fazer isso é não excluir o objeto original, mas a parte do código que aloca isso está no meu código de produção, e isso resultaria em vazamentos de memória.

Foi útil?

Solução

Seu teste de unidade é falha, pois está dependendo do comportamento indefinido. Você deve reescrever seu teste de unidade para que ele não dependa de comportamento indefinido; nesse caso, ele sempre passará, independentemente de como o gerenciador de memória decide alocar memória.

O que você está fazendo é o seguinte:

Object* pObject = new Object(...);
...
delete pObject;
pObject = new Object(...);
// Use dangling pointer to first object, and if it crashes, the unit test fails
// This is WRONG since a crash isn't guaranteed

Em vez disso, você deve reestruturar o teste de unidade para que funcione assim:

Object* pObject = new Object(...);
...
// Check to see if there are dangling references to pObject right before we
// delete it.  If there are, assert() and fail the unit test.
assert(NoDanglingReferences(pObject));
delete pObject;
// Continue on with more tests

Outras dicas

Você pode substituir new e delete com suas próprias versões que têm o comportamento que você deseja.

Primeiro de tudo - não em um gerenciador de memória "normal". Depois de negociar a memória, você passa para o gerenciador de memória e o último pode reutilizá -lo.

Você poderia Escreva um gerente personalizado Como Usuário Andreas Brinck sugere, mas o que faria? Ele não cria memória do ar, solicita -a de algum lugar como heap CRT ou pilha do sistema operacional.

Cenário A. Não retornaria a memória à pilha subjacente - você terá um vazamento e o bloco de memória ainda será mapeado no espaço de endereço e estará acessível.

Cenário B. Ele retornará a memória à pilha subjacente - então, quando seu manober tentar alocar a memória novamente, o heap subjacente pode retornar esse bloco novamente. Além disso, você não sabe o que o heap subjacente faz quando retorna a memória. Pode torná -lo não mapeado ou não - portanto, acessar que a memória pode travar ou não.

A linha inferior é que você está ferrado. Tentar testar comportamento indefinido não será muito produtivo.

Este é um exemplo de comportamento indefinido. Nem C ++ nem o gerenciador de heap definem como a memória será alocada. Você não pode confiar na memória de ser reutilizada ou não ser reutilizada. Quando você faz algo como acima, não há como determinar ou mudar se o ponteiro retornado será ou não diferente do primeiro alocado.

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