web-dev-qa-db-fra.com

Que fait exactement l'option -Wasabi de GCC? Quelles sont les implications de la suppression?

Contexte

Au cours de la dernière année, j’utilisais la bibliothèque nlohmann json[1] et était en compilation croisée sur x86_64 en utilisant GCC 5.x arm-linux-gnueabi-* sans avertissements. Lorsque j'ai mis à jour GCC vers une version plus récente, GCC générait des pages de notes de diagnostic cryptiques. Par exemple, voici l'une des notes

In file included from /usr/arm-linux-gnueabi/include/c++/7/vector:69:0,
             from include/json.hpp:58,
             from src/write_hsi.cpp:23:
/usr/arm-linux-gnueabi/include/c++/7/bits/vector.tcc: In member function ‘void std::vector<_Tp, _Alloc>::_M_realloc_insert(std::vector<_Tp, _Alloc>::iterator, _Args&& ...) [with _Args = {nlohmann::basic_json<std::map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long long int, long long unsigned int, double, std::allocator, nlohmann::adl_serializer>}; _Tp = nlohmann::basic_json<>; _Alloc = std::allocator<nlohmann::basic_json<> >]’:
/usr/arm-linux-gnueabi/include/c++/7/bits/vector.tcc:394:7: note: parameter passing for argument of type ‘std::vector<nlohmann::basic_json<>, std::allocator<nlohmann::basic_json<> > >::iterator {aka __gnu_cxx::__normal_iterator<nlohmann::basic_json<>*, std::vector<nlohmann::basic_json<>, std::allocator<nlohmann::basic_json<> > > >}’ changed in GCC 7.1
   vector<_Tp, _Alloc>::
   ^~~~~~~~~~~~~~~~~~~
/usr/arm-linux-gnueabi/include/c++/7/bits/vector.tcc: In member function ‘nlohmann::basic_json<ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType, JSONSerializer> nlohmann::basic_json<ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType, JSONSerializer>::parser::parse_internal(bool) [with ObjectType = std::map; ArrayType = std::vector; StringType = std::__cxx11::basic_string<char>; BooleanType = bool; NumberIntegerType = long long int; NumberUnsignedType = long long unsigned int; NumberFloatType = double; AllocatorType = std::allocator; JSONSerializer = nlohmann::adl_serializer]’:
/usr/arm-linux-gnueabi/include/c++/7/bits/vector.tcc:105:21: note: parameter passing for argument of type ‘__gnu_cxx::__normal_iterator<nlohmann::basic_json<>*, std::vector<nlohmann::basic_json<>, std::allocator<nlohmann::basic_json<> > > >’ changed in GCC 7.1
_M_realloc_insert(end(), std::forward<_Args>(__args)...);
~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Il était facile de trouver une solution, notamment en ajoutant -Wno-psabi Aux options du compilateur. En fait, c'était le correctif mis en œuvre dans la bibliothèque.[2]

Je comprends les bases des interfaces ABI (Application Binary Interfaces) et des interfaces ABI spécifiques au processeur (psABI). Pour référence, cette réponse[11] donne un aperçu rapide des ABI:

Une ABI ( application binaire ) est un standard qui définit un mappage entre des concepts de bas niveau dans des langages de haut niveau et les capacités d'un code machine spécifique de la plate-forme matérielle/OS. Cela inclut des choses comme:

  • comment C/C++/Fortran/... les types de données sont disposés en mémoire (tailles de données/alignements)
  • comment les appels de fonction imbriqués fonctionnent (où et comment sont stockées les informations permettant de retourner à l'appelant d'une fonction, où les arguments de la CPU et/ou de la mémoire sont passés)
  • comment le démarrage/initialisation du programme fonctionne (quel format de données un "exécutable" a, comment le code/les données sont chargés à partir de là, comment fonctionnent les DLL ...)

