Share via


Octets de mise en mémoire fantôme AddressSanitizer

Nous récapitulons brièvement le concept d’octets d’ombre et la façon dont ils peuvent être utilisés par l’implémentation runtime de /fsanitize=address. Pour plus d’informations, nous vous référons au document séminal et à l’algorithme AddressSanitizer.

Concept de base

Chaque 8 octets de l’espace d’adressage virtuel de votre application peut être décrit à l’aide d’un octet d’ombre.

Un octet d’ombre décrit le nombre d’octets actuellement accessibles comme suit :

  • 0 signifie tous les 8 octets
  • 1-7 signifie un à sept octets
  • Les nombres négatifs encodent le contexte pour le runtime à utiliser pour les diagnostics de création de rapports.

Légende d’octets d’ombre

Considérez cette légende d’octets d’ombre où tous les nombres négatifs sont définis :

Screenshot of the AddressSanitizer shadow-byte legend.

Mappage : description de votre espace d’adressage

Chaque 8 octets de l’espace d’adressage virtuel de l’application aligné sur « 0 mod-8 » peut être mappé à l’octet d’ombre qui décrit cet emplacement dans l’espace d’adressage virtuel. Ce mappage peut être effectué avec un décalage simple et ajouter.

Sur x86 :

char shadow_byte_value = *((Your_Address >> 3) + 0x30000000)

Sur x64 :

char shadow_byte_value = *((Your_Address >> 3) + _asan_runtime_assigned_offset)

Génération de code - tests

Réfléchissez à la façon dont des octets d’ombre spécifiques peuvent être écrits, soit par le code généré par le compilateur, les données statiques ou le runtime. Ce pseudo-code montre comment il est possible de générer un case activée qui précède toute charge ou magasin :

ShadowAddr = (Addr >> 3) + Offset;
if (*ShadowAddr != 0) {
    ReportAndCrash(Addr);
}

Lors de l’instrumentation d’une référence de mémoire inférieure à 8 octets, l’instrumentation est légèrement plus complexe. Si la valeur d’ombre est positive (ce qui signifie que seuls les premiers k octets du mot de 8 octets sont accessibles), nous devons comparer les 3 derniers bits de l’adresse à k.

ShadowAddr = (Addr >> 3) + Offset;
k = *ShadowAddr;
if (k != 0 && ((Addr & 7) + AccessSize > k)) {
    ReportAndCrash(Addr);
}

Le runtime et le code généré par le compilateur écrivent les octets d’ombre. Ces octets d’ombre autorisent ou révoquent l’accès lorsque les étendues se terminent ou que le stockage est libéré. Les case activée ci-dessus lisent les octets d’ombre qui décrivent les « emplacements » de 8 octets dans l’espace d’adressage de votre application, à un certain moment dans l’exécution du programme. Outre ces case activée générées explicitement, le runtime case activée également des octets d’ombre après qu’il intercepte (ou « hooks ») de nombreuses fonctions dans le CRT.

Pour plus d’informations, consultez la liste des fonctions interceptées.

Définition des octets d’ombre

Le code généré par le compilateur et le runtime AddressSanitizer peuvent écrire des octets d’ombre. Par exemple, le compilateur peut définir des octets d’ombre pour autoriser l’accès de taille fixe aux locaux de pile définis dans une étendue interne. Le runtime peut entourer des variables globales dans la section de données avec des octets d’ombre.

Voir aussi

Vue d’ensemble de AddressSanitizer
Résoudre les problèmes connus liés à AddressSanitizer
Référence de build et de langage AddressSanitizer
Informations de référence sur le runtime AddressSanitizer
Test cloud ou distribué AddressSanitizer
Intégration du débogueur AddressSanitizer
Exemples d’erreur AddressSanitizer