Firefox and Address Sanitizer

Qu'est ce que Address Sanitizer?

Address Sanitizer (ASan) est un détecteur d'erreurs de mémoire rapide qui détecte les bogues libres et hors limites dans les programmes C/C++. Il utilise une instrumentation de compilation pour vérifier toutes les lectures et écritures pendant l'exécution. De plus, la partie runtime remplace les fonctions malloc et free pour vérifier la mémoire allouée dynamiquement. Plus d'informations sur le fonctionnement d'ASan peuvent être trouvées sur le wiki the Address Sanitizer wiki.

Télécharger des versions d'artefacts

Pour les utilisateurs Linux, la façon la plus simple d'obtenir des versions Firefox avec Address Sanitizer est de télécharger une intégration continue comme une compilation de mozilla-central (mise à jour au moins une fois par jour) :

Création de votre version

Si, pour une raison quelconque, vous ne pouvez pas utiliser les binaires pré-compilés mentionnés dans la section précédente (par exemple, vous voulez une compilation non-Linux ou vous devez tester un patch), vous pouvez soit construire Firefox vous-même (voir la section suivante) soit utiliser le try server pour créer la compilation personnalisée pour vous. Pousser pour essayer nécessite l'accès au commit L1. Si vous n'avez pas encore cet accès, vous pouvez en faire la demande (voir Becoming A Mozilla Committer et Mozilla Commit Access Policy pour connaître les exigences). Notez que ce type d'accès est principalement pour les développeurs et autres contributeurs réguliers.

L'arbre contient plusieurs fichiers mozconfig pour créer des versions asan (les fichiers "nightly-asan" créent des versions, tandis que les fichiers "debug-asan" créent des versions debug+opt). Pour les verisons Linux, Le fichier de configuration approprié est utilisé par la cible linux64-asan. Si vous voulez créer une compilation macOS ou Windows, vous devrez copier le fichier de configuration approprié sur la configuration de débogage régulière avant de pousser pour essayer. Par exemple :

cp browser/config/mozconfigs/macosx64/debug-asan browser/config/mozconfigs/macosx64/debug

Vous pouvez ensuite pousser pour essayer de la manière habituelle et, une fois la compilation terminée, télécharger l'artefact de compilation approprié.

Creation de versions locals pour Windows

Sous Windows, ASan n'est supporté que dans les versions 64 bits.

Lancez mach bootstrap pour obtenir un clang-cl mis à jour dans votre répertoire   ~/.mozbuild, puis utilisez la mozconfig suivante :

ac_add_options --target=x86_64-pc-mingw32
ac_add_options --host=x86_64-pc-mingw32

ac_add_options --enable-address-sanitizer
ac_add_options --disable-jemalloc

export CC="clang-cl.exe"
export CXX="clang-cl.exe"

export LDFLAGS="clang_rt.asan_dynamic-x86_64.lib clang_rt.asan_dynamic_runtime_thunk-x86_64.lib"
CLANG_LIB_DIR="$(cd ~/.mozbuild/clang/lib/clang/*/lib/windows && pwd)"
export MOZ_CLANG_RT_ASAN_LIB_PATH="${CLANG_LIB_DIR}/clang_rt.asan_dynamic-x86_64.dll"
export LIB=$LIB:$CLANG_LIB_DIR

Si vous voulez utiliser une autre LLVM (voir les insctruction clang-cl), modifiez CLANG_LIB_DIR comme il convient.

Si vous lancez une version d'ASan sous WinDbg, vous pouvez voir de fausses exceptions de violation d'accès de première chance. Ceux-ci proviennent d'ASan créant des pages de mémoire fantôme à la demande, et peuvent être ignorés. Lancez sxi av pour ignorer ces exceptions. (Vous attraperez toujours les exceptions de violation d'accès de seconde chance si vous vous plantez réellement).

Le LeakSanitizer (LSan) n'est pas supporté sur Windows.

Creation de versions locals sur Linux ou Mac

Construire les pre-requis

LLVM/Clang

L'instrumentation ASan est implémentée en tant que LLVM pass et intégrée dans Clang. Toute version de Clang qui est capable de compiler Firefox a tout ce qu'il faut pour faire une compilation ASAN.

Compilation Firefox

Obtenir les sources

En utilisant cela ou n'importe quelle révision ultérieure, tout ce que vous avez à faire est de vous procurer un clone de mozilla-central.

Ajustement de la configuration de construction

Créez le fichier de configuration mozconfig avec le contenu suivant dans votre répertoire mozilla-central :

# Combined .mozconfig file for ASan on Linux+Mac

mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/objdir-ff-asan

# Adjust this to the number of CPU cores + 2
mk_add_options MOZ_MAKE_FLAGS=-j10

# Enable ASan specific code and build workarounds
ac_add_options --enable-address-sanitizer

