Obligement - L'Amiga au maximum

Samedi 24 mai 2025 - 16:31  

Translate

En De Nl Nl
Es Pt It Nl


Rubriques

Actualité (récente)
Actualité (archive)
Comparatifs
Dossiers
Entrevues
Matériel (tests)
Matériel (bidouilles)
Points de vue
En pratique
Programmation
Reportages
Quizz
Tests de jeux
Tests de logiciels
Tests de compilations
Trucs et astuces
Articles divers

Articles in English


Réseaux sociaux

Suivez-nous sur X




Liste des jeux Amiga

0, A, B, C, D, E, F,
G, H, I, J, K, L, M,
N, O, P, Q, R, S, T,
U, V, W, X, Y, Z,
ALL


Trucs et astuces

0, A, B, C, D, E, F,
G, H, I, J, K, L, M,
N, O, P, Q, R, S, T,
U, V, W, X, Y, Z


Glossaire

0, A, B, C, D, E, F,
G, H, I, J, K, L, M,
N, O, P, Q, R, S, T,
U, V, W, X, Y, Z


Galeries

Menu des galeries

BD d'Amiga Spécial
Caricatures Dudai
Caricatures Jet d'ail
Diagrammes de Jay Miner
Images insolites
Fin de jeux (de A à E)
Fin de Jeux (de F à O)
Fin de jeux (de P à Z)
Galerie de Mike Dafunk
Logos d'Obligement
Pubs pour matériels
Systèmes d'exploitation
Trombinoscope Alchimie 7
Vidéos


Téléchargement

Documents
Jeux
Logiciels
Magazines
Divers


Liens

Associations
Jeux
Logiciels
Matériel
Magazines et médias
Pages personnelles
Réparateurs
Revendeurs
Scène démo
Sites de téléchargement
Divers


Partenaires

Annuaire Amiga

Amedia Computer

Relec


A Propos

A propos d'Obligement

A Propos


Contact

David Brunet

Courriel

 


Programmation : Les allocations mémoire
(Article écrit par Thomas Richter et extrait de GuruMed.net - décembre 2002)


Note : traduction par Olivier Fabre.

Cet article est la traduction directe d'un chapitre de la documentation de MuGuardianAngel, l'utilitaire de débogage écrit par Thomas Richter. Merci à lui pour cette documentation très complète et son autorisation de traduction et publication sur Guru-Meditation.net.

Certaines parties de cette documentation sont d'un niveau relativement élevé et/ou ne concernent que des usages spécifiques, donc si vous vous sentez un peu perdu, n'hésitez pas à passer à la suite de l'article !

Gestion correcte de la mémoire : éviter les "hits"

Si vous vous demandez comment les hits (écriture illégale en mémoire) MuGuardianAngel peuvent être évités, voici les règles à suivre pour allouer et libérer la mémoire correctement.

Les règles qui suivent s'appliquent à tous les programmes qui sont supposés tourner d'une façon respectueuse du système. Je ne les ai pas inventées. Ce que vous trouverez ici est plus ou moins une copie des règles situées dans le ROM Kernel Reference Manual, la documentation développeur officielle de l'Amiga.

Enfreindre ces règles conduira à des programmes instables, que ce soit avec ou sans utilitaires mémoire additionnels. Un programme qui crée des hits lorsque MuGuardianAngel tourne, mais fonctionne correctement sinon, est quoi qu'il en soit instable et pourrait planter dans certaines situations.

Allocations mémoire

Le drapeau MEMF_PUBLIC

Positionnez l'attribut MEMF_PUBLIC (exec/memory.h). C'est généralement nécessaire !

Ne pas positionner cet attribut entraîne l'allocation de mémoire qui :
  • a) est *privée* et réservée à votre tâche, c'est-à-dire qu'elle ne peut pas être lue depuis une quelconque autre tâche.
  • b) ne peut pas être lue en toute sécurité à l'intérieur d'une paire Forbid()/Permit() ou Enable()/Disable().
Le système d'exploitation actuel [NDT : AmigaOS 3.9 et inférieurs] n'implémente aucun test pour cette règle, et MuGuardianAngel non plus. Puisque la mémoire privée n'est pas sous le contrôle direct de MuGuardianAngel, ce type de mémoire n'est jamais rendu indisponible ou touché de quelque façon que ce soit par cet outil de débogage. Dans le futur, les gestionnaires de mémoire pourraient voir dans ce bit un indice indiquant la possibilité d'assigner de la "mémoire virtuelle" à l'allocation, c'est-à-dire de la mémoire qui peut être déplacée sur disque.

