Você pode forçar um acidente se ocorrer uma gravação em um determinado local de memória com granularidade mais fina que a página?

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

Pergunta

Estou escrevendo um programa que, por razões de desempenho, usa memória compartilhada (soquetes e tubos como alternativas foram avaliados e eles não são rápidos o suficiente para minha tarefa, em geral, falando qualquer método IPC que envolva cópias é muito lento). Na região de memória compartilhada, estou escrevendo muitas estruturas de tamanho fixo. Há um programa responsável por escrever as estruturas na memória compartilhada e muitos clientes que leem dele. No entanto, há um membro de cada estrutura que os clientes precisam escrever (uma contagem de referência, que eles atualizarão atomicamente). Todos os outros membros devem ser lidos apenas para os clientes.

Como os clientes precisam alterar esse membro, eles não podem mapear a região de memória compartilhada apenas como leitura. Mas eles também não devem mexer com os outros membros e, como esses programas são escritos no C ++, a corrupção da memória é possível. Idealmente, deve ser o mais difícil possível para um cliente travar outro. Só estou preocupado com clientes de buggy, não maliciosos, então são permitidas soluções imperfeitas.

Eu posso tentar impedir que os clientes sobrescrevam declarando os membros no cabeçalho que eles usam como const, mas isso não impedirá a corrupção da memória (transbordamentos de buffer, moldes ruins, etc.) de sobrescrever. Eu posso inserir Canárias, mas então eu tenho que pagar constantemente o custo de verificá -los.

Em vez de armazenar diretamente o membro da contagem de referência, eu poderia armazenar um ponteiro para os dados reais em uma página de gravação mapeada separada, mantendo as estruturas em páginas apenas mapeadas. Isso funcionará, o sistema operacional forçará meu aplicativo a travar se eu tentar escrever para os dados apontados, mas o armazenamento indireto pode ser indesejável ao tentar escrever Bloquear algoritmos livres, porque a necessidade de seguir outro nível de indireção pode mudar se algo pode ser feito atomicamente.

Existe alguma maneira de marcar áreas menores de memória de modo que escrevê -las faça com que seu aplicativo exploda? Algumas plataformas têm pontos de observação de hardware, e talvez eu pudesse ativar um daqueles com montagem embutida, mas eu ficaria limitado a apenas 4 por vez no X86 de 32 bits e cada um só podia cobrir parte da estrutura, porque eles são limitados a 4 bytes. Também tornaria meu programa doloroso de depuração;)

Edit: eu encontrei este papel de estupro bastante, mas infelizmente exige o uso de memória ECC e um kernel Linux modificado.

Foi útil?

Solução

Não acho que seja possível fazer com que alguns bits se levem apenas como esse no nível do sistema operacional.

Uma coisa que me ocorreu agora é que você poderia colocar as contagens de referência em uma página diferente, como sugeriu. Se as estruturas forem um tamanho comum e estão todos em locais de memória seqüencial, você pode usar a aritmética do ponteiro para localizar uma contagem de referência do ponteiro das estruturas, em vez de ter um ponteiro dentro da estrutura. Isso pode ser melhor do que ter um ponteiro para o seu caso de uso.

long *refCountersBase;//The start address of the ref counters page
MyStruct *structsBase;//The start address of your structures page

//get address to reference counter
long *getRefCounter(MyStruct *myStruct )
{
    size_t n = myStruct - structsBase;
    long *ref = refCountersBase + n;
    return ref;
}

Outras dicas

Você precisaria adicionar um manipulador de sinal para o Sigsegv que se recupere da exceção, mas apenas para determinados endereços. Um ponto de partida pode ser http://www.opengroup.org/onlinepubs/009695399/basidefs/signal.h.html e a documentação correspondente para o seu sistema operacional.

Editar: Acredito que o que você deseja é executar a gravação e o retorno se o endereço de gravação estiver realmente ok, e cauda o manipulador de exceção anterior (o ponteiro que você recebe ao instalar seu manipulador de exceção) se deseja propagar a exceção. Não tenho experiência nessas coisas.

Eu nunca ouvi falar de aplicar somente leitura em menos de uma granularidade de página, então você pode estar sem sorte nessa direção, a menos que possa colocar cada estrutura em duas páginas. Se você puder comprar duas páginas por estrutura, poderá colocar o refre em uma das páginas e fazer o outro somente leitura.

Você pode escrever uma API em vez de apenas usar cabeçalhos. Forçar os clientes a usar a API removeria a maioria dos problemas de corrupção.

Manter os dados com a contagem de referência em vez de em uma página diferente ajudará na localidade dos dados e, assim, melhorar o desempenho do cache.

Você precisa considerar que um leitor pode ter um problema e não atualizar corretamente sua contagem de ref. Além disso, o escritor pode deixar de concluir uma atualização. Lidar com essas coisas requer verificações extras. Você pode combinar essas verificações com a API. Pode valer a pena experimentar medir as implicações de desempenho de algum tipo de verificação de integridade. Pode ser rápido o suficiente para manter uma soma de verificação, algo tão simples quanto Adler32.

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