Comparaison d’égalité des pointeurs sur différents objects

Inspiré par cette réponse à cette question , j’ai un peu creusé dans les normes C11 et C99 pour l’utilisation des opérateurs d’égalité sur les pointeurs (la question initiale concernait les opérateurs relationnels). Voici ce que C11 a à dire (C99 est similaire) au § 6.5.9.6:

Deux pointeurs se comparent égaux si et seulement si les deux pointeurs sont nuls, les deux pointeurs pointent sur le même object (y compris un pointeur sur un object et un sous-object au début) ou une fonction, les deux pointeurs pointent sur le dernier élément du même tableau object, ou l’un est un pointeur sur un point situé au-delà de la fin d’un object tableau et l’autre est un pointeur sur le début d’un object tableau différent qui suit immédiatement le premier object tableau de l’espace adresse. 94 )

La note de bas de page 94 dit (et notez que les notes de bas de page sont non normatives):

Deux objects peuvent être adjacents en mémoire parce qu’ils sont des éléments adjacents d’un tableau plus grand ou des éléments adjacents d’une structure sans remplissage entre eux, ou que l’implémentation a choisi de les placer ainsi, même s’ils ne sont pas liés. Si des opérations antérieures de pointeur non valide (telles que des access en dehors des limites du tableau) ont généré un comportement non défini, les comparaisons ultérieures produisent également un comportement non défini.

Le corps du texte et la note non normative semblent être en conflit. Si l’on prend au sérieux le “si et seulement si” du corps du texte, l’égalité ne devrait être rétablie que si elle était énoncée, et il n’y aurait pas de place pour UB. Donc, par exemple ce code:

uintptr_t a = 1; uintptr_t b = 1; void *ap = (void *)a; void *bp = (void *)b; printf ("%d\n", ap <= bp); /* UB by §6.5.8.5 */ printf ("%d\n", ap < bp); /* UB by §6.5.8.5 */ printf ("%d\n", ap == bp); /* false by §6.5.9.6 ?? */ 

devrait afficher zéro, car ap et bp ne sont ni des pointeurs sur le même object ni la même fonction, ni aucun des autres bits indiqués.

Au § 6.5.8.5 (opérateurs relationnels), le comportement est plus clair (je souligne):

Lorsque deux pointeurs sont comparés, le résultat dépend des emplacements relatifs dans l’espace d’adressage des objects pointés. Si deux pointeurs sur des types d’object ou des types incomplets pointent tous deux sur le même object ou tous les deux, un après le dernier élément du même object tableau, ils se comparent égaux. Si les objects pointés sont des membres du même object agrégé, les pointeurs sur les membres de la structure déclarés ultérieurement comparent les pointeurs supérieurs aux membres déclarés précédemment dans la structure, et les pointeurs sur des éléments de tableau avec des valeurs en indice plus grandes comparent les pointeurs supérieurs aux éléments du même tableau. avec des valeurs plus faibles en indice. Tous les pointeurs vers les membres d’un même object d’union se comparent. Si l’expression P pointe sur un élément d’un object tableau et que l’expression Q pointe sur le dernier élément du même object tableau, l’expression de pointeur Q+1 compare plus grande que P Dans tous les autres cas, le comportement est indéfini.

Des questions:

  • J’ai raison de dire qu’il y a une certaine ambiguïté quant au moment où les opérateurs d’égalité avec pointeurs sont autorisés UB (en comparant la note de bas de page et le corps du texte)?

  • S’il n’y a pas d’ambiguïté, à quel moment la comparaison de pointeurs avec des opérateurs d’égalité peut-elle précisément être UB? Par exemple, est-ce toujours UB si au moins un pointeur est créé artificiellement (voir ci-dessus)? Que se passe-t-il si un pointeur fait référence à une mémoire qui a été free()d ? Étant donné que la note de bas de page est non normative, peut-on en conclure qu’il n’y a jamais d’UB, en ce sens que toutes les «autres» comparaisons doivent donner de false ?

  • Le § 6.5.9.6 signifie-t-il vraiment que la comparaison d’égalité de pointeurs égaux sans signification mais égaux au niveau du bit doit toujours être fausse?

Notez que cette question est étiquetée langue-avocat ; Je ne demande pas ce que font en pratique les compilateurs, car je pense déjà connaître la réponse à cette question (comparez-les en utilisant la même technique que la comparaison d’entiers).

Ai-je raison de penser qu’il existe une certaine ambiguïté quant au moment où les opérateurs d’égalité avec pointeurs sont UB?

Non, car ce passage de §6.5.9 (3):

Les opérateurs == et != Sont analogues aux opérateurs relationnels, à l’exception de leur priorité inférieure.

Cela implique que ce qui suit à partir du § 6.5.9 (6) s’applique également aux opérateurs d’égalité:

Lorsque deux pointeurs sont comparés […] Dans tous les autres cas, le comportement est indéfini.

S’il n’y a pas d’ambiguïté, à quel moment la comparaison de pointeurs avec des opérateurs d’égalité peut-elle précisément être UB?

Il existe un comportement indéfini dans tous les cas pour lesquels la norme ne définit pas explicitement le comportement.

Est-ce toujours UB si au moins un pointeur est créé artificiellement converti d’un entier arbitraire?

§6.3.2.3 (5):

Un entier peut être converti en n’importe quel type de pointeur. Sauf indication contraire, le résultat est défini par l’implémentation, peut ne pas être correctement aligné, peut ne pas pointer vers une entité du type référencé et peut être une représentation d’interruption.

Que se passe-t-il si un pointeur fait référence à une mémoire qui a été free d?

§6.2.4 (2):

La valeur d’un pointeur devient indéterminée lorsque l’object vers lequel il pointe atteint la fin de sa vie.

peut-on en conclure qu’il n’y a jamais d’UB, en ce sens que toutes les «autres» comparaisons doivent donner de faux?

La norme définit dans quelles conditions deux pointeurs doivent se comparer, et dans quelles conditions deux pointeurs doivent être différents. Toute comparaison d’égalité entre deux pointeurs qui ne relève pas de ces deux ensembles de conditions appelle un comportement indéfini.

Le paragraphe 6.5.9 (6) signifie-t-il vraiment que la comparaison d’égalité de pointeurs égaux sans signification mais égaux au niveau du bit doit toujours être fausse?

Non, c’est indéfini.