26 votes

Est-ce que malloc est déterministe ?

Est-ce que malloc est déterministe ? Disons que j'ai un processus forké, c'est-à-dire une réplique d'un autre processus, et qu'à un moment donné les deux appellent la fonction malloc. Est-ce que l'adresse allouée serait la même dans les deux processus ? En supposant que les autres parties de l'exécution soient également déterministes.

Remarque : Ici, je parle uniquement de la mémoire virtuelle, pas de la mémoire physique.

27voto

Flexo Points 39273

Il n'y a aucune raison que cela soit déterministe, en fait il peut y avoir certains avantages à ce qu'il ne le soit pas, par exemple accroître la complexité de l'exploitation de bugs (voir aussi cet article).

Cette aléatoire peut être utile pour rendre l'écriture d'exploits plus difficile. Pour exploiter avec succès un débordement de tampon, vous devez généralement faire deux choses :

  1. Livrer une charge utile dans une zone mémoire prévisible / connue
  2. Forcer l'exécution à sauter à cet emplacement

Si l'emplacement mémoire est imprévisible, faire ce saut peut devenir beaucoup plus difficile.

La citation pertinente de la norme §7.20.3.3/2 :

La fonction malloc alloue de l'espace pour un objet dont la taille est spécifiée par la taille et dont la valeur est indéterminée

S'il était prévu d'en faire une version déterministe, cela serait clairement indiqué en ce sens.

Même si cela semble déterministe aujourd'hui, je ne parierais pas sur le fait que cela reste ainsi avec un noyau plus récent ou une version plus récente de la libc/GCC.

11voto

Tommy Points 56749

La spécification C99 (du moins, dans son dernier projet public) indique dans 'J.1 Comportement non spécifié':

Les éléments suivants ne sont pas spécifiés: ... L'ordre et la contiguïté de l'espace alloué par des appels successifs aux fonctions calloc, malloc et realloc (7.20.3).

Il semblerait donc que malloc n'ait pas à être déterministe. Il n'est donc pas sûr de supposer qu'il l'est.

7voto

Adam Rosenfield Points 176408

Cela dépend entièrement de l'implémentation de malloc. Il n'y a aucune raison inhérente pour laquelle une implémentation particulière de malloc introduirait de la non-déterminisme (sauf éventuellement comme test d'application, mais même alors, cela devrait être désactivé par défaut). Par exemple, le malloc de Doug Lea n'utilise pas rand(3) ou des méthodes similaires dans celui-ci.

Mais, comme malloc fait des appels au noyau tels que sbrk(2) ou mmap(2) sur Linux ou VirtualAlloc sur Windows, ces appels système peuvent parfois ne pas être déterministes, même dans des processus par ailleurs identiques. Le noyau peut décider de fournir intentionnellement des adresses mmap différentes dans différents processus pour une raison quelconque.

Donc, pour de petites allocations, qui sont généralement traitées dans l'espace utilisateur sans appel système, il est très probable que les pointeurs résultants seront les mêmes après un fork(); de grandes allocations qui sont traitées par un appel système peuvent être les mêmes.

En général, cependant, ne comptez pas dessus. Si vous avez vraiment besoin de pointeurs identiques dans des processus séparés, créez-les avant de les bifurquer, ou utilisez la mémoire partagée et partagez-les de manière appropriée.

2voto

minjang Points 4437

Il dépend des implémentations détaillées de malloc. Une implémentation typique de malloc (par exemple, dlmalloc) utilisée était déterministe. Cela est simplement dû au fait que l'algorithme lui-même est déterministe.

Cependant, en raison de nombreuses attaques de sécurité telles que les attaques par débordement de tas, malloc, qui est un gestionnaire de tas, a introduit une certaine aléatoire dans ses implémentations. (Mais, son entropie est relativement faible car les gestionnaires de tas doivent prendre en compte la vitesse et l'espace) Il est donc sûr de ne pas supposer un déterminisme rigoureux dans les gestionnaires de tas.

De plus, lorsque vous bifurquez un processus, il existe diverses sources de hasard, y compris ASLR.

2voto

Jerry Coffin Points 237758

Oui, c'est déterministe dans une certaine mesure, mais cela ne signifie pas nécessairement qu'il donnera des résultats identiques dans deux forks d'un processus.

Pour donner un exemple, la spécification Single Unix dit : "[...] pour éviter les erreurs, le processus enfant ne peut exécuter que des opérations sûres pour les signaux asynchrones jusqu'à ce qu'une des fonctions exec soit appelée."

Que ce soit pour le meilleur ou pour le pire, malloc n'est pas dans la liste des fonctions "sûres pour les signaux asynchrones".

Cette limitation se trouve dans une section qui parle des programmes multithreadé, mais ne spécifie pas si la limitation s'applique uniquement aux programmes multithreadés, ou s'applique également aux programmes à un seul thread.

En conclusion : vous ne pouvez pas compter sur malloc pour produire des résultats identiques dans le parent et le fils. Si le programme est multithreadé, vous ne pouvez pas compter sur malloc pour fonctionner du tout dans le fils, jusqu'à ce qu'il ait appelé exec - et il y a place à se demander raisonnablement s'il est effectivement garanti de fonctionner même dans un fils à un seul thread avant que le fils appelle exec.

Références:

  1. Spécification de fork
  2. Fonctions sûres pour les signaux asynchrones

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X