12
votes

Superposant plusieurs champs de référence CLR les uns avec les autres dans la structure explicite?

edit: Je suis bien conscient de cela que cela fonctionne très bien avec les types de valeur, ma question spécifique consiste à utiliser ceci pour les types de référence.

EDIT2: Je suis également conscient que vous ne pouvez pas supervider les types de référence et les types de valeur dans une structure, il s'agit simplement de recouvrir plusieurs champs de type de référence les uns avec les autres.

Je bricole avec structurs dans .NET / C #, et je viens de découvrir que vous pouvez le faire: xxx

contournant essentiellement avoir à faire la coulée dynamique pendant l'exécution en utilisant une structure qui a explicitement Disposition de champ, puis accédant à l'objet à l'intérieur car c'est le type correct.

MAINTENANT ma question est la suivante: peut-il faire des fuites de mémoire en quelque sorte ou tout autre comportement non défini à l'intérieur du CLR? Ou est-ce une convention entièrement soutenue utilisable sans aucun problème?

Je suis conscient que c'est l'un des coins les plus sombres du CLR et que cette technique n'est qu'une option viable dans très peu de détails. cas.


0 commentaires

5 Réponses :


-1
votes

Je ne suis au courant d'aucune question avec elle. En outre, je doute que Microsoft permettrait à cette utilisation si elle était dangereuse de manière non évidente.


1 commentaires

Quelle est mon hypothèse aussi, mais cela ressemble à l'un des coins les très sombres du CLR et que je le souhaite assuré par une personne qui est à 100% sur elle.



1
votes

Je ne peux pas voir comment la version de mise en page explicite peut être vérifiable sans l'injection d'exécution des contrôles supplémentaires de toute façon , car cela vous permet de voir une référence non nulle à quelque chose de Le type déclaré.

Ce serait plus sûr: xxx

aucun risque de références déchirées, etc., et toujours un seul champ. Cela n'implique pas de code risqué, etc. En particulier, il ne risque pas quelque chose d'idiot comme: xxx

Un autre problème est que vous ne pouvez supporter qu'un seul champ. manière sauf si vous pouvez garantir le mode CPU; Le décalage 0 est facile, mais il devient plus difficile si vous avez besoin de plusieurs champs et devez prendre en charge X86 et X64.


12 commentaires

N'a pas vraiment répondu à ma question. Je voulais savoir s'il était possible de faire ce que j'ai demandé (et exactement ce que j'ai demandé). Pas une autre solution au même problème (car pendant que mon exemple ici est simplifié, le problème réel ne peut pas utiliser de type de référence).


Soin d'expliquer le bowvote? C'est une approche risquée "B> sérieusement ; Juste quelques brefs tests superficiels indiquent des éléments tels que System.SystemException - qui ne sonne pas comme quelque chose que vous voulez introduire! Même comme un risque . (Descriptions de message comme "" Impossible de trouver la méthode sur l'instance d'objet. ")


@THR - puis changez "Classe" à "STRIT". Ce n'était pas le plus important de la poste; Ici, je vais le changer pour vous ...


J'ai besoin de les garder dans la même position de mémoire. Vous n'avez tout simplement pas répondu à ma question. Bien sûr, vous avez fourni une autre solution, mais ce n'était pas ma question: «Comment puis-je résoudre cela de manière différente?", Était-ce?


J'ai également déclaré que je sais à quel point c'est stupide et à quel point les rares cas d'utilisation possibles sont exotiques. Et j'ai un de ces cas d'utilisation.


Votre version oblige également une distribution dynamique, ce que je voulais contourner en premier lieu (lisez votre code plus attentivement maintenant)


@THR - comptez les champs du type; Il y a exactement un champ. Comment est-ce pas "le même emplacement de mémoire"? Au cas où l'auto-accessoire est confus, je vais le débrouiller.


Oui comme je l'ai dit, j'ai vu cela (lire votre code plus attentivement) - mais votre version oblige une distribution dynamique et une vérification de type associée, que je ne peux pas me permettre. Je dis même que dans la question initiale: "Fondamentalement contourner la mise en phase dynamique pendant l'exécution en utilisant une structure qui a une disposition de champ explicite, puis accédant à l'objet à l'intérieur car il est bon type."