Par exemple, VMM requiert une utilisation correcte de cet attribut [NDT : toute mémoire allouée avec le drapeau MEMF_PUBLIC ne sera jamais déplacée sur le disque].

Toute mémoire supposée contenir des structures du système d'exploitation doit être allouée avec le drapeau MEMF_PUBLIC, de même que toute mémoire devant être lue par d'autres tâches, interruptions, exceptions, tampons d'entrées/sorties.

Les seules exceptions sont les structures privées qui ne sont lues ou écrites que par votre tâche, qui ne sont jamais passées ni lues ou écrites par d'autres processus ou fonctions du système d'exploitation, et ne sont pas lues lorsque le multitâche est désactivé.

Vidages de la mémoire

Soyez prêts à ce qu'une allocation mémoire puisse vider les bibliothèques, polices de caractères et périphériques logiques inutilisés de la mémoire. En particulier, n'utilisez pas de ressources fermées. Utiliser "FindName()" sur une liste de ressources d'exec n'est pas suffisant pour utiliser une ressource.

Si vous ne voulez pas que des ressources soient vidées de la mémoire, positionnez le drapeau MEMF_NO_EXPUNGE lors de l'allocation mémoire. Cf. exec/memory.h.

Voici un moyen sûr de vider la mémoire :

AllocMem(0x7ffffff0,MEMF_PUBLIC);