Les réponses à celles-ci sont:

  • spécifique au langage (vous avez donc une ABI C, une ABI C++, une ABI Fortran, une ABI Pascal, ... même la spécification Java de bytecode, bien que ciblant un processeur "virtuel" au lieu d'un matériel réel, est une ABI),
  • spécifique au système d'exploitation (MS Windows et Linux sur le même matériel utilisent un ABI différent),
  • spécifique au matériel/à la CPU (le ARM et x86 sont différents).
  • évolue dans le temps (long) (les ABI existantes ont souvent été mises à jour/révisées afin que les nouvelles fonctionnalités de la CPU puissent être utilisées, comme, par exemple, en spécifiant comment x86 SSE devant être utilisés par les applications n'étaient bien entendu possibles que lorsque les CPU avaient ces regs (il fallait donc clarifier les ABI existantes).

Ainsi, l’ABI est le composant le plus important et l’un de ses composants (les détails "spécifiques au matériel/à la CPU") est le psABI.

Mon problème

Le problème que je rencontre est

  1. Je n'aime pas désactiver universellement les avertissements sans en comprendre les implications.
  2. Le conseil "utiliser -Wno-psabi Pour supprimer les notes" semble être un conseil assez courant pour ce type de notes de diagnostic qui "apparaissent soudainement" après la mise à niveau du compilateur.[2][3][4] Même celui des développeurs de GCC suggère de le faire.[5]
  3. Ni -Wpsabi Ni -Wno-psabi Ne sont documentés[6] dans le manuel GCC.[7]

En conséquence, je ne suis pas vraiment sûr de ce que -Wno-psabi Exactement affectera et n’affectera pas. Une option connexe -Wabi est documentée:[8]

-Wabi (C, Objective-C, C++ and Objective-C++ only)

Avertir lorsque G ++ génère un code probablement incompatible avec l’ABI C++ indépendant du vendeur ...

Il met également en garde contre les modifications liées à psABI. Les changements connus de psABI à ce stade incluent:

  • Pour SysV/x86-64, les unions avec des membres doubles longs sont passées en mémoire, comme spécifié dans psABI. Par exemple:

union U {long double ld;int i;};

union U Est toujours passé en mémoire.

Ma compréhension de tout cela est

  1. -Wabi Générera des avertissements en cas de changement de psABI.
  2. GCC 7 a corrigé un bogue ABI[9] introduit dans GCC 5 qui affecte ARM cibles.
    • Dans les notes de publication, il est indiqué "il s'agit d'un changement ABI".[dix]
    • Pour une raison quelconque, les notes de publication indiquent que les notes de diagnostic correspondantes sont générées lors de l'utilisation du -Wpsabi Non documenté, et non du document -Wabi Documenté.
    • Ce changement ABI n'est pas mentionné dans le manuel.
  3. En assemblant "ceci est un changement d’ABI" et "utilisez -Wpsabi", Il me semble que c’est plus précisément un changement de psABI, et non un type de changement d’ABI différent. (En réalité, c'est un changement dans la mise en œuvre de psABI par GCC, pas par psABI lui-même)

Je sais que la documentation n'est pas toujours à jour, en particulier pour une option connue non documentée. Mais ce qui me préoccupe, c’est que "use -Wno-psabi" Semble être la réponse standard à plusieurs types de ces notes de diagnostic cryptiques. Mais, dans ma compréhension de base des ABI, un ABI ne change-t-il pas un gros problème? Ne devrais-je pas m'inquiéter d'un changement d'ABI, plutôt que de simplement faire disparaître le message? Entre les éléments non documentés et certains des détails les plus fins de ABI vs psABI, je ne suis pas vraiment sûr ...

Par exemple, si j'ajoute -Wno-psabi À mon fichier make pour faire disparaître ces notes, que se passera-t-il s'il y a un autre changement ABI à l'avenir qui fait affecte mon projet? Ai-je effectivement fait taire les avertissements ou les notes qui pourraient être importants?

En outre, même si on nous dit "si vous recompilez tout le code, vous ne devez pas vous inquiéter",[5] qu'est-ce que "tout le code"? Est-ce que c'est mon code source? glibc? Toute autre bibliothèque partagée à l'échelle du système que je pourrais utiliser?

Les références

  1. https://github.com/nlohmann/json
  2. https://github.com/nlohmann/json/issues/658
  3. https://stackoverflow.com/a/481494
  4. https://stackoverflow.com/a/13915796/10270632
  5. https://gcc.gnu.org/ml/gcc/2017-05/msg00073.html
  6. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81831
  7. https://gcc.gnu.org/onlinedocs/gcc-8.2.0/gcc
  8. https://gcc.gnu.org/onlinedocs/gcc-8.2.0/gcc/C_002b_002b-Dialect-Options.html
  9. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=77728
  10. https://gcc.gnu.org/gcc-7/changes.html
  11. https://stackoverflow.com/a/806335
58
rmc

Vous ne devez vous soucier des ABI que lorsque vous franchissez les limites d'une bibliothèque. Dans vos propres applications/bibliothèques, l’ABI n’a pas vraiment d’importance, car tous vos fichiers objet sont compilés avec la même version du compilateur et les mêmes commutateurs.

Si vous avez une bibliothèque compilée avec ABI1 et une application compilée avec ABI2, l'application se bloquera lorsqu'elle tentera d'appeler des fonctions à partir de la bibliothèque car elle ne passera pas les arguments correctement. Pour réparer l'incident, vous devez recompiler la bibliothèque (et toutes les autres bibliothèques dont il dépend) avec ABI2.

Dans votre cas spécifique, tant que vous compilez nlohmann avec la même version du compilateur que votre application (ou utilisez simplement nlohmann comme en-tête), vous n'avez pas à vous soucier du changement d'ABI.

La suppression globale de l'avertissement semble être une option dangereuse, car elle vous empêchera de voir d'éventuels problèmes ABI. Une meilleure option serait d'utiliser #pragma pour désactiver l’avertissement uniquement pour les fonctions en question, par exemple:

#pragma GCC diagnostic Push
#pragma GCC diagnostic ignored "-Wno-psabi"
void foo()
{
}
#pragma GCC diagnostic pop
3
Alan Birtles