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)

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. Par conséquent, nous devons d'abord obtenir et construire LLVM et Clang.

Note: Au moment d'écrire ces lignes, ASan n'a été intégré que dans les versions du tronc LLVM/Clang SVN et pourrait ne pas encore être inclus dans les versions régulières. Par conséquent, le manuel décrit comment extraire  LLVM/Clang et construire à partir des sources.

Note: Les instructions suivantes (pour Linux) fonctionnent avec GCC 4.9 et G++ 4.9, veuillez installer ces paquets au préalable (par exemple gcc-4.9 et g++-4.9 par apt-get).

Les commandes suivantes font un nouveau SVN checkout/build de LLVM, Clang et les bibliothèques d'exécution du compilateur avec une révision confirmée pour fonctionner :

# Latest revision confirmed to build with Linux
# For MacOSX, please use at least r214699.
REV=266460
svn co -r $REV https://llvm.org/svn/llvm-project/llvm/trunk llvm
cd llvm
export LLVM_HOME=`pwd` # We will refer to this variable later during the build.
(cd tools && svn co -r $REV https://llvm.org/svn/llvm-project/cfe/trunk clang)
(cd projects && svn co -r $REV https://llvm.org/svn/llvm-project/compiler-rt/trunk compiler-rt)

Il n'est PAS conseillé d'utiliser les versions de clang fournies par le système pour les versions ASAN ; elles peuvent avoir des problèmes ou des instabilités lorsqu'elles sont utilisées pour construire/tester Firefox.  Les versions données sont connues pour fonctionner..

Maintenant, nous pouvons commencer notre construction, ce qui peut prendre un certain temps selon les spécifications de votre machine. Afin de configurer la compilation avec la méthode cmake recommandée, vous devez avoir au moins cmake 2.8.8 installé. Ajustez le paramètre -j à vos besoins en fonction de vos CPU (les utilisateurs Linux avec un gcc pa défaut supérieur à 4.9 peuvent avoir à appeler gcc-4.9 & g++-4.9 en ajoutant au préalable "CC=/usr/bin/gcc-4.9 CXX=/usr/bin/g++-4.9" à la ligne cmake; Les utilisateurs de MacOSX peuvent avoir besoin d'ajouter "-DLLVM_ENABLE_LIBCXX=ON" à la ligne cmake) :

mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE:STRING=Release $LLVM_HOME
make -j16

La construction avec cmake est fortement recommandée. Dans le cas où vous ne pouvez pas construire avec cmake pour une raison quelconque, il est toujours possible de construire sans lui. Utilisez plutôt ces étapes pour la construction :

# Use these steps only if the cmake build steps cannot be used
mkdir build
(cd build && ../configure --enable-optimized && make -j 10 ENABLE_OPTIMIZED=1 DISABLE_ASSERTIONS=1)

Veuillez noter que lorsque vous construisez sans cmake, le chemin d'accès à vos binaires résultants sera différent. For exemple, avec cmake, le binaire clang sera à  $LLVM_HOME/build/bin/clang while alors qu'avec l'autre méthode de compilation, vous l'obtiendrez à $LLVM_HOME/build/Release/bin/clang.

Building Firefox

Obtenir les sources

Le processus de compilation suivant a été testé pour la dernière fois avec mozilla-central revision ad79ffdf94a3. En utilisant cela ou toute révision ultérieure, tout ce que vous avez à faire est  de vous procurer un clone de mozilla-central.

Note: Auparavant, une liste noire était nécessaire pour éviter les défaillances de certaines fonctions. Depuis que le bug 751195 a atteri, ce n'est plus nécessaire puisque les changements et annotations nécessaires sont maintenant dans le code source.

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.

Note: si la compilation échoue avec une erreur sur 'max_align_t', commenter la ligne dans <cstddef> qui l'utilise (ex :  cstddef:51 "using ::max_align_t;" dans Fedora 21 avec libstdc++ 4.9.2 Release : 6.fc21).  clang 200213 n'a pas le support  max_align_t.

Avertissement : Si votre version MacOSX échoue avec fatal error: 'cstdio' file not found (ou 'algorithm', 'string', et quelque chose de la bibliothèque standard), vous devez installer libc++ par vous-même.

# Install libc++
cd llvm/projects
svn co -r $REV http://llvm.org/svn/llvm-project/libcxx/trunk libcxx
svn co -r $REV http://llvm.org/svn/llvm-project/libcxxabi/trunk libcxxabi

# Re-build LLVM
cd .. && rm build && mkdir build && cd build 
cmake -DCMAKE_BUILD_TYPE:STRING=Release $LLVM_HOME 
make -j16

Démarrer Firefox

Une fois la compilation terminée, vous pouvez démarrer Firefox à partir de l'objdir comme d'habitude.

Construire uniquement l'interpréteur de commandes JavaScript

Si vous voulez construire seulement le shell JavaScript au lieu de faire une construction Firefox complète, le script de construction ci-dessous vous aidera probablement à le faire. Avant de l'utiliser, vous devez bien sûr ajuster le chemin d'accès à LLVM_ROOT pour qu'il corresponde à votre configuration. Une fois que vous avez tout réglé, exécutez ce script dans le sous-répertoire js/src/ set passez un nom de répertoire comme premier paramètre. La compilation sera alors créée dans un nouveau sous-répertoire avec 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.

Crashes sur Ubuntu 11.10

Il semble y avoir un bug sur Ubuntu 11.10 où les binaires tels que certutilshlibsign et d'autres outils NSS s'écrasent au démarrage. En conjonction, vous verrez des avertissements tels que

/usr/bin/ld.bfd.real: /path/to/llvm/build/Release+Asserts/bin/../lib/clang/3.1/lib/linux/libclang_rt.asan-x86_64.a(asan_thread_registry.o)(.text+0x2d6): unresolvable R_X86_64_PLT32 relocation against symbol `memcpy@@GLIBC_2.2.5'

pendant la construction. La cause exacte n'est pas encore connue mais il se peut qu'il s'agisse d'un bug dans ld sur cette version d'Ubuntu, comme l'utilisation de gold lorsque le linker résout le problème. Pour contourner ce problème, il suffit de faire comme ceci : 

sudo apt-get install binutils-gold

et l'or sera votre lien par défaut. Cela vient avec l'effet secondaire positif que votre construction sera quelques minutes plus rapide en raison de moins de temps de liaison nécessaire..

Récent cmake sur Ubuntu 12.04 LTS

Malheureusement, la version actuelle d'Ubuntu LTS est livrée avec une version cmake qui est trop ancienne pour construire un compilateur-rt (2.8.7). Il y a plusieurs PPAs disponibles, bien que des cmake plus récents soient disponibles, par exemple  https://launchpad.net/~irie/+archive/cmake . Cet PPA a été confirmé pour fonctionner, mais vous l'utilisez à vos risques et périls bien sûr.

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 ReportGenericError (anciennement __asan_report_error). Pour plus d'informations sur l'utilisation d'ASan et les problèmes de débogage qu'il découvre, voir la page wiki de Google Code Address Sanitizer.

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
Dernière mise à jour par : hellosct1,