Remplacement malloc défini par l'utilisateur

Les utilisateurs peuvent remplacer le sous-système de mémoire (malloc, calloc, realloc, free, mallopt et sous-routines mallinfo ) avec un de leur propre conception.

Remarque: Les sous-systèmes de mémoire de remplacement écrits en C++ ne sont pas pris en charge en raison de l'utilisation du sous-système de mémoire libc.a dans la bibliothèque C++ libC.a.

Le sous-système de mémoire existant fonctionne à la fois pour les applications à unités d'exécution et les applications non à unités d'exécution. Le sous-système de mémoire définie par l'utilisateur doit être compatible avec les unités d'exécution de sorte qu'il fonctionne à la fois dans les processus à unités d'exécution et dans les processus non à unités d'exécution. Dans la mesure où il n'y a pas de vérification permettant de vérifier que c'est le cas, si un module de mémoire non autorisant les unités d'exécution multiples est chargé dans une application à unités d'exécution multiples, la mémoire et les données peuvent être altérées.

Les objets 32 et 64 bits du sous-système de mémoire défini par l'utilisateur doivent être placés dans une archive avec l'objet partagé 32 bits nommémem32.oet l'objet partagé 64 bits nommémem64.o.

Les objets partagés par l'utilisateur doivent exporter les symboles suivants:
  • __malloc__
  • __libre __
  • __réallocation __
  • __loc_calle__
  • __info_tous__
  • __mallopt__
  • __init_malloque___
  • __malloc_prefork_lock__
  • __malloc_postfork_unlock__
Les objets partagés par l'utilisateur peuvent éventuellement exporter le symbole suivant:
  • __début_malloque___
  • __posix_memalign__

L'exécution ne s'arrête pas si ces symboles n'existent pas.

Les fonctions sont définies comme suit:
void *__malloc__(size_t):
Cette fonction est l'équivalent utilisateur de la sous-routine malloc .
void __free__(void *):
Cette fonction est l'équivalent utilisateur de la sous-routine free .
void *__realloc__(void *, size_t):
Cette fonction est l'équivalent utilisateur de la sous-routine realloc .
void *__calloc__(size_t, size_t):
Cette fonction est l'équivalent utilisateur de la sous-routine calloc .
int __mallopt__(int, int):
Cette fonction est l'équivalent utilisateur de la sous-routine mallopt .
struct mallinfo __mallinfo__():
Cette fonction est l'équivalent utilisateur de la sous-routine mallinfo .
void __malloc_start__()
Cette fonction est appelée une fois avant tout autre point d'entrée malloc défini par l'utilisateur.
void __posix_memalign__()
Cette fonction est l'équivalent utilisateur de la sous-routine posix_memalign . Si ce symbole n'existe pas, l'exécution ne s'arrête pas, mais un appel à la sous-routine posix_memalign entraîne des résultats inattendus.
Les fonctions suivantes sont utilisées par le sous-système d'unités d'exécution pour gérer le sous-système de mémoire définie par l'utilisateur dans un environnement à unités d'exécution multiples. Ils ne sont appelés que si l'application et/ou le module défini par l'utilisateur sont liés à libpthreads.a. Même si le sous-système défini par l'utilisateur n'admet pas les unités d'exécution multiples et n'est pas lié à libpthreads.a, ces fonctions doivent être définies et exportées. Sinon, l'objet ne sera pas chargé.
void __malloc_init__(void)
Appelé par la routine d'initialisation pthread. Cette fonction permet d'initialiser le sous-système de mémoire utilisateur à unités d'exécution. Dans la plupart des cas, cela inclut la création et l'initialisation d'une forme de verrouillage des données. Même si le module de sous-système de mémoire défini par l'utilisateur est lié à libpthreads.a, le sous-système de mémoire défini par l'utilisateur doit fonctionner avant__malloc_init__()est appelée.
void __malloc_prefork_lock__(void)
Appelée par pthreads lorsque laforkUn sous-programme est appelé. Cette fonction permet de s'assurer que le sous-système de mémoire est dans un état connu avant lafork()et reste ainsi jusqu'à ce quefork()a été renvoyé. Dans la plupart des cas, cela inclut l'acquisition des verrous de sous-système de mémoire.
void __malloc_postfork_unlock__(void)
Appelée par pthreads lorsque laforkUn sous-programme est appelé. Cette fonction est utilisée pour rendre le sous-système de mémoire disponible dans le parent et l'enfant après unfork. Cela devrait annuler le travail effectué par__malloc_prefork_lock__. Dans la plupart des cas, cela inclut la libération des verrous du sous-système de mémoire.
Toutes les fonctions doivent être exportées à partir d'un module partagé. Des modules distincts doivent exister pour les implémentations 32 et 64 bits placées dans une archive. Par exemple :
  • Module mem.exp :
    __malloc__
    __free__
    __realloc__
    __calloc__
    __mallopt__
    __mallinfo__
    __malloc_init__
    __malloc_prefork_lock__
    __malloc_postfork_unlock__
    __malloc_start__
  • Module mem_functions32.o :

    Contient toutes les fonctions 32 bits requises

  • Module mem_functions64.o :

    Contient toutes les fonctions 64 bits requises

Les exemples suivants permettent de créer les objets partagés. :NONE.-lpthreadsest nécessaire uniquement si l'objet utilise des fonctions pthread.
  • Création d'un objet partagé 32 bits:
    ld -b32 -m -o mem32.o mem_functions32.o \
    -bE:mem.exp \
    -bM:SRE -lpthreads -lc
  • Création d'un objet partagé 64 bits:
    ld -b64 -m -o mem64.o mem_functions64.o \
    -bE:mem.exp \
    -bM:SRE -lpthreads -lc
  • Création de l'archive (le nom des objets partagés doit êtremem32.opour l'objet 32bit etmem64.opour l'objet 64bit ):
     ar -X32_64 -r archive_name mem32.o mem64.o

