choper les stackoverflow sous morphos/gcc
-
/me d’accord avec Krabob sur l’histoire de pile.
/me d’accord avec Henes sur l’histoire de drogue.
/me à 26 ans… mais pas d’asm
Bon résumons pour mettre les choses au clair:
– Henes raison sur le fait qu’il n’est pas facilement possible de détecter un overflow de la pile et qu’il est impossible d’augmenter la taille de la pile si on utilise la pile définie au début (dans une certaine mesure, car on peut changer carrement de pile comme le dit Nico).
– Krabob a raison sur la façon dont la pile est gérée sur un principe Amiga classique. (mais ce qui veut dire que les applis Amiga classique crash donc de la même façon sur MOS que OS4.)
– Python sous A/Box ne sera jamais à l’abris d’un stack overflow (snif)
Maintenant embrassez-vous tous sur la bouche et sur le champ !
—
Donnez de la drogue à Krabob
/me voit pas pourquoi la pile d’une tâche ne pourrait pas être protégée.
A priori, mais je raconte peut-être une connerie plus grosse que moi (encore que ces temps-ci ça devient malheureusement difficile), il n’y a que la tâche qui accède à sa pile, ou me gourè-je ? Quel besoin a la pile de se trouver dans un espace mémoire public ?
Lanza a écrit :
/me voit pas pourquoi la pile d’une tâche ne pourrait pas être protégée.
A priori, mais je raconte peut-être une connerie plus grosse que moi (encore que ces temps-ci ça devient malheureusement difficile), il n’y a que la tâche qui accède à sa pile, ou me gourè-je ? Quel besoin a la pile de se trouver dans un espace mémoire public ?
parce que tout le fond du pb est que l’on ne peut gérer la mémoire protégée avec les applications Amiga Classique, voilà .. c’est tout con en faite. et tout en découle.
Bon c’est vrai tout le monde à raison, et seul le futur nous dira si les friedens sont foutu de faire ce qu’il disent (d’aprés moi, ça viendra.)
par contre, yomgui voici une précision: la MMU te permet de faire croire que une mémoire physiquement discontinue, est en fait continue, et ceci par tache. Ce qui a été annoncé par OS4 , c’est que avec le format d’executable actuel, on pourra a terme faire ceci:
-détecter quand la pile dépasse
-utiliser le MMU pour dire qu’a l’endroit de ce dépassement vient se caller une plage mémoire libre, adressable dans la contuité de la pile : du coup c’est idéal, la pile ‘prend’ ce qu’elle a besoin, et on garde un code de pile ABI classique à recullons.(et on économise la memoire qu’on prendrait en trop avec un systeme de pile a taille maximum fixe.)
c’est ce point que henes pense impossible à réaliser, pasque d’aprés lui on peut dépasser de 2 fois une plage par une alloc locale (en pile). Mais avec le MMU, tu peux déclarer tout espace adressable à la suite de la pile a continuer de la façon que tu veux, et agir en conséquence sur une exeption (on aurait une exception par plage dans la vie d’une tache.)
En fait je ne sais pas comment est/sera réellement fait OS4 en interne. donc on suppute.
Eurêka ! J’ai compris. En fait si qu’on dépasse la pile le souci c’est qu’on sait pas quoi qu’il y a derrière. Mais si derrière on mettait systèmatiquement une plage mémoire protégée en écriture ?
Nan? c’est encore idiot ce que je dis?
[edit]Ah ben vlà que j’a le même genre d’idée que krabob, moi… Faut que je me méfie[/edit]
parce que tout le fond du pb est que l’on ne peut gérer la mémoire protégée avec les applications Amiga Classique, voilà .. c’est tout con en faite. et tout en découle.
C’est un raccourci un peu facile. Rien ne t’empêche de protéger des plages mémoires, tant que tes applis et / ou le système n’ont pas besoin de taper dedans, si ? Et si on protège toute la mémoire en écriture tant qu’elle n’est pas allouée ? Ça marche pas non plus ?
/me va vraiment devoir se taper une doc sur les MMU…
1. mea culpa : J’ai pensé qu’Henes voulait initialiser le premier élément de son tableau (ce que j’ai écrit), et je n’ai pas vu son “bug”.
2. Quoiqu’il en soit, le fait de déclarer un tableau dans une fonction provoque sont allocation sur la pile, ce qui induit l’écriture d’informations “en dessous” de l’adresse courante (back chain, entre autres choses), et donc l’allocation d’une nouvelle page ou un dépassement de pile.
3. Il est possible d’utiliser le MMU pour marquer la dernière page possible comme étant invalide. Tout accès dans cette page provoque alors une exception, détectable. Néanmoins, toute écriture en dehors de cette page n’est pas détectée, donc ça ne sert pas à grand chose même si c’est mieux que rien.
4. L’absence de détection fiable interdit d’avoir un système d’allocation automatique de nouvelles pages (ce qui serait faisable en utilisant un adressage logique des nouvelles pages, grace au MMU).
5. La seule solution est d’utiliser une adresse logique pour la totalité de la pile (pile à une adresse commune à toutes les tâches et dans une zone suffisament vaste pour pouvoir être étendue dynamiquement sans conflits) mais cela soulève plusieurs problèmes :
– La configuration MMU doit être modifiée chaque fois qu’on commute sur une autre tâche pour changer la relation adresses logiques->adresses physiques.
– Les données stockées sur la pile deviennent privées : il n’est plus possible de les transmettre à une autre tâche sans recopie.
La solution “adresse logique” est jouable sous certaines conditions :
– les API utilisées copient par précaution les données destinées à d’autres tâches (au cas où elles seraient stockées dans la pile par erreur).
– L’application considérée est conçue pour ne pas utiliser la pile pour des données réputées “publiques”.
– L’exécutable signale cette caractéristique ce qui permet à l’OS de mettre en place une pile auto-extensible pour cette application.
Tout ceci est quand même très théorique, et c’est une grosse bidouille.
Finalement, la solution la plus viable compte tenu des problèmes de compatibilité ascendante serait d’avoir un compilateur capable de générer du code destiné à vérifier l’état de la pile en temps réel. Puisque la taille de la pile augmente à chaque appel de fonction, il est possible :
– de s’assurer que la taille allouée est suffisante avant de rajouter une nouvelle trame.
– d’allouer une ou plusieurs nouvelle(s) page(s) (remappée(s) avec le MMU) si ce n’est pas le cas.
kakace :
mouai… le pb est surtout que les applis doivent maintenant être correctement codées: on passe pas à une tache de la mémoire privée, et la pile c’est privée ! donc quand on veut transmettre des choses à une autre tâche on le fait par une zone publique. na!
Lanza :
C’est un raccourci un peu facile. Rien ne t’empêche de protéger des plages mémoires, tant que tes applis et / ou le système n’ont pas besoin de taper dedans, si ? Et si on protège toute la mémoire en écriture tant qu’elle n’est pas allouée ? Ça marche pas non plus ?
Non c’est pas un raccourci… c’est un résumé
Et non tu peux pas protéger efficacement tes tâches sous amigaos/68k. cela a déjà été pls fois dit, cf Henes et les autres qui devient fou à force de répéter les même choses (d’ailleur je leurs conseil d’aller sur Gurumed et de faire qq articles à ce sujets histoires de ne plus à avoir à répéter autre chose qu’une URL… ça ira + vite )
PS: j’ai commencé la doc Motorola sur les instructions PPC-603, et j’ai fait un petit code ASM pour __chkext1(). J’arrive à calculer la stack restante, donc j’éspére arriver à détecter mes stack-overflow (dans la limite des cas usuels) bientôt
Et non tu peux pas protéger efficacement tes tâches sous amigaos/68k. cela a déjà était pls fois dit, cf Henes et les autres qui devient fou à force de répéter les même choses (d’ailleur je leurs conseil d’aller sur Gurumed et de faire qq articles à ce sujets histoires de ne plus à avoir à répéter autre chose qu’une URL… ça ira + vite )
Je suis au courant, merci. Mais comme tu le fais si bien remarquer, la pile n’a pas à être en zone publique. Mettre des infos publique sur la pile c’est caca! Et les applications qui font ça ne méritent pas de tourner.
glo glop kakasse ruléze.
Il est possible d’utiliser le MMU pour marquer la dernière page possible comme étant invalide.
Comme henes le faisait remarquer: LES derniéres pages potentiellement allouable, et pas “la derniére” sinon les grosses alloc locale peuvent dépasser . (Il est possible ques des plages plus loin soient allouées) et donc potentiellemnt l’accés à ces plages non alloué peuvent être géré par exception.
La solution “adresse logique” est jouable sous certaines conditions :
– les API utilisées copient par précaution les données destinées à d’autres tâches (au cas où elles seraient stockées dans la pile par erreur).
– L’application considérée est conçue pour ne pas utiliser la pile pour des données réputées “publiques”.
– L’exécutable signale cette caractéristique ce qui permet à l’OS de mettre en place une pile auto-extensible pour cette application.
Tout ceci est quand même très théorique, et c’est une grosse bidouille.
Gloop glop kakasse, tu dis que des trucs interessant. Mais de mon point de vue,ce n’est pas une bidouille. Les contexte MMU varient par tache: c’est leurs raisons d’être !
Je viens de vérifier avec 2 appli identiques lancé en meme temps en mode debug sous windowsWP (mais j’avais déjà vérifié ça avec java sous win2000 ya un moment:)
En mettant un point d’arret en debut de main(), je vois que
la meme variable locale (en pile) pointe vers la meme adresse pour les 2 applications (qui tournent en meme temps.) pourtant elles pointent des memoires différentes ! C’est un comportement classique d’une pile moderne, alloué et adressé en privée! windows, linux, mac, java, font ça. (note à propos de java: sous intel, les pages mémoires “java” sont déclaré en big endian alors que le reste du systeme est en little endian !!! c’est dingue les MMU pour faire des contextes managés non ? )
Donc ça déplace le vrai probléme qui est de savoir si les taches peuvent fonctionner avec un OS protégé derrriére.
Ben moi je dis: si ça se peut. j’ai pas les docs là, mais je voulais vérifier: ya pas un attribut de la classe “message” de base qui contient la taille du message ?
Qui dit OS protégé dit protection mémoire, et tant qu’à faire mémoire virtuelle. Le rêve de beaucoup d’Amigaïstes depuis longtemps.
Le problème principal est que ce système impose d’incessantes recopies de données lors des communications entre tâches et accessoirement entre une tâche et l’OS (si nécessaire). C’est synonyme de ralentissement au niveau des API de communication inter-processus, et c’est la raison principale qui fait que l’AmigaOS et ses dérivés sont plus réactifs que les OS “protégés” (a ce sujet, les modifications incessantes du “maping” par le scheduler induisent aussi une baisse des performances).
Ces copies posent un problème avec les pointeurs, vu qu’ils référencent un objet via son adresse logique (et non pas physique), adresse logique qui ne correspond plus à rien si elle est utilisée telle quelle par une autre tâche. Or, pour des raisons de performance, l’AmigaOS utilise les pointeurs de manière extensive, y compris au sein de structures de données, ce qui rend cette copie très délicate (voire impossible ou trop coûteuse en temps). Pour contourner ce problème épineux, il faudrait revoir l’ensemble des APIs (et donc casser la compatibilité ou ajouter une couche d’abstraction supplémentaire et dont l’utilisation serait obligatoire) pour optimiser l’ensemble du système et le rendre “compatible” avec une mémoire protégée.
En résumé, l’AmigaOS que vous connaissez n’est pas adapté à une quelconque protection de la mémoire, par construction. Il a été conçu pour être rapide, réactif et peu gourmand en ressources, et les choix faits à l’époque compliquent énormément les choses d’autant plus que ces choix perdurent par la force des choses (habitudes de programmation, compatibilité ascendante, nouvelles implémentations inspirées du design originel, etc). Par exemple, où s’arrête l’OS (protégé) et où commencent les applications lorsque la plupart du code et des données sont partagés (bibliothèques, pilotes, etc) ?
C’est loin d’être simple et à moins d’un revirement radical (énorme travail de fond sur le design, nouvelles règles d’utilisation des API, nouvelles API, redéfinition de certains principes, etc), je vois mal MorphOS ou AmigaOS 4 proposer un tel système, propre, stable, transparent et performant dans un avenir plus ou moins proche.
zut je viens de perdre une heure a taper un mail et IE me l’a foiré. pas grave je recommence.
Hier soir j’ai pris vingt minutes pour parcourir exec.doc et ses .h Et je trouve que des choses évidentes apparaissent.
Rappel: exec a du être fait vers 1985 par sassenrath et à cette époque UNIX avait dejà la mémoire protégée. de plus
il est evident qu’amigaOS s’inspire d’UNIX dans son noyau. en 85, les 68000 n’avaient pas de MMU. il était évident que les 68000 évolueraient vers du MMU.
Partout on a la notion de “fabrique” (au sens des design pattern, gestionnaire encapsulé qui crée et détruit des objet.) comme dans un systeme protégé. Par exemple, pour créer un écran, tu donnes à OpenScreen() une description (taglist) privée, et on te renvoie un pointeur vers une mémoire publique, dont la logique
est d’etre en lecture seule pour la tâche. et on a une fonction de destruction: CloseScreen()
Je me suis interessé aux messages que tu dis si sensible: dans exec, on a CreateMsgPort() et DeleteMsgPort() pour créer des ports de gestion de message. On manipule juste leurs pointeurs: gestion encapsulé en public,et justement
les messages pointent ces ports. Et exec.doc nous met en garde de pas bricoler son port soit meme,comme par hazard.
Je me suis ensuite interessé a PutMsg() qui permet d’envoyer des messages alloués sois-meme en privée, donc qui
pourrait poser probléme. Je me suis d’abord aperçu qu’en 6 ans de prog systeme je ne l’ai jamais utilisé ! et pour cause
on utilise énormément GetMsg() mais PutMsg() est plutot utilisé en privé par le systéme. J’ai donc fait une
recherche sur des codes utilisant PutMsg( ) dans le conference developerCD (réputé bancal), pour ma culture: dans la moitié des cas, les messages créée le sont par des factory (Create/DeleteRexxMsg,…) Mais dans l’autre moitié, ok, c’est une alloc privée, puis une obligation
de remplir une struct message, puis un PutMsg(). Mais voilà, dans cette struct il faut forcément remplir nm_Length,
qui contient la taille de la structure. Cela permet potentiellement à l’OS de la copier vers une struct publique a l’execution de PutMsg().
En résumé, l’AmigaOS que vous connaissez n’est pas adapté à une quelconque protection de la mémoire, par construction.
Pourquoi les concepteurs amiga aurait spécifié de remplir ce champs depuis 1985 alors qu’il est inutile dans une contexte non protégé ? Parce qu’ils avaient prévu de basculer tout amigaOS en protection mémoire c’est évident. Tout les exemple utilisant PutMsg remplissent ce champ.
Le problème principal est que ce système (recopier des msg) impose d’incessantes recopies de données lors
des communications entre tâches et accessoirement entre une tâche et l’OS (si nécessaire). C’est synonyme de ralentissement au niveau des API de communication inter-processus, et c’est la raison principale qui fait que l’AmigaOS et ses dérivés sont plus réactifs que les OS “protégés”
je ne suis pas d’accord du tout, tu résonnes en 68000,un cpu sans cache, ou meme le code executé devait passer systematiquement par le bus lors de l’execution, ou la moindre lecture/ecriture passait du cpu a la ram. Si les autres OS ne sont pas réactif, c’est à cause de leurs politiques de memoire virtuelle qui va meme cacher de la memoire video, avec des notions de priorité pas applicables (windows).
Dans le cas de recopie de message: On a UNE SEULE COPIE DE STRUCTURE PAR CREATION DE MESSAGE vers une mem publique, pas plus !!, et ces structs sont de taille minimale ! le PowerPC quand il switche de contexte de tache ( un nombre important de fois par seconde,meme sans protection) doit empiler/depiler 384 octet de regsitres, et au moins la moitié a chaque saut de fonctions !!
ainsi Les flux mémoires du au simple fonctionnement du PPC sont énormément plus volumineux et fréquent qu’une copie de struct de temps en temps. et considérez ceci:
dans un systeme non protégé PowerPC, la lecture d’une struct en cache prend un certain temps (lecture).
La recopie de la méme struct vers une plage publique peut se faire avec dcbz (en interne): dans ce cas, la copie
prend PRESQUE AUTANT de temps que la lecture seule de la struct du message !!!
La protection mémoire n’est pas l’ennemie de la réactivité !!! faut arreter de penser 68000 !!! La protection mémoire sous AMigaOS est possible et on l’aura !
krabob :
Le pb n’est pas un pb d’API pour la protection mémoire (bien que dans certains cas…) mais surtout un pb de leur utilisation par les développeurs (parfois peu scrupuleux de lire les docs ) d’une part, et par la façon dont le système (le coeur) est conçus d’autre part. (et j’ai des doutes aussi sur la façon dont les fonctions sont générées dans le code).
En résumé: + un pb d’implémentation que d’architecture…
Il faut donc tout ré-emplémenter… mais on risque fortement de ne plus avoir de compatibilité avec les anciennes applis.
PS: y avais pas déjà un post au sujet de la protection de mémoire en général ?
- You must be logged in to reply to this topic.
› Forums › AmigaOS, MorphOS et AROS › Développement › choper les stackoverflow sous morphos/gcc