Substituição de malloc definida pelo usuário

Os usuários podem substituir o subsistema de memória (malloc, calloc, realloc, free, mallopt e mallinfo subroutines) com um de seu próprio design.

Nota: Subsistemas de Memória de Substituição gravados em C++ não são suportados devido ao uso do subsistema de memória libc.a na biblioteca C++ libC.a.

O subsistema de memória existente funciona para aplicações encadeadas e não encadeadas. O subsistema de memória definido pelo usuário deve ser o threadsafe para que ele funcione em processos encadeados e não encadeados. Como não há verificações para verificar se ele é, se um módulo de memória não threadsafe é carregado em um aplicativo encadeado, a memória e os dados podem estar corrompidos.

O subsistema de memória definido pelo usuário 32-e 64-bit objetos devem ser colocados em um arquivo com o objeto compartilhado de 32-bit denominadomem32.oe o objeto compartilhado de 64-bit denominadomem64.o.

Os objetos compartilhados pelo usuário devem exportar os seguintes símbolos:
  • __malloc__
  • __free__
  • __realloc__
  • __calloc__
  • __mallinfo__
  • __mallopt__
  • __malloc_init__
  • __malloc_prefork_lock__
  • __malloc_postfork_unlock__
Os objetos compartilhados pelo usuário podem, opcionalmente, exportar o seguinte símbolo:
  • __malloc_start__
  • __posix_memalign__

A execução não para se esses símbolos não existirem.

As funções são definidas da seguinte forma:
void *__malloc__(size_t):
Esta função é o equivalente ao usuário da subroutine malloc .
void __free__(void *):
Esta função é o equivalente ao usuário da subroutine free .
void *__realloc__(void *, size_t):
Esta função é o equivalente ao usuário da subroutine realloc .
void *__calloc__(size_t, size_t):
Esta função é o equivalente ao usuário da subroutine calloc .
int __mallopt__(int, int):
Esta função é o equivalente ao usuário da subroutine mallopt .
struct mallinfo __mallinfo__():
Esta função é o equivalente ao usuário da subroutine mallinfo .
void __malloc_start__()
Esta função será chamada uma vez antes de qualquer outro ponto de entrada malloc definido pelo usuário ser chamado.
void __posix_memalign__()
Esta função é o equivalente de usuário da subroutina posix_memalign . Se este símbolo não existir, a execução não irá parar, mas uma chamada feita para a subroutine posix_memalign causará resultados inesperados.
As funções a seguir são utilizadas pelo subsistema de encadeamento para gerenciar o subsistema de memória definido pelo usuário em um ambiente multiencadeado. Eles serão chamados apenas se o aplicativo e / ou o módulo definido pelo usuário estiverem ligados ao libpthreads.a Mesmo que o subsistema definido pelo usuário não seja thread-safe e não esteja ligado a libpthreads.a, essas funções deverão ser definidas e exportado Caso contrário, o objeto não será carregado.
void __malloc_init__(void)
Chamado pela rotina de inicialização do pthread. Esta função é usada para inicializar o subsistema de memória do usuário encadeado. Na maioria dos casos, isso inclui criar e inicializar alguma forma de bloqueio de dados. Mesmo se o módulo do subsistema de memória definido pelo usuário estiver ligado a libpthreads.a, o subsistema de memória definido pelo usuário deverá funcionar antes__malloc_init__()é chamado.
void __malloc_prefork_lock__(void)
Chamado por pthreads quando oforksubroutine é chamada. Esta função é usada para insumo que o subsistema de memória está em um estado conhecido antes dofork()e fica assim até que ofork()retornou. Na maioria dos casos isso inclui adquirir os bloqueios do subsistema de memória.
void __malloc_postfork_unlock__(void)
Chamado por pthreads quando oforksubroutine é chamada. Esta função é usada para tornar o subsistema de memória disponível no pai e no filho após umfork. Isso deve desfazer o trabalho feito por__malloc_prefork_lock__. Na maioria dos casos, isso inclui a liberação de bloqueios do subsistema de memória.
Todas as funções devem ser exportadas a partir de um módulo compartilhado. Os módulos separados devem existir para implementações de 32 e 64-bit colocados em um arquivo. Por exemplo:
  • Módulo mem.exp :
    __malloc__
    __free__
    __realloc__
    __calloc__
    __mallopt__
    __mallinfo__
    __malloc_init__
    __malloc_prefork_lock__
    __malloc_postfork_unlock__
    __malloc_start__
  • mem_functions32.o módulo:

    Contém todas as funções 32-bit necessárias

  • mem_functions64.o módulo:

    Contém todas as funções 64-bit necessárias

Os exemplos a seguir são para criar os objetos compartilhados. Os comandos-lpthreadsparâmetro é necessário apenas se o objeto usar funções pthread.
  • Criação de 32-bit objeto compartilhado:
    ld -b32 -m -o mem32.o mem_functions32.o \
    -bE:mem.exp \
    -bM:SRE -lpthreads -lc
  • Criação de 64-bit objeto compartilhado:
    ld -b64 -m -o mem64.o mem_functions64.o \
    -bE:mem.exp \
    -bM:SRE -lpthreads -lc
  • Criação do arquivo (o nome de objetos compartilhados deve sermem32.opara o objeto 32bit emem64.opara o objeto 64bit ):
     ar -X32_64 -r archive_name mem32.o mem64.o