@THR - Qu'est-ce qui vous fait penser que vous ne pouvez pas vous permettre cela? Je ne suis pas étranger au code de performance (je suis actuellement en train d'utiliser ILGenerator pour faire Vérifiables Optimisations que le compilateur C # ne peut pas le faire) et une vérification de type ( ISInst ) est pas votre plus gros problème. Produire du code qui ne fait pas de choses stupides (voir SystemException ) est beaucoup plus important.


@THR - exécutez-le par coureur. Il est pas vérifiable. Alors prenez vos chances. Sur votre tête, que ce soit. Vous avez demandé des problèmes possibles; Je vous ai donné une alternative et certaines choses valides manifestement valables à regarder ( SystemException et "échec de la charge de type" ). Mais merci pour la négativité.


Je n'ai pas demandé des alternatives, car il n'y a pas d'alternative pour ce que je veux faire (performance sage).


@THR - mon mauvais; J'ai changé le phrasé à ce sujet.



2
votes

Si vous alignez le type de manière dangereuse, l'exécution lancera un Typeloadexception sur la charge même lors de la compilation avec / dangereux . Donc, je pense que vous êtes en sécurité.

Je suppose - puisque vous pouvez utiliser StructLayout et compiler votre code sans / dangereux drapeaux-- Il s'agit d'une caractéristique du CLR. Vous avez besoin de l'attribut StructLayout simplement parce que c # n'a aucun moyen direct de déclarer des types de cette façon.

Jetez un coup d'œil à Cette page qui détaille une partie de la façon dont C # Structs se traduit En IL, vous remarquerez qu'il y a beaucoup de dispositions de mémoire de la mémoire intégrées à l'IL / CLR elle-même.


1 commentaires

C'est ce que je suppose aussi, je veux juste que cela soit confirmé par une personne qui connaisse vraiment le CLR que cela ne peut en aucun cas que je ne peux en aucun cas créer des fuites de mémoire ou quelque chose d'autre comportement extrêmement non défini.



5
votes

Eh bien, vous avez trouvé un trou de boucle, le CLR le permet, car tous les champs superposés sont des objets. Tout ce qui vous permettrait de désordre avec une référence d'objet est directement rejeté avec une méthode Typeloadexception: xxx

mais vous pouvez l'exploiter en donnant les champs de classes. Rien de vraiment mauvais n'arrive aussi longtemps que vous ne lisez que les valeurs de champ, vous pouvez obtenir la valeur de la poignée de suivi de cette façon, par exemple.

écrire ces champs conduit à une exécution d'exécution. Je pense cependant que c'est un exploit si vous pouvez deviner correctement la valeur d'une poignée de suivi. Une utilisation pratique est suffisamment proche de zéro.


3 commentaires

Si je vous comprends correctement: tant que tous les champs qui se chevauchent sont des objets, il est prudent de lire et d'écrire à eux à l'aide du type correct (affectation essentiellement au champ asobject , puis en lisant à partir du Asfoo / asbar en fonction du type)? Si j'essaie de lire un foo à partir de asbar il va bien sûr casser. Il ne peut me donner aucune fuite de mémoire, etc. de quelque manière que ce soit?


@thth: Non, le collecteur des ordures n'a pas de problème avec elle.


@Hanspassant Il existe un cas particulier intéressant de tableaux superposés. Vous pouvez superposer des octets et une gamme d'intents. Ensuite, vous affectez un tableau d'octet N-Élément au champ d'octet [] et CLR pense que vous avez la matrice N-Element INT dans le champ Int []. Cela vous permet d'écrire en dehors de la mémoire assignée. Parfois, cela bloque l'application.



1
votes

Étant donné que le collecteur des ordures est non essuie et ne distingue que des références d'objet et des bits unis, les références qui se chevauchent ne le dérouleront pas. Toutefois, tandis que la référence d'un objet peut complètement chevaucher une autre, celle-ci n'est pas vérifiable, aka dangereuse (Standard ECMA-335, page 180, II.10.7 Contrôle de la mise en page). Il est facile de construire un programme qui exploite cette unité d'annulation à la crash horriblement: xxx

ici, l'appel Func charge un pointeur de fonction d'un dernier élément de la table virtuelle de la classe d'objet. Selon Cet article suivant la VTBL Il y a une table de poignée. Le traiter comme un pointeur de fonction conduit à un système.AccessviolationException.


0 commentaires