# Ensure you set this to your LLVM_HOME path
export LLVM_HOME="/path/to/your/llvm"

# Set CC/CXX based on LLVM_HOME
export CC="$LLVM_HOME/build/bin/clang"
export CXX="$LLVM_HOME/build/bin/clang++"

# This will ensure the symbolizer is packaged with the binary
export LLVM_SYMBOLIZER="$LLVM_HOME/build/bin/llvm-symbolizer"

# Add ASan to our compiler flags
export CFLAGS="-fsanitize=address -Dxmalloc=myxmalloc -fPIC"
export CXXFLAGS="-fsanitize=address -Dxmalloc=myxmalloc -fPIC"

# Additionally, we need the ASan flag during linking. Normally, our C/CXXFLAGS would
# be used during linking as well but there is at least one place in our build where
# our CFLAGS are not added during linking.
# Note: The use of this flag causes Clang to automatically link the ASan runtime :)
export LDFLAGS="-fsanitize=address"

# These three are required by ASan
ac_add_options --disable-jemalloc
ac_add_options --disable-crashreporter
ac_add_options --disable-elf-hack

# Keep symbols to symbolize ASan traces later
export MOZ_DEBUG_SYMBOLS=1
ac_add_options --enable-debug-symbols
ac_add_options --disable-install-strip

# Settings for an opt build (preferred)
# The -gline-tables-only ensures that all the necessary debug information for ASan
# is present, but the rest is stripped so the resulting binaries are smaller.
ac_add_options --enable-optimize="-O2 -gline-tables-only"
ac_add_options --disable-debug

# Settings for a debug+opt build
#ac_add_options --enable-optimize
#ac_add_options --enable-debug

# MacOSX only: Uncomment and adjust this path to match your SDK
# ac_add_options --with-macos-sdk=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.8.sdk

