mmap
Table des matières
Retour à l'index
NOM
mmap, munmap - Établir/supprimer une projection en mémoire (map/unmap) des
fichiers ou des périphériques
BIBLIOTHÈQUE
Bibliothèque C standard (libc, -lc)
SYNOPSIS
#include <sys/mman.h>
void *mmap(void addr[.length], size_t length, int prot, int flags,
int fd, off_t offset);
int munmap(void addr[.length], size_t length);
Consultez la section NOTES pour plus d'informations sur les exigences de la
macro de test de fonctionnalité.
DESCRIPTION
mmap() crée une nouvelle projection dans l'espace d'adressage virtuel du
processus appelant. L'adresse de démarrage de la nouvelle projection est
indiquée dans addr. Le paramètre length indique la longueur de la
projection (qui doit être supérieure à 0).
Si addr est NULL, le noyau choisit l'adresse (alignée sur une page) à
laquelle démarrer la projection ; c'est la méthode la plus portable pour
créer une nouvelle projection. Si addr n'est pas NULL, le noyau le
considère comme une indication sur l'endroit où placer la projection ; sous
Linux, elle sera placée à une frontière de page proche (mais toujours
supérieure ou égale à la valeur indiquée par /proc/sys/vm/mmap_min_addr)
et tente d'y créer la projection. Si une projection y existe déjà, le noyau
prend une nouvelle adresse qui peut ou pas dépendre de
l'indication. L'adresse de la nouvelle projection est renvoyée comme
résultat de l'appel.
Le contenu d'une projection de fichier (par opposition à une projection
anonyme ; voir ci-dessous MAP_ANONYMOUS) est initialisé avec length
octets à partir de la position offset dans le fichier (ou autre objet)
correspondant au descripteur de fichier fd. offset doit être un
multiple de la taille de la page renvoyée par sysconf(_SC_PAGE_SIZE).
Après le retour de l'appel mmap(), le descripteur de fichier fd peut
être fermé immédiatement sans invalider la projection.
L'argument prot indique la protection que l'on désire pour cette zone de
mémoire et ne doit pas entrer en conflit avec le mode d'ouverture du
fichier. Il s'agit soit de PROT_NONE (le contenu de la mémoire est
inaccessible) soit d'un OU binaire entre les constantes suivantes :
- PROT_EXEC
-
Il est possible d'exécuter les pages.
- PROT_READ
-
Il est possible de lire les pages.
- PROT_WRITE
-
Il est possible d'écrire les pages.
- PROT_NONE
-
Il n'est pas possible d'accéder aux pages.
Le paramètre des attributs
Le paramètre flags détermine si les modifications de la projection sont
visibles depuis les autres processus projetant la même région et si les
modifications sont appliquées au fichier sous-jacent. Ce comportement est
déterminé en incluant exactement une des valeurs suivantes dans flags :
- MAP_SHARED
-
Partager la projection. Les modifications de la projection sont visibles
dans les autres processus qui projettent la même région et (en cas de
projection file-backed) elles sont appliquées au fichier sous-jacent (pour
contrôler précisément le moment des mises à jour du fichier sous-jacent, il
faut utiliser msync(2)).
- MAP_SHARED_VALIDATE (depuis Linux 4.15)
-
Cet attribut apporte le même comportement que MAP_SHARED sauf que les
projections MAP_SHARED ignorent les attributs inconnus dans flags. Au
contraire, lors de la création d'une projection en utilisant
MAP_SHARED_VALIDATE, le noyau vérifie que tous les attributs passés sont
connus et il fait échouer la projection avec l'erreur EOPNOTSUPP pour les
attributs inconnus. Ce type de projection est aussi nécessaire pour pouvoir
utiliser certains attributs de projection (comme MAP_SYNC).
- MAP_PRIVATE
-
Créer une projection privée, utilisant la méthode de copie à l'écriture. Les
modifications de la projection ne sont pas visibles depuis les autres
processus projetant le même fichier, et ne modifient pas le fichier
lui-même. Il n'est pas précisé si les changements effectués dans le fichier
après l'appel mmap() seront visibles dans la région projetée.
MAP_SHARED et MAP_PRIVATE sont décrits dans POSIX.1-2001 et
POSIX.1-2008. MAP_SHARED_VALIDATE est une extension Linux.
De plus, zéro ou plus des valeurs suivantes peuvent être incluses dans
flags (avec un OU binaire) :
- MAP_32BIT (depuis Linux 2.4.20, 2.6)
-
Placer la projection dans les deux premiers gigaoctets de l'espace
d'adressage du processus. Cet attribut n'est pris en charge que sous x86-64,
pour les programmes 64 bits. Il a été ajouté pour permettre à la pile d'un
fil d'exécution d'être allouée dans les deux premiers gigaoctets de mémoire,
afin d'améliorer les performances des changements de contexte sur les
premiers processeurs 64 bits. Les processeurs x86-64 modernes n'ont plus ces
problèmes de performance, donc l'utilisation de cet attribut n'est pas
nécessaire sur ces systèmes. L'attribut MAP_32BIT est ignoré quand
MAP_FIXED est positionné.
- MAP_ANON
-
Synonyme de MAP_ANONYMOUS ; fourni pour une compatibilité avec d'autres
implémentations.
- MAP_ANONYMOUS
-
La projection n'est prise en charge par aucun fichier ; son contenu est
initialisé à 0. L'argument fd est ignoré ; cependant, certaines
implémentations demandent que fd soit -1 si MAP_ANONYMOUS (ou
MAP_ANON) est utilisé, et les applications portables doivent donc s'en
assurer. L'argument offset devrait être 0. La prise en charge de
MAP_ANONYMOUS avec MAP_SHARED a été ajoutée dans Linux 2.4.
- MAP_DENYWRITE
-
Cet attribut est ignoré (autrefois — Linux 2.0 et antérieur — il signalait
une tentative d'écriture dans le fichier sous-jacent et qui échouait avec
l'erreur ETXTBUSY. Mais cela permettait des attaques par déni de
service).
- MAP_EXECUTABLE
-
Cet attribut est ignoré.
- MAP_FILE
-
Attribut pour compatibilité. Ignoré.
- MAP_FIXED
-
Ne pas considérer addr comme une indication : n'utiliser que l'adresse
indiquée. addr doit être correctement alignée : pour la plupart des
architectures, un multiple de la taille de page suffit, toutefois certaines
architectures imposent des limitations supplémentaires. Si la zone mémoire
indiquée par addr et length recouvre des pages d'une projection
existante, la partie recouverte de la projection existante sera ignorée. Si
l'adresse indiquée ne peut être utilisée, mmap() échouera.
-
Les logiciels qui aspirent à la portabilité devraient utiliser l'attribut
MAP_FIXED prudemment, en gardant à l'esprit que l'aspect exact des
projections de mémoire du processus est autorisé à changer significativement
entre les versions de Linux, de la glibc et du système
d'exploitation. Lisez attentivement le point sur cet attribut dans les NOTES !
- MAP_FIXED_NOREPLACE (depuis Linux 4.17)
-
Cet attribut offre un comportement identique à MAP_FIXED par rapport à
l'application de addr, mais il s'en distingue en ce que
MAP_FIXED_NOREPLACE n’écrase jamais une plage projetée existante. Si la
plage demandée entre en conflit avec une projection existante, cet appel
échoue avec l'erreur EEXIST. Cet attribut peut donc être utilisé comme
une façon d'essayer de projeter une plage d'adresses de manière atomique
(vis-à-vis d'autres fils d'exécutions) : un thread réussira, tous les autres
signaleront un échec.
-
Remarquez que les anciens noyaux qui ne reconnaissent pas l'attribut
MAP_FIXED_NOREPLACE se rabattront généralement (en détectant une
collision avec une projection existante) sur un type de comportement « sans
MAP_FIXED » : ils renverront une adresse différente de celle
demandée. Les logiciels rétro-compatibles devront donc vérifier l'adresse
renvoyée vis-à-vis de l'adresse demandée.
- MAP_GROWSDOWN
-
Cet attribut est utilisé pour les piles. Il indique au noyau le système de
mémoire virtuelle vers lequel la projection devrait descendre dans la
mémoire. L'adresse renvoyée est une page inférieure à la zone de mémoire
créée dans l'espace d'adressage virtuel du processus. La modification d'une
adresse dans la page de « garde » sous la projection fera agrandir la
projection d’une page. Cette croissance peut se répéter jusqu'à ce que la
taille de la projection dans la page atteigne l’extrémité haute de la
projection plus basse suivante, point où la modification de la page de
« garde » donnera un signal SIGSEGV.
- MAP_HUGETLB (depuis Linux 2.6.32)
-
Allouer la projection à l'aide de « pages immenses ». Consultez le fichier
Documentation/vm/hugetlbpage.txt des sources du noyau Linux pour plus
d'informations ainsi que les NOTES ci-dessous.
- MAP_HUGE_2MB
-
MAP_HUGE_1GB (depuis Linux 3.8)
Utilisé avec MAP_HUGETLB pour sélectionner d'autres tailles de pages
immenses (hugetlb) (respectivement 2 Mo et 1 Go) sur les systèmes qui gèrent
plusieurs tailles de page hugetlb.
-
Plus généralement, la taille de la page immense souhaitée peut être
configurée en encodant le logarithme de base 2 de la taille de la page
désirée dans les six bits situés sur MAP_HUGE_SHIFT (une valeur de zéro
dans ce champ de bit fournit la taille de page immense par défaut ; vous
pouvez connaître celle-ci à l'aide du champ Hugepagesize qui apparaît
dans /proc/meminfo). Ainsi, les deux constantes ci-dessus sont définies
comme suit :
-
#define MAP_HUGE_2MB (21 << MAP_HUGE_SHIFT)
#define MAP_HUGE_1GB (30 << MAP_HUGE_SHIFT)
-
Vous pouvez connaître l'intervalle de tailles des pages immenses gérées par
le système en listant les sous-répertoires de /sys/kernel/mm/hugepages.
- MAP_LOCKED (depuis Linux 2.5.37)
-
Marquer la région projetée pour qu'elle soit verrouillée de la même manière
que mlock(2). Cette implémentation essaiera de remplir (prefault) toute
la plage mais l'appel mmap() n’échouera pas avec ENOMEM si cela
échoue. Des erreurs énormes pourraient donc se produire ultérieurement. La
sémantique n'est donc pas aussi robuste que mlock(2). Vous devriez
utiliser mmap() et mlock(2) si d'énormes erreurs ne sont pas
acceptables après l'initialisation de la projection. L'attribut
MAP_LOCKED est ignoré sur les anciens noyaux.
- MAP_NONBLOCK (depuis Linux 2.5.46)
-
Cet attribut n'a de sens qu'en conjonction avec MAP_POPULATE. Ne pas
effectuer de lecture anticipée : créer seulement les entrées de tables de
page pour les pages déjà présentes en RAM. Depuis Linux 2.6.23, cet attribut
fait que MAP_POPULATE n'a aucun effet. Un jour la combinaison de
MAP_POPULATE et MAP_NONBLOCK pourra être implémentée de nouveau.
- MAP_NORESERVE
-
Ne pas réserver d'espace de swap pour les pages de cette projection. Une
telle réservation garantit que l'on puisse modifier les zones soumises à une
copie-en-écriture. Sans réservation, on peut recevoir un signal SIGSEGV
durant une écriture, s'il n'y a plus de place disponible. Consultez
également la description du fichier /proc/sys/vm/overcommit_memory dans
la page proc(5). Avant Linux 2.6, cet attribut n'avait d'effet que pour
les projections privées modifiables.
- MAP_POPULATE (depuis Linux 2.5.46)
-
Remplir (prefault) les tables de pages pour une projection. Pour une
projection de fichier, cela provoque une lecture anticipée du fichier. Les
accès ultérieurs à la projection ne seront pas bloqués par des erreurs de
pages. L'appel mmap n'échoue pas si la projection ne peut pas être
remplie (par exemple à cause de limitation sur le nombre de pages immenses
mappées lors de l'utilisation de MAP_HUGETLB). La prise en charge de
MAP_POPULATE avec les projections privées a été ajoutée dans
Linux 2.6.23.
- MAP_STACK (depuis Linux 2.6.27)
-
Allouer la projection à une adresse qui convient à la pile d'un processus ou
d'un thread.
-
Cet attribut n'est pas opérationnel pour l'instant sur Linux. Mais son
utilisation permet aux applications de s'assurer qu'elles le gèreront de
manière transparente s'il est implémenté dans le futur. Ainsi, il est
utilisé dans l'implémentation de threading de la glibc pour accepter le fait
que certaines architectures pourront (plus tard) nécessiter un traitement
spécial pour allouer des piles. Une autre raison d'utiliser cet attribut est
la portabilité : MAP_STACK existe et a un effet sur d'autres systèmes
(comme certains BSD).
- MAP_SYNC (depuis Linux 4.15)
-
Cet attribut n'est possible qu'avec le type de projection
MAP_SHARED_VALIDATE ; les projections de type MAP_SHARED ignoreront
silencieusement cet attribut. Il n'est pris en charge que pour des fichiers
gérant le DAX (projection directe de mémoire persistante). Pour les autres
fichiers, créer une projection avec cet attribut provoquera une erreur
EOPNOTSUPP.
-
Les projections de fichier partagé ayant cet attribut fournissent une
garantie que tant que la mémoire est projetée avec accès en écriture dans
l'espace d'adressage du processus, elle sera visible dans le même fichier et
au même endroit même après un plantage ou un redémarrage du système. Couplé
à l'utilisation des instructions adéquates du processeur, cela offre aux
utilisateurs de telles projections une manière plus efficace de rendre des
modifications de données persistantes.
- MAP_UNINITIALIZED (depuis Linux 2.6.33)
-
Ne pas effacer pas les pages anonymes. Cet attribut n'a pour l'instant un
effet que si le noyau a été configuré avec l'option
CONFIG_MMAP_ALLOW_UNINITIALIZED. À cause des implications sur la
sécurité, cette option n'est normalement active que sur des périphériques
embarqués (c'est-à-dire avec des périphériques avec lesquels il est possible
d'avoir un contrôle total de la mémoire utilisateur).
Parmi les attributs ci-dessus, seul MAP_FIXED est spécifié dans
POSIX.1-2001 et POSIX.1-2008. Cependant, la plupart des systèmes gèrent
aussi MAP_ANONYMOUS (ou son synonyme MAP_ANON).
munmap()
L'appel système munmap() détruit la projection dans la zone de mémoire
spécifiée et s'arrange pour que toute référence ultérieure à cette zone
mémoire déclenche une erreur d'adressage. La projection est aussi
automatiquement détruite lorsque le processus se termine. À l'inverse, la
fermeture du descripteur de fichier ne supprime pas la projection.
L'adresse addr doit être un multiple de la taille de la page (mais ce
n'est pas obligatoire pour length). Toutes les pages contenant une partie
de l'intervalle indiqué sont libérées, et tout accès ultérieur déclenchera
SIGSEGV. Aucune erreur n'est détectée si l'intervalle indiqué ne contient
pas de page projetée.
VALEUR RENVOYÉE
En cas de succès, mmap() renvoie un pointeur sur la zone projetée. En cas
d'échec, la valeur MAP_FAILED (c'est-à-dire (void *) -1) est
renvoyée et errno est défini pour indiquer l'erreur.
S'il réussit, munmap() renvoie 0. En cas d'échec, -1 est renvoyé et
errno est défini pour indiquer l'erreur (probablement EINVAL).
ERREURS
- EACCES
-
Le descripteur ne correspond pas à un fichier normal ou une demande de
projection de fichier a été demandée mais fd n'est pas ouvert en lecture,
ou une demande de projection partagée MAP_SHARED avec protection
PROT_WRITE a été demandée mais fd n'est pas ouvert en lecture et
écriture (O_RDWR), ou encore PROT_WRITE est demandé mais le fichier
est ouvert en ajout seulement.
- EAGAIN
-
Le fichier est verrouillé ou trop de pages ont été verrouillées en mémoire
(consultez setrlimit(2)).
- EBADF
-
fd n'est pas un descripteur de fichier valable (et MAP_ANONYMOUS
n'était pas précisé).
- EEXIST
-
MAP_FIXED_NOREPLACE était indiqué dans flags et la plage couverte par
addr et length est en conflit avec une projection existante.
- EINVAL
-
addr ou length ou offset sont non valables (par exemple : zone
trop grande, ou non alignée sur une frontière de page).
- EINVAL
-
(depuis Linux 2.6.12) length est nul.
- EINVAL
-
flags ne contenait ni MAP_PRIVATE, ni MAP_SHARED, ni
MAP_SHARED_VALIDATE.
- ENFILE
-
La limite du nombre total de fichiers ouverts pour le système entier a été
atteinte.
- ENODEV
-
Le système de fichiers sous-jacent ne gère pas la projection en mémoire.
- ENOMEM
-
Aucune mémoire disponible.
- ENOMEM
-
Le nombre maximal de projections du processus serait dépassé. Cette erreur
peut aussi se produire pour munmap() lors de la suppression d'une
projection d'une région au milieu d'une projection existante, puisque cela
provoque deux régions plus petites de chaque côté de la région à supprimer.
- ENOMEM
-
(Depuis Linux 4.7) La limite RLIMIT_DATA du processus, décrite dans
getrlimit(2), serait dépassée.
- ENOMEM
-
addr n'est pas apprécié parce qu'il dépasse l'espace d'adressage virtuel
du processeur
- EOVERFLOW
-
Sur architecture 32 bits avec l'extension de fichiers très grands
(c'est-à-dire utilisant un off_t sur 64 bits) : le nombre de pages
utilisées pour length plus le nombre de pages utilisées pour offset
dépasserait unsigned long (32 bits).
- EPERM
-
L'argument prot a demandé PROT_EXEC mais la zone appartient à un
fichier sur un système de fichiers monté sans permission d'exécution.
- EPERM
-
La lecture a été interrompue par un signal ; consultez fnctl(2).
- EPERM
-
L'attribut MAP_HUGETLB était indiqué, mais l'appelant n'était pas
priviliégié (il n'avait pas la capacité CAP_IPC_LOCK) et n'est pas membre
du groupe sysctl_hugetlb_shm_group ; voir la desription de
/proc/sys/vm/sysctl_hugetlb_shm_group dans proc_sys(5).
- ETXTBSY
-
MAP_DENYWRITE a été réclamé mais fd est ouvert en écriture.
L'accès à une zone de projection peut déclencher les signaux suivants :
- SIGSEGV
-
Tentative d'écriture dans une zone en lecture seule.
- SIGBUS
-
Tentative d'accès à une page du tampon au-delà de la fin du fichier
projeté. Pour une explication du traitement des octets dans la page
correspondant à la fin du fichier projeté n'étant pas un multiple de la
taille de la page, voir les NOTES.
ATTRIBUTS
Pour une explication des termes utilisés dans cette section, consulter
attributes(7).
| Interface | Attribut | Valeur
|
|
mmap(),
munmap()
| Sécurité des threads | MT-Safe
|
VERSIONS
Sur certaines architectures matérielles (par exemple, i386), PROT_WRITE
implique PROT_READ. Cela dépend de l'architecture si PROT_READ
implique PROT_EXEC ou non. Les programmes portables doivent toujours
indiquer PROT_EXEC s'ils veulent exécuter du code dans la projection.
La manière portable de créer une projection est de spécifier addr à 0
(NULL), et d'omettre MAP_FIXED dans flags. Dans ce cas, le système
choisit l'adresse de la projection ; l'adresse est choisie de manière à ne
pas entrer en conflit avec une projection existante et de ne pas être
nulle. Si l'attribut MAP_FIXED est indiqué et si addr vaut 0 (NULL),
l'adresse projetée sera zéro (NULL).
Certaines constantes de flags sont définies seulement si des macros de
test de fonctionnalités adaptées sont définies (potentiellement par
défaut) : _DEFAULT_SOURCE avec la glibc 2.19 ou supérieure, ou bien
_BSD_SOURCE ou _SVID_SOURCE dans la glibc 2.19 et antérieure (la
définition de _GNU_SOURCE suffit également, et son usage aurait été plus
logique, puisque ces attributs sont tous spécifiques à Linux). Les attributs
adéquats sont : MAP_32BIT, MAP_ANONYMOUS (et son synonyme
MAP_ANON), MAP_DENYWRITE, MAP_EXECUTABLE, MAP_FILE,
MAP_GROWSDOWN, MAP_HUGETLB, MAP_LOCKED, MAP_NONBLOCK,
MAP_NORESERVE, MAP_POPULATE, et MAP_STACK.
Différences entre bibliothèque C et noyau
Cette page décrit l'interface fournie par la fonction mmap() de la
glibc. Initialement, cette fonction appelait un appel système du même
nom. Depuis Linux 2.4, cet appel système a été remplacé par mmap2(2). De
nos jours, la fonction mmap() de la glibc appelle mmap2(2) avec la
bonne valeur pour offset.
STANDARDS
POSIX.1-2008.
HISTORIQUE
POSIX.1-2001, SVr4, 4.4BSD.
Sur les systèmes POSIX sur lesquels mmap(), msync(2) et munmap()
sont disponibles, _POSIX_MAPPED_FILES est définie dans
<unistd.h> comme étant une valeur supérieure à 0 (consultez
aussi sysconf(3)).
NOTES
La mémoire obtenue par mmap est préservée au travers d'un fork(2),
avec les mêmes attributs.
Un fichier est projeté en multiples de de la taille de la page. Pour un
fichier dont la longueur n'est pas un multiple de la taille de page, la
mémoire restante est remplie de zéros lors de la projection, et les
écritures dans cette zone n'affectent pas le fichier. Les effets de la
modification de la taille du fichier sous-jacent sur les pages
correspondant aux zones ajoutées ou supprimées ne sont pas précisés.
Une application peut déterminer les pages d'une projection se trouvant dans
le tampon/le cache de page en utilisant mincore(2).
Utilisation sûre de MAP_FIXED
La seule utilisation sûre de MAP_FIXED est quand la plage d'adresses
indiquée par addr et length a été préalablement réservée en utilisant
une autre projection ; sans quoi l'utilisation de MAP_FIXED est
hasardeuse car elle supprime brutalement des projections préexistantes, ce
qui facilite la corruption par un processus multithread de son propre espace
d'adressage.
Par exemple, supposons qu'un thread A cherche dans /proc/pid/maps une
plage d'adresses inutilisée où il peut se projeter en utilisant
MAP_FIXED, tandis qu'un thread B acquiert en même temps tout ou partie de
cette même plage d'adresses. Quand le thread A utilisera ensuite
mmap(MAP_FIXED), il va de fait écraser la projection créée par le thread
B. Dans ce scénario, le thread B ne doit pas créer de projection
directement ; un appel de bibliothèque qui, en interne, utilise dlopen(3)
pour charger d'autres bibliothèques partagées, est suffisant. L'appel
dlopen(3) projettera la bibliothèque dans l'espace d'adressage du
processus. De plus, presque tous les appels de bibliothèques peuvent être
implémentés d'une manière qui ajoute des projections de mémoire aux espaces
d'adressage, à l'aide de cette technique ou en allouant simplement de la
mémoire. Parmi les exemples, figurent brk(2), malloc(3),
pthread_create(3) et les bibliothèques PAM
Depuis Linux 4.17, un programme multithreadé peut utiliser l'attribut
MAP_FIXED_NOREPLACE pour éviter le risque décrit ci-dessus quand on
essaie de créer une projection à une adresse fixe non réservée par une
projection préexistante.
Modifications d'horodatage pour les projections prises en charge par un fichier
Pour les projections prises en charge par un fichier, le champ st_atime
du fichier peut être mis à jour à tout moment entre l'appel mmap() et le
munmap() correspondant. Le premier accès dans la page projetée mettra le
champ à jour si cela n'a pas été déjà fait.
Les champs st_ctime et st_mtime pour un fichier projeté avec
PROT_WRITE et MAP_SHARED seront mis à jour après une écriture dans la
région projetée, et avant l'éventuel msync(2) suivant avec l'attribut
MS_SYNC ou MS_ASYNC.
Projections de pages immenses (Huge TLB)
Pour les projections qui utilisent des pages immenses, les exigences des
attributs de mmap() et de munmap() diffèrent quelque peu de celles
pour des projections qui utilisent la taille native des pages du système.
Pour mmap(), offset doit être un multiple de la taille de la page
immense sous-jacente. Le système aligne automatiquement length pour qu'il
soit un multiple de la taille de la page immense sous-jacente.
Pour munmap(), addr et length doivent être tous deux un multiple de
la taille de la page immense sous-jacente.
BOGUES
Sous Linux, il n'y a aucune garantie comme celles indiquées plus haut à
propos de MAP_NORESERVE. Par défaut, n'importe quel processus peut être
tué à tout moment lorsque le système n'a plus de mémoire.
Avant Linux 2.6.7, l'attribut MAP_POPULATE n'avait d'effet que si prot
était PROT_NONE.
SUSv3 indique que mmap() devrait échouer si length est 0. Cependant,
avant Linux 2.6.12, mmap() réussissait dans ce cas : aucune projection
n'était créée, et l'appel renvoyait addr. Depuis Linux 2.6.12, mmap()
échoue avec le code d'erreur EINVAL si length est nul.
POSIX spécifie que le système devrait toujours remplir de zéros toutes les
pages incomplètes à la fin de l'objet et que le système n'écrira jamais de
modification de l'objet au-delà de sa fin. Sous Linux, lors de l'écriture de
données vers ce genre de pages incomplètes après la fin de l'objet, les
données restent dans le cache de page même après que le fichier soit fermé
et déprojeté, et même si les données ne sont jamais écrites vers le fichier
lui-même, les projections suivantes pourraient voir le contenu modifié. Dans
certains cas, cela pourrait être corrigé en appelant msync(2) avant la
déprojection. Cependant, cela ne fonctionne pas sur tmpfs(5) (par exemple
en utilisant l'interface de mémoire partagée POSIX documentée dans
shm_overview(7)).
EXEMPLES
Le programme suivant affiche la partie du fichier, précisé par le premier
argument de la ligne de commande, sur la sortie standard. Les octets qui
seront affichés sont précisés à partir d'un offset (déplacement) et d'une
longueur en deuxième et troisième paramètre. Le code fait une projection
mémoire des pages nécessaires du fichier puis utilise write(2) pour
afficher les octets voulus.
Source du programme
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#define handle_error(msg) \
do { perror(msg); exit(EXIT_FAILURE); } while (0)
int
main(int argc, char *argv[])
{
int fd;
char *addr;
off_t offset, pa_offset;
size_t length;
ssize_t s;
struct stat sb;
if (argc < 3 || argc > 4) {
fprintf(stderr, "%s position du fichier [longueur]\n", argv[0]);
exit(EXIT_FAILURE);
}
fd = open(argv[1], O_RDONLY);
if (fd == -1)
handle_error("open");
if (fstat(fd, &sb) == -1) /* To obtain file size */
handle_error("fstat");
offset = atoi(argv[2]);
pa_offset = offset & ~(sysconf(_SC_PAGE_SIZE) - 1);
/* la position de mmap() doit être alignée sur la page */
if (offset >= sb.st_size) {
fprintf(stderr, "la position est au-delà de la fin du fichier\n");
exit(EXIT_FAILURE);
}
if (argc == 4) {
length = atoi(argv[3]);
if (offset + length > sb.st_size)
length = sb.st_size - offset;
/* Ne peut pas afficher d'octets situés après la fin du fichier */
} else { /* Pas d'affichage de longueur arg ==> à la fin du fichier */
length = sb.st_size - offset;
}
addr = mmap(NULL, length + offset - pa_offset, PROT_READ,
MAP_PRIVATE, fd, pa_offset);
if (addr == MAP_FAILED)
handle_error("mmap");
s = write(STDOUT_FILENO, addr + offset - pa_offset, length);
if (s != length) {
if (s == -1)
handle_error("write");
fprintf(stderr, "écriture partielle");
exit(EXIT_FAILURE);
}
munmap(addr, length + offset - pa_offset);
close(fd);
exit(EXIT_SUCCESS);
}
VOIR AUSSI
ftruncate(2), getpagesize(2), memfd_create(2), mincore(2),
mlock(2), mmap2(2), mprotect(2), mremap(2), msync(2),
remap_file_pages(2), setrlimit(2), shmat(2), userfaultfd(2),
shm_open(3), shm_overview(7)
Dans proc(5), les descriptions des fichiers : /proc/pid/maps,
/proc/pid/map_files et /proc/pid/smaps.
B.O. Gallmeister, POSIX.4, O'Reilly, p. 128-129 et 389-391.
TRADUCTION
La traduction française de cette page de manuel a été créée par
Christophe Blaess <https://www.blaess.fr/christophe/>,
Stéphan Rafin <stephan.rafin@laposte.net>,
Thierry Vignaud <tvignaud@mandriva.com>,
François Micaux,
Alain Portal <aportal@univ-montp2.fr>,
Jean-Philippe Guérard <fevrier@tigreraye.org>,
Jean-Luc Coulon (f5ibh) <jean-luc.coulon@wanadoo.fr>,
Julien Cristau <jcristau@debian.org>,
Thomas Huriaux <thomas.huriaux@gmail.com>,
Nicolas François <nicolas.francois@centraliens.net>,
Florentin Duneau <fduneau@gmail.com>,
Simon Paillard <simon.paillard@resel.enst-bretagne.fr>,
Denis Barbier <barbier@debian.org>,
David Prévot <david@tilapin.org>
et
Jean-Philippe MENGUAL <jpmengual@debian.org>
Cette traduction est une documentation libre ; veuillez vous reporter à la
GNU General Public License version 3
concernant les conditions de copie et
de distribution. Il n'y a aucune RESPONSABILITÉ LÉGALE.
Si vous découvrez un bogue dans la traduction de cette page de manuel,
veuillez envoyer un message à
Index
- NOM
-
- BIBLIOTHÈQUE
-
- SYNOPSIS
-
- DESCRIPTION
-
- Le paramètre des attributs
-
- munmap()
-
- VALEUR RENVOYÉE
-
- ERREURS
-
- ATTRIBUTS
-
- VERSIONS
-
- Différences entre bibliothèque C et noyau
-
- STANDARDS
-
- HISTORIQUE
-
- NOTES
-
- Utilisation sûre de MAP_FIXED
-
- Modifications d'horodatage pour les projections prises en charge par un fichier
-
- Projections de pages immenses (Huge TLB)
-
- BOGUES
-
- EXEMPLES
-
- Source du programme
-
- VOIR AUSSI
-
- TRADUCTION
-
This document was created by
man2html,
using the manual pages.
Time: 05:06:20 GMT, September 19, 2025