Activation du sous-système de mémoire définie par l'utilisateur

Le sous-système de mémoire définie par l'utilisateur peut être activé à l'aide de l'une des options suivantes:
  • Variable d'environnement MALLOCTYPE
  • :NONE._malloc_user_defined_namevariable globale dans l'application de l'utilisateur

Pour utiliser la variable d'environnement MALLOCTYPE , l'archive contenant le sous-système de mémoire défini par l'utilisateur est spécifiée en définissant MALLOCTYPE suruser:archive_namearchive_name se trouve dans l'applicationlibpathou le chemin est spécifié dans la variable d'environnement LIBPATH .

Pour utiliser le_malloc_user_defined_namevariable globale, l'application de l'utilisateur doit déclarer la variable globale comme suit:
char *_malloc_user_defined_name="archive_name"

archive_name doit se trouver dans le chemin d'accès à la bibliothèque de l'application ou dans un chemin spécifié dans la variable d'environnement LIBPATH .

Remarque :
  1. Lorsqu'une application setuid est exécutée, la variable d'environnement LIBPATH est ignorée de sorte que l'archive doit se trouver dans le chemin d'accès à la bibliothèque de l'application.
  2. archive_name ne peut pas contenir d'informations de chemin.
  3. Lorsque la variable d'environnement MALLOCTYPE et la variable d'environnement_malloc_user_defined_nameLes variables globales sont utilisées pour spécifier archive_name, l'archive spécifiée par MALLOCTYPE remplacera celle spécifiée par_malloc_user_defined_name.

Remarques sur les versions 32 bits et 64 bits

Si l'archive ne contient pas à la fois les objets partagés 32 bits et 64 bits et que le sous-système de mémoire définie par l'utilisateur a été activé à l'aide de la variable d'environnement MALLOCTYPE , des problèmes se produisent lors de l'exécution de processus 64 bits à partir d'applications 32 bits et de processus 32 bits à partir d'applications 64 bits. Lorsqu'un nouveau processus est créé à l'aide de la sous-routine exec , le processus hérite de l'environnement de l'application appelante. Cela signifie que la variable d'environnement MALLOCTYPE sera héritée et que le nouveau processus tentera de charger le sous-système de mémoire défini par l'utilisateur. Si le membre d'archivage n'existe pas pour ce type de programme, le chargement échoue et le nouveau processus se ferme.

Remarques relatives aux unités d'exécution

Toutes les fonctions fournies doivent fonctionner dans un environnement à unités d'exécution multiples. Même si le module est lié à libpthreads.a, au moins__malloc__()doit fonctionner avant__malloc_init__()est appelé et pthreads est initialisé. Cette opération est obligatoire car l'initialisation de pthread requiertmalloc()avant__malloc_init__()est appelée.

Toutes les fonctions de mémoire fournies doivent fonctionner dans des environnements à unités d'exécution et non à unités d'exécution. :NONE.__malloc__()La fonction doit pouvoir s'exécuter jusqu'à la fin sans avoir de dépendances sur__malloc_init__()(c'est-à-dire,__malloc__()doit d'abord supposer que__malloc_init__()n'a pas encore été exécuté.) Après__malloc_init__()a terminé,__malloc__()peut s'appuyer sur n'importe quel travail effectué par__malloc_init__(). Cette opération est requise car l'initialisation de pthread utilisemalloc()avant__malloc_init__()est appelée.

Les variables suivantes sont fournies pour empêcher l'appel de routines liées à des unités d'exécution inutiles:
  • :NONE.__multi_threadedla variable est nulle jusqu'à ce qu'une unité d'exécution soit créée lorsqu'elle devient différente de zéro et ne sera pas remise à zéro pour ce processus.
  • :NONE.__n_pthreadsla variable est-1jusqu'à ce que pthreads ait été initialisé lorsqu'il est défini sur1. A partir de ce point, il y a un comptage du nombre d'unités d'exécution actives.

Exemple :

Plus__malloc__()Utilisationspthread_mutex_lock(), le code peut ressembler à ce qui suit:

if (__multi_threaded)
pthread_mutex_lock(mutexptr);

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

if (__multi_threaded)
pthread_mutex_unlock(mutexptr);

Dans cet exemple,__malloc__()n'est pas en mesure d'exécuter les fonctions pthread avant que pthreads ne soit complètement initialisé. Les applications à unité d'exécution unique sont également accélérées car le verrouillage n'est pas effectué tant qu'une deuxième unité d'exécution n'est pas démarrée.

Restrictions

Les sous-systèmes de mémoire écrits en C++ ne sont pas pris en charge en raison de l'initialisation et des dépendances de libC.a et du sous-système de mémoire libc.a .

Les messages d'erreur ne sont pas traduits car la sous-routine setlocale utilisemalloc()pour initialiser les environnements locaux. Plusmalloc()échoue, la sous-routine setlocale ne peut pas se terminer et l'application est toujours dans laPOSIXEnvironnement local. Par conséquent, seuls les messages en anglais par défaut seront affichés.

Les programmes existants générés de manière statique ne peuvent pas utiliser le sous-système de mémoire défini par l'utilisateur sans recompilation.

Génération de rapports d'erreurs

La première fois que la sous-routine malloc est appelée, l'objet 32 ou 64 bits de l'archive spécifiée par la variable d'environnement MALLOCTYPE est chargé. Si le chargement échoue, un message s'affiche et l'application se ferme. Si le chargement aboutit, une tentative est effectuée pour vérifier que tous les symboles requis sont présents. Si des symboles sont manquants, l'application est arrêtée et la liste des symboles manquants s'affiche.