Vous pouvez aussi en avoir besoin, comme on peut le voir dans browser/config/mozconfigs/linux64/nightly-asan (le fichier de configuration utilisé pour les versions d'Addresse Sanitizer utilisées pour les tests automatisés):

# ASan specific options on Linux
ac_add_options --enable-valgrind

Démarrer le processus de compilation

Maintenant vous lancez le processus de compilation en utilisant la commande régulière ./mach build.

Démarrer Firefox

Une fois la compilation terminée, ./mach run s'exécute avec les options habituelles pour s'exécuter dans un débogueur (gdb, lldb, rr, etc.) fonctionnent correctement, tout comme les options --disable-e10s et autres.

Construire uniquement l'interpréteur de commandes JavaScript

Si vous voulez construire uniquement le shell JavaScript au lieu de faire une construction Firefox complète, le script de construction ci-dessous vous aidera probablement à le faire. Exécutez ce script dans le sous-répertoire js/src/ et passez un nom de répertoire comme premier paramètre. La compilation sera alors créée dans un nouveau sous-répertoire portant ce nom.

#! /bin/sh

if [ -z $1 ] ; then
    echo "usage: $0 <dirname>"
elif [ -d $1 ] ; then
    echo "directory $1 already exists"
else
    autoconf2.13
    mkdir $1
    cd $1
    LLVM_ROOT="/path/to/llvm"
    CC="$LLVM_ROOT/build/Release/bin/clang" \
    CXX="$LLVM_ROOT/build/Release/bin/clang++" \
    CFLAGS="-fsanitize=address" \
    CXXFLAGS="-fsanitize=address" \
    LDFLAGS="-fsanitize=address" \
            ../configure --enable-debug --enable-optimize --enable-address-sanitizer --disable-jemalloc
    make -j 8
fi

Obtenir des symboles dans les traces de Sanitizer Address

Par défaut, les traces ASan sont non symbolisées et n'impriment que le binaire/bibliothèque et un décalage mémoire à la place. Pour obtenir des traces plus utiles, contenant des symboles, il y a deux approches.

Utilisation du symbole LLVM (recommandé)

LLVM est livré avec un binaire symboliseur qu' ASan utilisera facilement pour produire immédiatement des traces symbolisées. Pour l'utiliser, il suffit de définir la variable d'environnement  ASAN_SYMBOLIZER_PATH pour refléter l'emplacement de votre binaire llvm-symbolizer, avant d'exécuter le processus. Si vous avez téléchargé un paquet pré-compilé ou fait une compilation d'essai, alors le binaire sera inclus dans l'archive (même emplacement que le binaire firefox). Si vous avez construit ASan vous-même, alors vous voudrez définir la variable à $LLVM_HOME/build/bin/llvm-symbolizer à la place.

Avertissement : Sous OS X, le bac à sable du contenu empêche le symboliseur de fonctionner.  Pour utiliser llvm-symbolizer sur l'affichage  ASan d'un processus de contenu, le sandbox de contenu doit être désactivé. Ceci peut être fait en définissant MOZ_DISABLE_CONTENT_SANDBOX=1 dans votre environnement d'exécution. Le réglage de ce paramètre dans  .mozconfig n'a aucun effet.

Traces de Post-traitement avec asan_symbolize.py

Au lieu d'utiliser le binaire llvm-symbolizer, vous pouvez aussi utiliser le script  asan_symbolize.py, livré avec LLVM ($LLVM_HOME/projects/compiler-rt/lib/asan/scripts/asan_symbolize.py). L'inconvénient est que le script devra utiliser  addr2line pour obtenir les symboles, ce qui signifie que chaque bibliothèque devra être chargée en mémoire (y compris libxul, qui prend un peu de temps).

Cependant, dans certaines situations, il est logique d'utiliser ce script. Par exemple, si vous avez/reçu une trace non symbolisée, alors vous pouvez toujours utiliser le script pour la transformer en une trace symbolisée, étant donné que vous pouvez obtenir les binaires originaux qui ont produit la trace non symbolisée. Pour que le script fonctionne dans de tels cas, vous devez vous assurer que les chemins dans la trace pointent vers les binaires réels, ou changer les chemins en conséquence.

Puisque la sortie du script asan_symbolize.py est toujours mangled, vous voudrez peut-être aussi passer la sortie par c++filt par la suite.

Dépannage / Problèmes connus

Impossible de spécifier -o lors de la génération de plusieurs fichiers de sortie

Si vous obtenez l'erreur "cannot specify -o when generating multiple output files" à partir de clang, désactivez elf-hack dans votre mozconfig pour contourner le problème :

ac_add_options --disable-elf-hack

Construction optimisée

Depuis qu'un problème avec -O2/-Os et ASan a été résolu, les optimisations régulières utilisées par Firefox devraient fonctionner sans problème. Le build optimisé n'a qu'une pénalité de vitesse à peine perceptible et semble être encore plus rapide que les builds de débogage réguliers.

Pas de "AddressSanitizer: libc interceptors initialized" s'affiche après l'exécution de  ./mach run

$ ASAN_OPTIONS=verbosity=2 ./mach run

Utilisez plutôt la commande ci-dessus

"An admin user name and password" sont requis pour accéder au mode Développeur

Veuillez activer le mode Développeur par :

$ /usr/sbin/DevToolsSecurity -enable
Developer mode is now enabled.

Problèmes de débogage que ASan trouve

Lorsque ASan découvre un problème, il n'imprime qu'un message d'erreur et quitte l'application. Pour arrêter l'application dans un débogueur avant que ASan ne la quitte, définissez un point d'arrêt sur __asan::ReportGenericError. Pour plus d'informations sur l'utilisation d'ASan et les problèmes de débogage qu'il détecte, voir la page Address sanitizer and a debugger sur le wiki en amont.

__asan_describe_address(pointer)

émis à l'invite du débogueur ou même directement dans le code permet de sortir beaucoup d'informations sur cette adresse mémoire (thread et pile d'allocation, de désallocation, si elle est un peu en dehors d'un buffer connu, thread et pile d'allocation de ce buffer, etc). Cela peut être utile pour comprendre où un tampon qui n'est pas aligné a été alloué, lors de l'exécution de travaux SIMD, par exemple.

rr (seulement Linux x86) fonctionne très bien avec ASan et combiné, ce combo permet de faire quelques stratégies de débogage très puissantes.

LeakSanitizer

LeakSanitizer (LSan) est un mode d'exécution spécial pour ASan standard. Il tire parti de la façon dont ASan suit l'ensemble des blocs sous tension à n'importe quel point donné pour imprimer la pile d'allocation de tout bloc qui est encore vivant à l'arrêt, mais qui n'est pas accessible à partir de la pile, selon un balayage conservateur.  Ceci est très utile pour détecter les fuites d'objets tels que les char* qui ne participent pas à la détection des fuites de l'arrêt de Gecko.

Pour qu'une construction ASan exécute LSan, définissez la variable d'environnement  ASAN_OPTIONS à detect_leaks=1 (ou ajoutez-la comme une entrée dans une liste :-séparée si elle est déjà définie sur quelque chose).  Si vous utilisez une construction sans débogage, vous voudrez également définir la variable d'environnement  MOZ_CC_RUN_DURING_SHUTDOWN=1, pour s'assurer que nous exécutons des GCs et des CCs d'arrêt pour éviter les fuites intempestives.

Si un objet signalé par LSan n'est intentionnellement jamais libéré, un symbole peut être ajouté à build/sanitizers/lsan_suppressions.txt pour que LSan l'ignore.

Pour plus d'informations sur LSan, voir la page wiki Leak Sanitizer.

Étiquettes et contributeurs liés au document

Contributeurs à cette page : hellosct1, mdnwebdocs-bot
Dernière mise à jour par : hellosct1,