Pourquoi le qualificatif de ressortingction permet-il toujours à memcpy d’accéder à la mémoire qui se chevauche?

Je voulais voir si ressortingct empêcherait memcpy d’accéder à la mémoire qui se chevauchait.

La fonction memcpy copie n octets de la zone mémoire src vers la zone mémoire destinée directement . Les zones de mémoire ne doivent pas se chevaucher.

memmove utilise un tampon pour memmove tout risque de chevauchement de mémoire.

Le qualificatif de ressortingct indique que pendant la durée de vie du pointeur, seul le pointeur lui-même ou une valeur directement issue de celui-ci (tel que pointer + n ) aura access aux données de cet object. Si la déclaration d’intention n’est pas suivie et que l’object est accédé par un pointeur indépendant, cela entraînera un comportement indéfini.

 #include  #include  #define SIZE 30 int main () { char *ressortingct itself; itself = malloc(SIZE); strcpy(itself, "Does ressortingct stop undefined behavior?"); printf("%d\n", &itself); memcpy(itself, itself, SIZE); puts(itself); printf("%d\n", &itself); memcpy(itself-14, itself, SIZE); //intentionally trying to access ressortingcted memory puts(itself); printf("%d\n", &itself); return (0); } 

Sortie ()

Adresse de lui-même: 12345
Est-ce que restreindre arrête un comportement non défini?
Adresse de lui-même: 12345
arrêter un comportement indéfini bop indéfini?
Adresse de lui-même: 12345

Est- memcpy que memcpy utilise un pointeur indépendant? Parce que la sortie montre clairement un comportement indéfini et que ressortingct n’empêche pas l’access à la mémoire qui se chevauche avec memcpy .

Je suppose que memcpy a un avantage en memcpy performances puisqu’il copie directement les données, tandis que memmove utilise un tampon. Mais avec les ordinateurs modernes, devrais-je ignorer ces performances potentiellement meilleures et toujours utiliser memmove car cela ne garantit aucun chevauchement?

Le mot-clé ressortingct est un conseil fourni au compilateur pour permettre la génération de code, indiquant au compilateur qu’il ne devrait pas être dérangé par la possibilité d’un alias de pointeur (deux pointeurs nommés différents accédant à la même adresse).

Dans une fonction qui prend ressortingct pointeurs de ressortingct , le compilateur comprend que l’écriture sur l’un n’aura pas d’impact sur l’autre. Lors de la copie d’un emplacement A à un emplacement B, cela signifie que vous pouvez modifier ce code en toute sécurité:

  • Lecture de A [0] dans le registre 1
  • Ecrire à B [0] à partir du registre 1
  • Lecture de A [1] dans le registre 1
  • Ecrire à B [1] à partir du registre 1
  • Lecture de A [2] dans le registre 1
  • Ecrire à B [2] à partir du registre 1
  • Lecture de A [3] dans le registre 1
  • Ecrire à B [3] à partir du registre 1

Dans cette séquence:

  • Lecture de A [0] dans le registre 1
  • Lecture de A [1] dans le registre 2
  • Lecture de A [2] dans le registre 3
  • Lecture de A [3] dans le registre 4
  • Ecrire à B [0] à partir du registre 1
  • Ecrire à B [1] à partir du registre 2
  • Ecrire à B [2] à partir du registre 3
  • Ecrire à B [3] à partir du registre 4

Ces deux séquences ne sont identiques que si A et B ne se chevauchent pas et que le compilateur n’optimisera pas la seconde sauf si vous avez utilisé ressortingct (ou s’il ne peut pas deviner, à partir du contexte, qu’il est sécuritaire de le faire).

Si vous finissez par fournir un pointeur aliasé sur une fonction qui ne les attend pas, le compilateur pourra peut-être vous avertir au moment de la compilation, mais rien ne garantit qu’il le fera. Mais vous ne devriez vraiment pas vous attendre à une erreur au moment de la compilation – vous devriez plutôt la voir comme une permission que vous accordez au compilateur lorsqu’il génère l’assembly à partir de votre code.


Répondez à votre question sur les performances – si vous êtes certain que vos pointeurs ne se chevauchent pas, utilisez memcpy . Si vous ne le faites pas, utilisez memmove . memmove générale, memmove vérifie s’il y a un chevauchement et finit par utiliser memcpy s’il memcpy existe pas, mais vous payez le chèque.

La fonction memcpy copie n octets de la zone mémoire src vers la zone mémoire destinée directement .

Par “directement”, je suppose que vous voulez dire que la fonction évite de copier d’abord de la source à la mémoire tampon, puis de la mémoire tampon à la destination. Bien que cela soit vraisemblablement vrai, la norme n’exige pas qu’elle soit vraie.

memmove utilise un tampon pour memmove tout risque de chevauchement de mémoire.

Non, memmove produit un résultat comme s’il avait d’abord été copié dans un tampon, puis de là vers la destination. Il n’est pas nécessaire d’utiliser réellement un tampon de cette manière, à condition que le résultat souhaité soit obtenu. Toute implémentation donnée pourrait ou non le faire.

Est- memcpy que memcpy utilise un pointeur indépendant? Parce que la sortie montre clairement un comportement indéfini et que ressortingct n’empêche pas l’access à la mémoire qui se chevauche avec memcpy .

ressortingct n’empêche rien, jamais. Les compilateurs ne sont pas tenus de diagnostiquer ni même de remarquer que vous transmettez des pointeurs avec alias pour ressortingct parameters qualifiés. En effet, cette détermination ne peut souvent pas être faite au moment de la compilation.

En effet, lorsque vous appelez memcpy() avec les arguments que vous avez memcpy() lors de votre premier appel, vous fournissez deux pointeurs indépendants vers le même object que les arguments source et destination. En conséquence, le comportement du programme n’est pas défini.

Votre programme présente également un comportement indéfini suite au calcul itself - 14 (que le pointeur obtenu soit ou non déréférencé). Si itself lieu de cela itselfitself pointait au moins 14 octets à l’intérieur de l’object alloué, de sorte que l’arithmétique du pointeur soit valide, les arguments de la seconde commande memcpy() seraient à nouveau incompatibles avec les exigences de la qualification ressortingct des parameters le programme afficherait UB pour cette raison aussi.

Je suppose que memcpy a un avantage en memcpy performances puisqu’il copie directement les données, tandis que memmove utilise un tampon. Mais avec les ordinateurs modernes, devrais-je ignorer ces performances potentiellement meilleures et toujours utiliser memmove car cela ne garantit aucun chevauchement?

C’est une question d’opinion, et donc hors sujet ici. Je dirai seulement qu’il est préférable d’aborder les questions de performance en mesurant d’ abord, puis en prenant des décisions éclairées par les résultats de ces mesures. De plus, les caractéristiques de performance de différentes implémentations peuvent varier.

ressortingct n’arrête jamais le comportement indéfini. En fait, il introduit un comportement non défini dans certains cas. Si ressortingct est supprimé d’un morceau de code qui n’a pas d’UB, le code n’a toujours pas d’UB. mais l’inverse n’est pas vrai.


Votre code provoque un comportement indéfini sur cette ligne:

 strcpy(itself, "Does ressortingct stop undefined behavior?"); 

en raison du débordement de la taille du tampon alloué. Après cela, tous les paris sont ouverts.

Le qualificatif de ressortingct n’empêche pas les dépassements de mémoire tampon.