(c'est comme ceci que "Avail flush" vide la mémoire).

MuGuardianAngel ne signalera jamais un vidage de mémoire comme étant une allocation mémoire échouée, contrairement à MungWall.

La mémoire et les coprocesseurs de l'Amiga

La mémoire devant être lue par les coprocesseurs doit être allouée avec le drapeau MEMF_CHIP, sinon les coprocesseurs ne pourront pas y accéder. Ceci est valable pour :
  • Les zones d'affichage (bitmaps natifs [NDT : ne concerne donc pas les cartes graphiques]).
  • Les listes Copper matérielles (mais pas leurs abstractions graphiques pour la famille CMove(), CWait(), etc.).
  • Les bitmaps d'images (struct IntuiImage->ImageData).
  • Les tampons mémoire du lecteur de disquette (mais depuis la V37, ce n'est plus nécessaire pour les tampons mémoire d'entrées/sorties du trackdisk.device).
  • Les tampons mémoire du coprocesseur audio.
  • Les sprites matériels et les données des images des "Bobs".
  • Tout ce à quoi les coprocesseurs natifs pourraient accéder.
L'ordre des blocs de mémoire

Ne faites aucune supposition quant à l'ordre dans lequel vous obtenez de la mémoire. La deuxième allocation n'est pas forcément située à une adresse plus élevée !

L'attribut MEMF_FAST

N'utilisez pas l'attribut MEMF_FAST inutilement si de la mémoire Chip peut être OK pour vous également. Le système d'exploitation est suffisamment intelligent pour allouer de la mémoire Fast s'il y en a de disponible. Il se repliera sur la mémoire Chip s'il n'y a plus de mémoire Fast. Il n'y a en général aucune raison de demander explicitement de la mémoire Fast.

Alignement

Toute mémoire allouée avec AllocMem() est forcément alignée sur un multiple de deux mots longs [NDT : 8 octets], c'est-à-dire que les bits 0 à 2 de l'adresse seront toujours à zéro. Si vous avez besoin d'un alignement plus important, voyez l'astuce ci-dessous.

La taille des tampons

Faites bien attention à toujours allouer assez de mémoire pour le pire cas possible. En langage C, une chaîne nécessite n+1 octets de mémoire pour contenir une chaîne de longueur n. Certaines fonctions du système d'exploitation nécessitent, à cause de bogues, un tampon mémoire légèrement plus grand que ce qu'il pourrait vous sembler ; contrôlez la section "Bugs" des Autodocs (ce bogue affecte souvent les fonctions DOS, mais également certaines fonctions d'Intuition).

MuGuardianAngel est capable de détecter *certains* accès hors limites à la mémoire, mais en général, seulement lors de la libération de cette mémoire.

Attributs mémoire

Ne positionnez aucun attribut non documenté pour les attributs mémoire d'AllocMem(). Ils *pourraient* être ignorés sous cette version du système d'exploitation, mais ne le seront probablement pas dès la prochaine version. Regardez le fichier exec/memory.h pour y trouver les drapeaux valides. Dans la version actuelle (V40), les drapeaux suivants sont définis :

#define MEMF_ANY      (0L)     /* N'importe quel type de mémoire fera l'affaire */
#define MEMF_PUBLIC   (1L<<0)  /* Très important, Cf. les avertissements au-dessus ! */
#define MEMF_CHIP     (1L<<1)  /* Pour les coprocesseurs natifs ("custom chips") */
#define MEMF_FAST     (1L<<2)  /* Mémoire Fast, Cf. avertissements ! */
#define MEMF_LOCAL    (1L<<8)  /* Mémoire qui ne disparaît pas à la réinitialisation */
#define MEMF_24BITDMA (1L<<9)  /* Mémoire utilisable par le DMA dont l'adresse tient en 24 bits */
#define MEMF_KICK     (1L<<10) /* Mémoire utilisable pour les KickTags */
#define MEMF_CLEAR   (1L<<16)  /* AllocMem : rempli la zone de zéro (NULL) */
#define MEMF_LARGEST (1L<<17)  /* AvailMem : retourne la taille du plus grand bloc */
#define MEMF_REVERSE (1L<<18)  /* AllocMem : alloue du haut vers le bas */
#define MEMF_TOTAL   (1L<<19)  /* AvailMem : retourne la taille totale de la mémoire */

Contenu de la mémoire

N'émettez aucune hypothèse quant au contenu d'une zone de mémoire à moins que vous n'ayez spécifié l'attribut MEMF_CLEAR pour l'effacer. Ne pas positionner cet attribut rend l'allocation un peu plus rapide, mais dans ce cas, le bloc de mémoire peut contenir tout et n'importe quoi.

MuGuardianAngel tente d'être un peu méchant avec les programmes qui n'allouent pas la mémoire avec MEMF_CLEAR : au lieu de laisser la mémoire telle quelle, il la remplit avec un motif spécial non NULL.

Code auto-modifiant

L'usage de code auto-modifiant n'est pas conseillé. Si vous devez absolument jouer avec ça et ne pouvez pas faire autrement, utilisez l'appel système suivant pour vider les caches processeur une fois que votre code est placé en mémoire et doit s'exécuter :

ClearCacheU()

Ne vous attendez pas à ce qu'il soit en mémoire avant que vous appeliez cette routine. C'est encore plus important pour les routines comme les interruptions qui sont appelées de manière asynchrone.

Échecs

Soyez prêts à ce que votre requête de mémoire échoue. Un test explicite est requis après un appel à AllocMem() [NDT : ainsi qu'après toutes les autres fonctions d'allocation mémoire, bien sûr]. Se contenter de laisser le Guru apparaître dans le cas d'une allocation échouée n'est pas suffisant. Affichez un message d'alerte, quittez votre programme proprement, vérifiez votre code !

Pour ceux qui programment en assembleur : non, il n'est pas documenté qu'AllocMem() positionne le bit zéro si l'allocation a échoué. Vous devez faire le test vous-même.

Si vous l'appelez depuis un Process, les versions 37 et supérieures du système d'exploitation garantissent un code de retour de IoErr() égal à ERROR_NO_FREE_STORE (=103L).

MuGuardianAngel montrera les allocations mémoire échouées si l'option SHOWFAIL est activée. De plus, il essaye d'être méchant avec les programmes et change volontairement les registres d1/a0-a1 ou d0-d1/a0-a1 (aussi appelés "scratch registers") avant de quitter les routines de gestion de mémoire. Il positionnera aussi le drapeau Z pour tromper les programmes assembleur qui ne testent pas d0 correctement.

AllocMem() et les changements de contexte

Ni AllocMem() ni FreeMem() ne "cassent" un état "Forbid" [NDT : c'est-à-dire que si le multitâche est coupé, ces fonctions ne le restaureront pas]. C'est important car c'est la seule façon "d'afficher" une liste dont l'accès est protégé par Forbid() à l'aide de la dos.library et d'autres fonctions.

La séquence suivante permet de faire ceci légalement :
  • Appeler Forbid().
  • Faire une copie de la liste élément par élément, en utilisant AllocMem().
  • Appeler Permit().
  • Afficher la copie de la liste.
  • Libérer la mémoire.
Exécuter un Wait(), par exemple en utilisant un sémaphore pour protéger l'accès à la liste mémoire, serait ici fatal.

AllocMem(), FreeMem(), AllocAbs() et les interruptions

Aucune de ces fonctions ne peut être appelée depuis une interruption ou en mode superviseur.

Souvenez-vous, cependant, que les gestionnaires d'entrée ("input handlers") de l'input.device ne tournent pas sous interruptions mais dans le contexte de la tâche de l'input.device, bien qu'ils soient construits par-dessus une structure d'interruption. Par conséquent, appeler AllocMem() dans ce cas pour faire une copie d'un événement d'entrée est légal.

Libération de mémoire

Taille des désallocations

La taille d'une désallocation doit correspondre exactement à la taille de l'allocation. Il n'est pas autorisé de :
  • Arrondir la taille, car l'algorithme d'arrondi du système d'exploitation pourrait changer dans le futur pour gérer certains matériels (par exemple les lignes de cache du PowerPC qui font 32 octets).
Et aussi une autre règle qui n'a pas été mentionnée dans les RKRM :
  • Libérer un morceau de bloc de mémoire, c'est-à-dire une partie d'un tableau. Ceci est absolument illégal, pas d'exceptions, pas d'excuses. Libérez tout ou rien. Libérer un morceau d'un bloc de mémoire requiert la connaissance des règles d'alignement du système d'exploitation et pourrait rendre le programme instable et inefficace si ces règles changeaient dans de futures versions.
Je recommanderais donc fortement de ne pas utiliser cette technique.

MuGuardianAngel va détecter un hit si un programme essaye de libérer un bloc de mémoire d'une taille différente de celle avec laquelle il a été alloué. De plus, il détectera un hit si un programme essaye de libérer de la mémoire "non alignée", c'est-à-dire un bloc de mémoire dont l'adresse n'est pas multiple de 8 octets.

Cependant, les versions 37 et inférieures de la layers.library ne respectent pas cette règle (beurk !) ; cette bibliothèque est donc explicitement exclue de la gestion mémoire de MuGuardianAngel. Elle libère, malheureusement, des blocs de mémoire partiels.

Accès à la mémoire désallouée

Ne touchez pas à la mémoire désallouée. Si elle a été libérée, elle a été libérée et vous n'avez plus le droit de l'utiliser, d'y faire référence, de la lire ni d'y écrire. Une autre tâche pourrait la vouloir.

MuGuardianAngel marquera la mémoire libérée comme indisponible dès que possible. Si vous essayez d'y accéder, un hit se produira.

Une exception qui n'est pas formulée dans les RKRM mais est malheureusement largement utilisée : la désallocation de mémoire à l'intérieur d'une paire Forbid()/Permit(). La mémoire, sauf les huit premiers octets qui sont utilisés pour l'administration, reste non modifiée et prête à être utilisée tant que le multitâche est désactivé. Exécuter un Wait(), directement ou indirectement, annulera l'état "Forbid()" et rendra donc la mémoire inutilisable.

Soyez prévenus ! Bien que cet accès soit en quelque sorte légal, et donc toléré par MuGuardianAngel, ceci est tout de même "laid" selon moi et par conséquent fortement déconseillé. Une des très rares exceptions où ce comportement pourrait être utile se trouve dans le bout de code suivant, qui "décharge" le segment d'un programme "qui se charge et reste résident" :

move.l  SysBase(a4),a6
jsr     _LVOForbid(a6)
move.l  DOSBase(a4),a6
move.l  Segment(a4),d1
jsr     _LVOUnloadSeg(a6)   ; "Décharge" son propre code
move.l  a6,a1               ; ce code reste légal grâce
move.l  SysBase(a4),a6      ; au Forbid()
jsr     CloseLibrary(a6)    ; ferme la dos.library
moveq   #0,d0
rts                         ; quitte.

Notez que vous devez absolument être certain que le segment n'est pas un segment "overlay" car UnloadSeg() annulera l'état "Forbid()" dans ce cas. Cependant, ceci ne fonctionne pas pour les programmes qui se chargent et restent résidents de toute façon.

MuGuardianAngel garantit actuellement que la mémoire n'est pas rendue indisponible si elle est libérée lorsque le multitâche est coupé (état "Forbid()"). Elle est rendue indisponible dès que le multitâche est réinstauré. Contrairement à MungWall, MuGuardianAngel modifie cette mémoire et contrôle son intégrité dès qu'il en a le droit. Il testera même la mémoire deux fois : dès que FreeMem() est appelé, et une autre fois lorsque le multitâche est restauré.

Mémoire Chip et accès par le Blitter

La logique du Blitter utilise le DMA (Direct Memory Access = Accès direct à la mémoire) et accède à la mémoire Chip indépendamment du processeur. Si vous utilisez un tampon mémoire temporaire pour le Blitter, prenez garde à ce que le Blitter n'y accède plus avant de le désallouer. Pour en être sûr, appelez WaitBlit() avant de libérer de la mémoire qui a été utilisée comme tampon mémoire pour le Blitter.

MuGuardianAngel ne peut malheureusement pas détecter les accès illégaux à la mémoire Chip par le Blitter, car ceci est hors de contrôle de la MMU.

La mémoire et les accès DMA matériels

Les contrôleurs de disque dur modernes peuvent accéder à la mémoire par DMA, parallèlement au processeur. Si vous avez l'intention d'utiliser ce DMA matériel directement parce que vous écrivez un pilote de périphérique pour ce matériel, préparez-vous à vider les caches du processeur correctement. En particulier, appelez CachePreDMA(...) avant l'opération DMA et CachePostDMA(...) ensuite.

Consultez les Autodocs pour les détails de ces fonctions et leurs paramètres. Lisez-les, puis réfléchissez-y, puis lisez-les encore. C'est important que vous les compreniez correctement !

Valeur de retour

FreeMem() ne retourne aucune valeur utile, ni ne positionne de code de condition.

Comme toujours, MuGuardianAngel essayera d'être méchant avec les programmes et modifiera les registres "perdus" et les codes de condition.

AllocAbs() et autres curiosités

AllocAbs est destiné à une utilisation spéciale consistant à allouer de la mémoire à un emplacement prédéfini. Ne l'utilisez pas sans de bonnes raisons.

Portée de la mémoire allouée

AllocAbs() arrondi les adresses. Préparez-vous à ce que le bloc de mémoire que vous obtenez ne soit pas identique à celui que vous avez demandé. Cependant, si l'allocation est réussie, il est garanti que le bloc de mémoire demandé se trouve dans le bloc de mémoire retourné.

Attendez-vous à ce que votre requête ne puisse pas être satisfaite parce que la mémoire requise est déjà utilisée par une autre tâche.

Dans ce cas, AllocAbs() retourne NULL. Vous devez tester cela explicitement ! Aucun code de condition n'est positionné.

AllocAbs() ne positionnera pas le code ERROR_NO_FREE_STORE de IoErr().

MuGuardianAngel, comme toujours, remplira les registres perdus ("scratch registers") avec des valeurs insignifiantes et positionnera le drapeau Z pour amener les programmes mal écrits à une condition d'échec.

Contenu de la mémoire allouée

N'émettez aucune hypothèse quant au contenu du bloc de mémoire alloué. Le système d'exploitation utilise des parties des blocs de mémoire libres pour des raisons d'administration et pourrait avoir écrit dans des parties de blocs de mémoire.

Ceci signifie plus particulièrement pour les programmes résistant à la réinitialisation, dont la mémoire est allouée de cette façon par le mécanisme de KickMemPtr d'exec, que les huit premiers octets seront corrompus. Pensez-y !

MuGuardianAngel corrompra la mémoire allouée volontairement, sauf celle allouée par AllocAbs().

Libération de la mémoire allouée avec AllocAbs()

Pour être sûr que la mémoire allouée est réellement libérée complètement, appelez FreeMem() avec l'adresse et la taille de la mémoire que vous avez demandée, pas avec la valeur de retour d'AllocAbs(). Ceci peut paraître étrange, mais la logique de FreeMem() applique les mêmes arrondis de taille et d'adresse qu'AllocAbs(). Si vous passez néanmoins une adresse différente, comme la valeur de retour au lieu de l'adresse demandée, il n'est pas garanti que toute la mémoire sera libérée.

Un petit exemple pourrait être utile (en utilisant l'algorithme d'arrondi actuel) :

AllocAbs(0x07,0x300007);

...alloue 16 octets et retourne 0x300000. Appeler ensuite :

FreeMem(0x300000,0x07);

...ne libérera que huit octets en partant de 0x300000 au lieu de 16. Par contre :

FreeMem(0x300007,0x07);

...fonctionnera comme souhaité.

Cependant, MuGuardianAngel détectera ce dernier FreeMem() comme mal aligné. Il faut ignorer le hit dans ce cas.

Utiliser AllocAbs() pour allouer de la mémoire alignée

La routine suivante est une astuce pour allouer de la mémoire alignée :

void *AllocAligned(ULONG bytesize,ULONG attributes,ULONG alignment)
{
    UBYTE *mem,*res;

    alignment--;
    if (mem=AllocMem(bytesize+alignment,attributes & (~MEMF_CLEAR))) {
    Forbid();
    FreeMem(mem,bytesize+alignment);
    mem = (mem + alignment)&(~alignment);
    res = AllocAbs(bytesize,mem);
    Permit();
    if (res) {
        if (attributes & MEMF_CLEAR)
            memset(mem,0,bytesize);
        } else mem = NULL;
    }
    return mem;
}

Appelez cette routine avec "alignment" valant 16 pour aligner la mémoire sur une frontière de 16 octets. Il ne faut pas fournir une valeur qui ne soit pas une puissance de 2.

Notez que la mémoire est mise à zéro "à la main" si MEMF_CLEAR fait partie des attributs. Ceci doit être fait car AllocAbs() ne garantit pas le contenu de la mémoire, même si l'AllocMem() précédent a déjà initialisé la mémoire.

--------------------

Voilà, tout programme se conformant à ces règles ne causera aucun problème avec MuGuardianAngel !

Outils de débogage

Si vous écrivez un débogueur et que vous devez absolument lire de la mémoire non allouée, allez en mode superviseur pour la lire. MuGuardianAngel ne détectera que les accès à la mémoire "libre" en mode utilisateur.

Les outils de débogage suivants sont recommandés :
  • MuForce : détecte les accès à la base de vecteurs (VBR) et aux zones mémoire non alouées.
  • MuGuardianAngel (-: : détecte les accès à la mémoire "libre", les accès illégaux et hors de portée, ainsi que les problèmes mentionnés plus haut.
  • SegTracker : garde les noms des programmes associés à leurs segments chargés en mémoire afin d'identifier aisément le code. Utilisé par les programmes ci-dessus.
  • PatchWork : détecte les paramètres invalides lors des appels système.
  • Sashimi : redirige les hits MuGuardianAngel vers une fenêtre "console".
  • SaferPatches : détecte les correctifs de fonctions illégaux. Si celui-ci plante en faisant un Guru, il y a un problème.
Même un programme fonctionnant sans problème avec ces outils n'est pas obligatoirement exempt de bogues !

D'autres particularités pour les amateurs éclairés. (-:

Ce qui suit est une liste de caractéristiques du système d'exploitation dont vous devriez être conscient si vous avez l'intention d'écrire votre propre pool mémoire. Je les ai trouvés en écrivant PoolMem, donc les voici pour votre information. Cependant, n'utilisez pas ces techniques dans votre propre code.

Bien que les règles ci-dessus aient été mises en place pour les développeurs, ça ne veut pas dire que le système d'exploitation les respecte ("Quod licet Iovi non licet bovi").

J'ai trouvé les caractéristiques suivantes du système d'exploitation :
  • FFS (toutes les versions entre la V37 et la V43) s'attend à ce que FreeMem() retourne la valeur "-1". Ceci a été corrigé dans la version 43.20.
MuGuardianAngel provoque donc un code de retour étrange pour la fonction Close() pour les versions de FFS inférieures à la V43.20.
  • La version 37 de la layers.library alloue la mémoire par grands blocs, mais la libère en une suite de petites désallocations. En d'autres termes, elle découpe de grands blocs de mémoire en plus petits blocs.
La version actuelle de MuGuardianAngel contient un test spécial pour permettre ceci exclusivement pour la layers.library. Cependant, ceci a toujours été illégal, est illégal et continuera à être illégal. J'espère que ce fouillis a été nettoyé dans la V39.
  • Certains programmes s'attendent à ce que le drapeau Z (zéro) du processeur soit positionné lors d'un échec après un appel à AllocMem(), et ne le soit pas si l'allocation a réussi. Ceci n'est pas documenté.
MuGuardianAngel fera échouer ces programmes volontairement.


[Retour en haut] / [Retour aux articles]