10
votes

Ce piratage est-il pour supprimer l'aliasing Avertissement UB?

Nous venons de mettre à niveau notre compilateur à GCC 4.6 et nous obtenons maintenant certains de ces avertissements. Au moment où notre code de code n'est pas dans un état d'être compilé avec C ++ 0x et de toute façon, nous ne voulons pas l'exécuter dans Prod (au moins pas encore) - alors j'avais donc besoin d'une solution pour supprimer cet avertissement.

Les avertissements se produisent généralement à cause de quelque chose comme ceci: xxx

plus tard, ceci est utilisé de la manière suivante xxx

Pour lire, mettre à jour et revenir par exemple, la distribution suivante utilisée pour arriver xxx

ceci était correct avec 4.4; en 4.6 ce qui précède génère:

AVERTISSEMENT: le pointeur punne de type cassera des règles strictes-aliasing

Un moyen propre pour supprimer cette erreur consiste à utiliser un «code> union , cependant, comme je l'ai dit, nous ne pouvons pas utiliser C ++ 0x (et donc des syndicats non restreints), donc J'ai employé le Horrible Hack Hack ci-dessous - maintenant, l'avertissement est parti, mais je suis susceptible d'invoquer des démons nasaux? xxx

ceci semble Travailler Bien (voir exemple simple ici: http://www.ideone.com/9P3MS ) et génère non Avertissements, est-ce que ça va (pas dans le sens stylistique) d'utiliser ceci jusqu'à C ++ 0x?

Remarque: je ne veux pas utiliser -fno-strict-aliasing Généralement ...

EDIT : Il semble que je me trompais, le même avertissement est là sur 4.4, je suppose que nous ne l'avons cueilli récemment avec le changement (il a toujours été improbable Être un problème de compilateur), la question se tient toujours.

EDIT : Une enquête supplémentaire a donné des informations intéressantes, il semble que la fonte et l'appelant la fonction de membre dans O NE LINE est ce qui cause l'avertissement, si le code est divisé en deux lignes comme suit xxx

ceci ne génère pas réellement un avertissement. En conséquence, mon exemple simple sur l'idéone est imparfait et plus important encore mon hack avant ne corrige pas l'avertissement , le seul moyen de résoudre ce problème est de diviser l'appel de la fonction de la fonte - puis de la distribution être laissé comme un reterpret_cast .


7 commentaires

Je pense qu'après que vous avez fait nouveau (page.vdata) Automype () , le type réel de l'objet situé au même endroit que page.vdata est mérite certains , comme c'est la dernière chose qui est stockée là-bas, et donc le type de jeu de mots est légal. L'avertissement déclenché par la distribution ne sait probablement pas avec certitude que vous avez fait ce placement nouveau, cependant. Si j'ai raison pour que votre code d'origine soit bien correct, alors n'assumant aucun bogue dans GCC, l'horrible piratage devrait être ok aussi (puis de la définition de REINIERPRET_CAST rend le pointeur résultant de la même manière). Pas sûr, cependant.


@Steve, semble être comme si j'avais tort, l'avertissement est là dans 4,4, tout aussi - tout simplement pas ramassé. La question sur le hack est toujours debout.


" Cela ne génère pas en réalité un avertissement. En conséquence, " avec quelles options?


@CuciousGuy, -wall si je me souviens bien ..


@Nim vous voudrez peut-être réessayer avec une certaine optimisation.


@Cuciousguy, -O3 , je n'ai pas vu les avertissements ...


@Nim il n'est pas garanti, mais en général, plus d'optimisation signifie plus d'analyse de code signifie plus d'avertissements.


4 Réponses :


1
votes

Pourquoi ne pas utiliser: xxx pré>

et ensuite: p> xxx pré>

Je ne pense pas qu'un syndicat est le meilleur moyen, il peut aussi être problématique. À partir des DOCS GCC: P>

`-fstrict-aliasing'
 Allows the compiler to assume the strictest aliasing rules
 applicable to the language being compiled.  For C (and C++), this
 activates optimizations based on the type of expressions.  In
 particular, an object of one type is assumed never to reside at
 the same address as an object of a different type, unless the
 types are almost the same.  For example, an `unsigned int' can
 alias an `int', but not a `void*' or a `double'.  A character type
 may alias any other type.

 Pay special attention to code like this:
      union a_union {
        int i;
        double d;
      };

      int f() {
        a_union t;
        t.d = 3.0;
        return t.i;
      }
 The practice of reading from a different union member than the one
 most recently written to (called "type-punning") is common.  Even
 with `-fstrict-aliasing', type-punning is allowed, provided the
 memory is accessed through the union type.  So, the code above
 will work as expected.  However, this code might not:
      int f() {
        a_union t;
        int* ip;
        t.d = 3.0;
        ip = &t.i;
        return *ip;
      }


2 commentaires

@Nim: Y a-t-il une raison pour laquelle non? Peut-être avoir un constructeur factice qui n'écrit pas le vdata et juste à la place - nouveau lorsque vous souhaitez l'utiliser.


Il y a des complications que je n'ai pas mentionnées, le pr quelque type est une variante, et je tiens à utiliser le fait que l'attribution au même type détenu par la variante est moins chère que la construction de la valeur par défaut ( puis reconstruisant le nouveau type).



0
votes

Je serais plus préoccupé par certains_size ne pas être assez gros, franchement. Cependant, il est légal to alias tout type avec un char * . Donc simplement faire reterpret_cast (& page.vdata [0]) devrait être très bien.

Aussi, je remetterais ce genre de conception. Sauf si vous implémentez boost :: variante ou quelque chose de similaire, il n'y a pas beaucoup de raisons de l'utiliser.


6 commentaires

Il est légal d'alias tout type avec char * , mais il n'est pas nécessairement légal d'alias char * avec n'importe quel type. Les règles de type-Pun ne sont pas symétriques par rapport au type réel de l'objet et le type utilisé pour y accéder.


Tandis que les règles de revêtement de type ne sont pas en général symétriques, elles sont symétriques par rapport à char - vous pouvez alias tout type avec char et peut alias char avec n'importe quel type. Étant donné que ce code est un aliasing avec char , l'avertissement du compilateur est incorrect.


@Chris: check 3.10 / 15. Il ne dit pas qu'un objet dont le type dynamique est Char est accessible via un lvalue de n'importe quel type. Différents cas de Automype sont corrects, mais les seuls UDT qui sont qualifiés sont un agrégat ou un syndicat avec un char , signé Char , non signé Char membre ou version qualifiée de CV d'un de ceux-ci. Automatique pourrait ne pas être un tel agrégat ou un tel syndicat. Il n'y a pas de symétrie. Donc, cet alias n'est que légal depuis que le type dynamique de l'objet est quelqueye , grâce au placement nouveau. S'il y a quelque part ailleurs dans la norme qui permet à tout autre aliasing, je l'ai manqué.


@Stevejessop: Je considère cela un bogue dans la norme alors. Il faut y avoir un moyen d'avoir une blob de mémoire non ancrée d'un nombre spécifique d'octets. S'il n'y a pas, une manière approuvée de faire cela doit être créée. Si rien d'autre, il est pratiquement impossible de mettre en œuvre un allocateur en C ++.


@Omnifaous: Il y a une maladresse là-bas - placement Nouveau vous donne un moyen de convertir la mémoire brute ( char ) dans votre objet de type Automype sans Avez-vous déjà eu à vous référer à tout autre lvalue, puisque la mise en œuvre prend en charge cela. Clairement, ce n'est pas la manière dont C résout le problème, cependant et que les types de POD ont des règles sur la durée de vie et le fait que vous puissiez la mettre fin à la "réutilisation" de leur mémoire. Cette "réutilisation" pourrait interagir avec les règles d'aliasing d'une certaine manière, je ne me souviens pas. Si cela implique une symétrie non indiquée dans 3,10 / 15, mes excuses.


@Stevejessop Il s'agit d'un état de fait confus, triste et effrayant: il existe différentes interprétations des règles d'aliasing, non seulement par un programmeur aléatoire C ++, également par des implémentations de compilateur (au moins GNU). Et une interprétation, le plus fort, signifie que vous ne pouvez pas avoir d'allocator personnalisé en C / C ++, fin de l'histoire. La seconde interprétation moins stricte signifie que Vous ne pouvez pas avoir d'allocator personnalisé en C mais le placement-nouveau vous sauve. Veuillez noter que la norme ISO C semble avoir une sémantique aloritable assez différente (et l'OMI Le Comité C est devenu un aliasing Crazy WRT).



0
votes
template <class T>
struct DataPage {
   alignof(T) char vData[sizeof(T)];
};

1 commentaires

Malheureusement, je ne peux pas utiliser ici un modèle, car nous utilisons un mécanisme pour étendre pr quelque type de telle sorte que la compatibilité ascendante soit maintenue avec des sorties plus anciennes - en conséquence, toutes les rejets doivent avoir suffisamment de stockage pour tenir compte de la comptabilisation. Modifications potentielles à ATTRAINTYPE ...



2
votes
SomeDataPage page;
SomeType *data = new(page.vData) SomeType(); // non-trivial constructor
data->some_member();

4 commentaires

Merci pour la réponse, je pense que j'ai mis à jour la question, la seule façon de pouvoir éviter que l'avertissement était de diviser la distribution (malheureusement, le nouvel opération nouvelle se produit au moment de l'initialisation et à l'appel à Certain_member () arrive pendant la course normale) - il y a donc maintenant un reterpret_cast comme j'ai ajouté à la modification. C'est la seule façon de l'obtenir pour supprimer l'avertissement. J'aurais dû ajouter ceci comme une réponse - mais je n'ai jamais eu de route ...


@NIM Le problème ici est que, en décomposant les opérations, vous ne réparez pas le problème sous-jacent (s'il y a vraiment un problème sous-jacent), vous faites simplement que le compilateur vous avertit.


AFAIK Il n'y a pas de problème sous-jacent, j'utilise le placement nouveau pour construire l'objet; IMO, c'est un avertissement parasite qui devait être réduit au silence dans ce cas spécifique - sans que le type d'interrupteur d'avertissement d'avertissement.


@Nim mon interprétation est également qu'il s'agit d'un avertissement parasite; La question que j'ai avec les règles d'aliasing strictes est que les règles ne sont pas assez claires pour tout le monde, en particulier des écrivains compilateurs.