Habilitando o subsistema de memória definido pelo usuário

O subsistema de memória definido pelo usuário pode ser ativado utilizando-se um dos seguintes:
  • A variável de ambiente MALLOCTYPE
  • Os comandos_malloc_user_defined_namevariável global no aplicativo do usuário

Para utilizar a variável de ambiente MALLOCTYPE , o arquivo contendo o subsistema de memória definido pelo usuário é especificado configurando-se MALLOCTYPE parauser:archive_nameonde archive_name está no aplicativo'slibpathou o caminho é especificado na variável de ambiente LIBPATH .

Para usar o_malloc_user_defined_namevariável global, o aplicativo do usuário deve declarar a variável global como:
char *_malloc_user_defined_name="archive_name"

onde archive_name deve estar na libpath do aplicativo ou um caminho especificado na variável de ambiente LIBPATH .

Observação:
  1. Quando um aplicativo setuid é executado, a variável de ambiente LIBPATH é ignorada de modo que o arquivo deve estar na libpath do aplicativo.
  2. archive_name não pode conter informações de caminho.
  3. Quando ambos a variável de ambiente MALLOCTYPE e a_malloc_user_defined_namevariável global são usadas para especificar o archive_name, o arquivo especificado por MALLOCTYPE substituirá o especificado por_malloc_user_defined_name.

32-bit e 64-bit considerações

Se o arquivo não contiver ambos os objetos compartilhados de 32-bit e 64-bit bits e o subsistema de memória definido pelo usuário foi ativado usando a variável de ambiente MALLOCTYPE , haverá problemas executando processos de 64-bit bits a partir de 32-bit aplicativos e 32-bit processos a partir de 64-bit aplicativos. Quando um novo processo é criado usando a subroutine exec , o processo herda o ambiente do aplicativo de chamada. Isso significa que a variável de ambiente MALLOCTYPE será herdada e o novo processo tentará carregar o subsistema de memória definido pelo usuário. Se o membro de arquivo não existir para este tipo de programa, a carga falhará e o novo processo sairá.

Considerações do encadeamento

Todas as funções fornecidas devem funcionar em um ambiente multiencadeado. Mesmo se o módulo estiver vinculado a libpthreads.a, pelo menos__malloc__()deve trabalhar antes__malloc_init__()é chamado e pthreads é inicializado. Isso é necessário porque a inicialização pthread requermalloc()antes__malloc_init__()é chamado.

Todas as funções de memória fornecidas devem funcionar em ambientes encadeados e não encadeados. Os comandos__malloc__()função deve ser capaz de ser executado até a conclusão sem ter quaisquer dependências em__malloc_init__()(ou seja,__malloc__()deve presumir inicialmente que__malloc_init__()tem não ainda executado.) Depois__malloc_init__()tiver concluído,__malloc__()pode contar com qualquer trabalho feito por__malloc_init__(). Isso é necessário porque a inicialização pthread usamalloc()antes__malloc_init__()é chamado.

As seguintes variáveis são fornecidas para evitar que rotinas relacionadas a encadeamento desnecessárias sejam chamadas de:
  • Os comandos__multi_threadedvariável é zero até que um encadeamento é criado quando ele se torna diferente de zero e não será redefinido para zero para esse processo.
  • Os comandos__n_pthreadsvariável é-1até que pthreads tenha sido inicializado quando for configurado como1. A partir desse ponto sobre ele é uma contagem do número de threads ativas.

Exemplo:

Se__malloc__()Usapthread_mutex_lock(), o código pode parecer semelhante ao seguinte:

if (__multi_threaded)
pthread_mutex_lock(mutexptr);

/* ..... work ....... */

if (__multi_threaded)
pthread_mutex_unlock(mutexptr);

Neste exemplo,__malloc__()é impedido de executar funções pthread antes de pthreads ser totalmente inicializado. Os aplicativos de rosca única também são acelerados porque o bloqueio não é feito até que um segundo encadeamento seja iniciado.

Limitações

Subsistemas de memória gravados em C++ não são suportados devido à inicialização e às dependências do libC.a e do subsistema de memória libc.a

As mensagens de erro não são traduzidas porque o subroutine setlocale usamalloc()para inicializar os locales. Semalloc()falha então a subroutine setlocale não pode finalizar e o aplicativo ainda está noPOSIXCódigo do idioma. Portanto, apenas as mensagens em inglês padrão serão exibidas.

Os programas construídos estaticamente não podem usar o subsistema de memória definido pelo usuário sem recompilação.

Relatório de erro

A primeira vez que a subroutine malloc é chamada, o objeto 32-ou 64-bit no arquivo especificado pela variável de ambiente MALLOCTYPE é carregado. Se a carga falhar, uma mensagem será exibida e as saídas do aplicativo. Se a carga for bem-sucedida, uma tentativa é feita para verificar se todos os símbolos necessários estão presentes. Se algum símbolo estiver faltando, o aplicativo é finalizado e a lista de símbolos ausentes será exibida.