1
votes

Est-il sûr de memcpy regex_t?

Est une copie simple et superficielle de regex_t (de POSIX et regcomp () etc) garanti de toujours fonctionner?


1 commentaires

De quel regex_t parle-t-on?


3 Réponses :


7
votes

Une copie simple et superficielle de regex_t est-elle garantie de toujours fonctionner?

À condition que l'objet pointé par le pointeur de destination soit suffisamment grand pour contenir les octets copiés, et ne chevauche pas l'objet source, il n'y a pas de conditions d'échec définies pour memcpy () . Dans la mesure où tout ce qui se trouve dans un ordinateur peut être garanti, la réussite de la copie est garantie.

Cependant, cela ne signifie pas nécessairement que la copie résultante peut être utilisée indépendamment de l'original. POSIX ne place pas d'exigences suffisantes sur regex_t pour garantir cela, et il ne serait pas trop surprenant que certaines implémentations de regex_t contenaient des pointeurs vers des données allouées dynamiquement. En fait, l'existence de la fonction regfree () est une disposition explicite pour cette possibilité.


4 commentaires

La simple existence de pointeurs vers des données allouées à l'intérieur de l'objet ne veut rien dire. Si nous appelons regfree sur la copie, mais pas sur l'original, tout va bien. Ce qui pose problème, c'est la sensibilité potentielle de l'objet à sa propre adresse: des pointeurs dirigés en lui-même, soit à l'intérieur de cet objet lui-même, soit émanant d'autres objets (même inconnus de l'application).


@Kaz, l'existence de pointeurs vers des données allouées dynamiquement signifie que la copie ne peut pas être utilisée indépendamment de l'original , ce que j'ai affirmé. Votre stipulation que regree () ne sera pas appelé sur l'original s'il est appelé sur la copie est juste une telle dépendance, et la plus probable, mais pas la seule possible.


@Kaz "La simple existence de pointeurs vers des données allouées à l'intérieur de l'objet ne veut rien dire." Si ces pointeurs sont initialisés lors de la création de l'objet et jamais modifiés, alors peut-être que vous avez raison. Cependant, si l'implémentation change l'un des pointeurs après la copie (par exemple avec realloc , ou un explicite free et malloc ) alors la copie du l'objet a un pointeur non valide.


@ user3386109 Et cela pourrait se produire dans regexec si des aspects de la compilation sont retardés à l'exécution (par exemple, la construction du sous-ensemble NFA-> DFA est effectuée de manière dynamique, avec mise en cache). La (ré) allocation de mémoire n'est pas nécessairement entièrement effectuée lorsque regcomp est terminé.



1
votes

Il est possible d'interpréter POSIX de telle sorte que ce soit correct, mais probablement gras et imprudent.

Dans ISO C (qui est inclus dans POSIX par référence normative), ce qui suit est écrit à propos d'exactement un type de bibliothèque, et aucun autre :

"L'adresse de l'objet FILE utilisé pour contrôler un flux peut être significative; une copie d'un objet FILE n'a pas besoin d'être diffusée à la place de l'original. "

Essentiellement, le même texte est répété dans POSIX, 2.5 Flux d'E / S standard.

Donc vous penserait que cela crée un précédent de "désinscription": toute représentation qui ne doit pas être copiée sera documentée avec une telle interdiction, et d'autres types peuvent l'être.

De plus, cela est renforcé par la présence d'explicite "opt out" dans un autre domaine de la norme: threading:

"Pour les barrières, les variables de condition, les mutex et les verrous en lecture-écriture, [TSH] [Option Start] si le processus est partagé l'attribut est défini sur PTHREAD_PROCESS_PRIVATE, [Option End] uniquement le synchr Un objet de onisation à l'adresse utilisée pour l'initialiser peut être utilisé pour effectuer la synchronisation. "

Il semble que l'approche standard consiste à préciser quand l'utilisation d'un objet copié est interdite.

Pourtant, je me méfierais de copier toute structure qui sert comme une sorte de descripteur de ressource avec état, plutôt que juste une structure d'information (comme struct stat ou struct pwent ). Les développeurs pourraient accidentellement rendre une telle chose sensible à sa propre adresse, avec quelque chose comme:

struct foo {
  type_t *internal_ptr;
  /* ... */
  type_t internal_array_of_something[...];
};

Il n'y a aucun texte dans POSIX qui interdit que . Un problème similaire se pose si le système maintient, quelque part, des back-pointeurs vers la structure, ou dans la structure.

POSIX doit être lu, avant tout, pas comme un guide pour la programmation (quels programmes peuvent ou peut ne pas le faire) mais comme un ensemble d'exigences pour une implémentation qui accepte des programmes.

Il ne semble pas y avoir d'exigence dans POSIX qui dit qu'une implémentation ne doit pas faire un regex_t sensible à son adresse. Si tel est le cas, cela signifie qu'une telle implémentation ne manque pas d'être conforme.

C'est-à-dire que ce problème est souligné dans les zones d'exigences pour les flux FILE * et Les objets de synchronisation pthread peuvent n'avoir aucune implication dans d'autres domaines.


0 commentaires

2
votes

La spécification POSIX ici est plutôt mal écrite:

Si l'argument preg de regexec () ou regfree () n'est pas une expression régulière compilée retournée par regcomp (), le résultat n'est pas défini.

preg n'est pas un objet mais un pointeur vers un objet (il devrait donc dire quelque chose comme "ne pointe pas vers ...") et regcomp ne le fait pas le "retourne" (il modifie un objet pointé), mais l'intention de "est" semble être qu'il doit être le même objet, pas un autre objet avec la même valeur. J'interpréterais l'appel de regfree sur une copie comme une violation de ceci, entraînant un comportement indéfini.


1 commentaires

Je suis d'accord avec cette analyse.