IdentifiantMot de passe
Loading...
Mot de passe oubli� ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les r�ponses en temps r�el, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++/CLI Discussion :

FieldInfo.SetValue recod� avec GetFieldOffset


Sujet :

C++/CLI

  1. #1
    Membre tr�s actif

    Profil pro
    �tudiant
    Inscrit en
    D�cembre 2004
    Messages
    499
    D�tails du profil
    Informations personnelles :
    �ge : 39
    Localisation : France

    Informations professionnelles :
    Activit� : �tudiant

    Informations forums :
    Inscription : D�cembre 2004
    Messages : 499
    Par d�faut FieldInfo.SetValue recod� avec GetFieldOffset
    J'ai enfin trouv� o� �tait cach� ce satan� FieldOffset dans l'objet RtFieldInfo.
    Pour ce faire j'ai mis un data break point sur l'adresse d'un champ, puis j'ai appel� Field.SetValue, �a m'a amen� au code assembleur de clr.dll et au champ non typ� RuntimeFieldHandle.m_ptr
    (clr.dll c'est du code non manag� mais heureusement ils ont laiss� dans le .pdb les noms des fonctions)
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
     
    // RuntimeFieldHandle.cpp : main project file.
     
    #include "stdafx.h"
     
    using namespace System;
    using namespace System::Reflection;
     
    // Je définis un type .NET avec plein de champs, 
    // et je retrouve bien l'offset 28 (en 32bit) pour le champ String ^s
     
    ref struct A {
    	Object ^h;
    	Int32 ^k,^l,^m,pp;
    	UInt32 a,b,c,d,e;
    	Object ^h2;
    private :
    	Type ^t;
    	Boolean p;
    	UInt32 a2,b2,c2,d2,e2;
    public:
    	String ^s;
    };
     
    generic <typename T> value struct FieldReference {
    	UInt32 offset;
    	Object ^obj;
     
    	value struct RuntimeFieldHandle_m_ptr {
    		UInt32 a,b,offset; // attention UInt32 est peut-être uniquement valable en 32bit
    	};
     
    	static UInt32 GetFieldOffset(FieldInfo ^f) {
    		RuntimeFieldHandle h = f->FieldHandle;
    		IntPtr value = h.Value;
    		RuntimeFieldHandle_m_ptr * m_ptr = (RuntimeFieldHandle_m_ptr *)(void*)value; // le type de value n'est pas communiqué par .NET : il faut le trouver soi-même
    		UInt32 res = m_ptr->offset;
                    // le premier bit est probablement un flag ?
    		res &= 0x7FFFFFF; // attention 0x7FFFFFF est peut-être uniquement valable en 32bit
     
    		return res +  sizeof(void*); // ajout de la VMT
    	}
     
     
    	FieldReference(Object ^obj, UInt32 offset) : obj(obj), offset(offset) {}
     
    	FieldReference(Object ^obj, FieldInfo^ fi) : obj(obj) {
    		offset = GetFieldOffset(fi);
    	}
     
    	FieldReference(Object ^obj, String ^fieldName) : obj(obj) {
    		Type ^t = obj->GetType();
    		FieldInfo ^fi = t->GetField(fieldName);
    		offset = GetFieldOffset(fi);
    	}
     
    	property T Value {
     
    		T get() {
    			pin_ptr<Object^> tmp = &this->obj;
    			void *ptr = (void*)tmp;
    			char *objadr = *(char**)ptr;
    			void *fieldadr = objadr + this->offset;
     
    			return (T)*(Object^*)fieldadr;
    		}
    		void set(T t) {
    			pin_ptr<Object^> tmp = &this->obj;
    			void *ptr = (void*)tmp;
    			char *objadr = *(char**)ptr;
    			void *fieldadr = objadr + this->offset;
     
    			*(Object^*)fieldadr = t;
    		}
    	};
    };
     
    int main(array<System::String ^> ^args)
    {
    	A ^a = gcnew A();
    	a->s = "avant";
     
    	FieldReference<String^> a_s(a,"s");
    	a_s.Value = "apres";
    	Console::WriteLine(a->s);
        return 0;
    }
    Je n'ai pas test� en 64 bit : la constante 0x7FFFFFF et les UInt32 de RuntimeFieldHandle_m_ptr deviennent peut-�tre des UInt64.

  2. #2
    Expert �minent
    Avatar de M�dinoc
    Homme Profil pro
    D�veloppeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 397
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    �ge : 41
    Localisation : France

    Informations professionnelles :
    Activit� : D�veloppeur informatique
    Secteur : High Tech - �diteur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 397
    Par d�faut
    �a, c'est du bas niveau comme je l'aime!
    Bravo pour ton investigation.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parl� avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  3. #3
    Membre tr�s actif

    Profil pro
    �tudiant
    Inscrit en
    D�cembre 2004
    Messages
    499
    D�tails du profil
    Informations personnelles :
    �ge : 39
    Localisation : France

    Informations professionnelles :
    Activit� : �tudiant

    Informations forums :
    Inscription : D�cembre 2004
    Messages : 499
    Par d�faut
    Je ne sais pas si tu savais mais je viens de regarder : les pin_ptr ont un co�t nul ou presque. C'est juste une variable locale et une instruction lea (ldarga ou ldloca en MSIL), je suppose donc que c'est uniquement quand le garbage collector passe qu'il r�pertorie les pin_ptr et marque les objets correspondant comme "ne devant pas bouger (et donc restant dans la m�me g�n�ration ?)".

    C'est cool mais �a n'est pas tr�s consistant avec GCHandle par exemple (gcroot) qui fait je ne sais combien d'op�rations (dans la propri�t� Target) pour r�cup�rer l'objet, alors qu'en th�orie il suffit d'une indirection de pointeur. D'ailleurs j'ai peur qu'au milieu du code de GCHandle.Target.get il n'y ait pas un truc du genre : "si le garbage collector est en train de passer, alors aller chercher le Object^ � un autre endroit" (comme je l'ai d�j� dit, en temps normal le GCHandle est simplement un Object^* [ dans le cas du gcroot donc du GCHandle(.., GCHandleType::Normal) je n'ai pas trop regard� les autres] ).

    Une autre mis�re de .NET est qu'on ne peut pas pinner dynamiquement un array<Object^> (si on fait un GCHandle(.., GCHandleType:: Pinned) sur un array, .NET il dit � l'ex�cution que ce n'est pas blittable...), r�sultat on est oblig� d'utiliser les gcroot vu qu'on ne peut pas coder soi-m�me son propre m�canisme d'allocation dynamique d'Object^.

    (C'est cool de trouver quelqu'un qui aime bien le "hardcore .NET". A mon taf je suis le seul que �a fasse rigoler, et j'avoue que j'ai l'impression de monologuer tout seul quand je raconte que Java ferait bien de faire comme .NET et de g�n�rer des exceptions compatibles avec les exceptions SEH et d'inclure des instructions de manipulation pointeur dans leur bytecode.)

  4. #4
    Expert �minent
    Avatar de M�dinoc
    Homme Profil pro
    D�veloppeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 397
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    �ge : 41
    Localisation : France

    Informations professionnelles :
    Activit� : D�veloppeur informatique
    Secteur : High Tech - �diteur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 397
    Par d�faut
    Je ne sais pas comment �a marche � bas niveau, mais dans le CIL le pin est juste un mot-cl� pinned sur une d�claration de variable locale.

    Dans la Emit, �a se sp�cifie dans ILGenerator.DeclareLocal().
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parl� avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

Discussions similaires

  1. SetValue pour un lookup avec simple quote dans EntityType
    Par VITALTH dans le forum Microsoft Dynamics CRM
    R�ponses: 1
    Dernier message: 19/08/2014, 19h49
  2. recoder MethodInfo->Invoke avec il.Emit
    Par acx01b dans le forum C++/CLI
    R�ponses: 10
    Dernier message: 22/02/2014, 21h39
  3. R�ponses: 2
    Dernier message: 20/01/2014, 12h19
  4. Recoder une variable avec l'op�rateur contains
    Par 5natacha dans le forum D�butez
    R�ponses: 10
    Dernier message: 25/05/2012, 17h04
  5. R�ponses: 4
    Dernier message: 29/05/2007, 17h04

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo