OVH Cloud OVH Cloud

Prb avec SetThreadContext/GetThreadContext

41 réponses
Avatar
Olivier
Bonjour,

J'ai un probleme avec les fonctions SetThreadContext et GetThreadContext
sous Windows XP cela fonctionne
mais sous Windows 2000 sur certains postes (apparemment du Pentium M 1.6
GHz)

Les registres Dr0, Dr1, Dr2, Dr3, Dr6, Dr7 ne sont pas restitués
correctement.
CONTEXT context;

context.ContextFlags = CONTEXT_DEBUG_REGISTERS;

context.Dr2=context.Dr0=0x123;

context.Dr3=context.Dr1=0x321;

context.Dr6=0xFFFF0FF0;

context.Dr7=0;

SetThreadContext(GetCurrentThread(), &context);

context.Dr2=context.Dr0=context.Dr3=context.Dr1=context.Dr7=context.Dr6=0;

context.ContextFlags=CONTEXT_DEBUG_REGISTERS;

GetThreadContext(GetCurrentThread(), &context);

// dr0 dr1 dr2 dr3 dr6 dr7 =0 -> c'est pas bon

Merci,

10 réponses

1 2 3 4 5
Avatar
Patrick Philippot
Bonjour,

J'ai un probleme avec les fonctions SetThreadContext et
GetThreadContext sous Windows XP cela fonctionne
mais sous Windows 2000 sur certains postes (apparemment du Pentium M
1.6 GHz)



Quel que soit le type de machine, comme le thread continue de s'exécuter
entre les 2 appels, il n'est pas surprenant que son contexte ait changé.
Si les résultats divergent entre plusieurs systèmes, c'est dû au fait
que les processeurs sont différents, que l'état du dispatcheur est
différent, etc.

--
Patrick Philippot - Microsoft MVP
MainSoft Consulting Services
www.mainsoft.fr
Avatar
Olivier
"Patrick Philippot" wrote in message
news:dr7i5h$oq5$
Bonjour,

J'ai un probleme avec les fonctions SetThreadContext et
GetThreadContext sous Windows XP cela fonctionne
mais sous Windows 2000 sur certains postes (apparemment du Pentium M
1.6 GHz)



Quel que soit le type de machine, comme le thread continue de s'exécuter
entre les 2 appels, il n'est pas surprenant que son contexte ait changé.
Si les résultats divergent entre plusieurs systèmes, c'est dû au fait que
les processeurs sont différents, que l'état du dispatcheur est différent,
etc.


Meme si le SetThreadContext et get sont fait pour le thread courant ?
Avatar
Patrick Philippot
Olivier wrote:
Meme si le SetThreadContext et get sont fait pour le thread courant ?



Peu importe.

Revenons sur le rôle de la structure de contexte d'un thread. A quoi
sert-elle essentiellement? A sauvegarder l'état des registres du
processeur et quelques autres informations au moment où le dispatcheur
(scheduler) interrompt ce thread, afin de pouvoir restaurer ce thread
exactement dans le même état au moment où le dispatcheur lui rendra la
main.

Or, un thread peut-être interrompu absolument n'importe où et n'importe
quand, donc à plus forte raison entre le SetThreadContext et le
GetThreadContext. Cela peut arriver ou ne pas arriver. Vous ne pouvez
être sûr de retrouver les mêmes infos que si vous avez suspendu le
thread avant le Set ou bien si ce thread est en suspendu pour une raison
quelconque (Waitxxxx).

En tous cas, c'est mon interprétation de la chose et ce résultat ne me
surprend pas. Mais peut-être suis-je dans l'erreur.

--
Patrick Philippot - Microsoft MVP
MainSoft Consulting Services
www.mainsoft.fr
Avatar
Remi THOMAS
"Olivier" écrivit
Bonjour,

J'ai un probleme avec les fonctions SetThreadContext et GetThreadContext
sous Windows XP cela fonctionne
mais sous Windows 2000 sur certains postes (apparemment du Pentium M 1.6
GHz)

Les registres Dr0, Dr1, Dr2, Dr3, Dr6, Dr7 ne sont pas restitués
correctement.
CONTEXT context;

context.ContextFlags = CONTEXT_DEBUG_REGISTERS;

context.Dr2=context.Dr0=0x123;

context.Dr3=context.Dr1=0x321;

context.Dr6=0xFFFF0FF0;

context.Dr7=0;

SetThreadContext(GetCurrentThread(), &context);

context.Dr2=context.Dr0=context.Dr3=context.Dr1=context.Dr7=context.Dr6=0;

context.ContextFlags=CONTEXT_DEBUG_REGISTERS;

GetThreadContext(GetCurrentThread(), &context);

// dr0 dr1 dr2 dr3 dr6 dr7 =0 -> c'est pas bon

Merci,





Bonjour,

Le plus souvent c'est parceque la structure CONTEXT n'est pas crée au bon
endroit.
Tu fais un new ou c'est sur la pile.
Sur la pile il y a de forte chance que la structure ait disparue quand tu y
accèdes.
La différence de comportement entre XP et 2000 c'est que sous XP
miraculeusement ton espace mémoire n'est pas écrasé après sa libération.
Sous 2000 oui.

Rémi

--
Rémi THOMAS
MVP Visual C++ .NET
http://www.pixel-technology.com/rthomas
Avatar
Patrick Philippot
Remi THOMAS wrote:
Le plus souvent c'est parceque la structure CONTEXT n'est pas crée au
bon endroit.
Tu fais un new ou c'est sur la pile.
Sur la pile il y a de forte chance que la structure ait disparue
quand tu y accèdes.



Salut Rémi,

En dehors de ce problème de gestion mémoire, j'aimerais bien ton avis
sur l'opinion que j'ai émise. A savoir que je ne vois pas pourquoi le
contexte resterait dans le même état si on laisse le thread s'exécuter.
Ou pour être plus clair, s'il a été interrompu au moins une fois entre
le Set et le Get. A moins que le scheduler ne se serve pas de la même
structure?

--
Patrick Philippot - Microsoft MVP
MainSoft Consulting Services
www.mainsoft.fr
Avatar
Vincent Burel
"Remi THOMAS" wrote in message
news:43d79c24$0$21351$
"Olivier" écrivit
> Bonjour,
>
> J'ai un probleme avec les fonctions SetThreadContext et GetThreadContext
> sous Windows XP cela fonctionne
> mais sous Windows 2000 sur certains postes (apparemment du Pentium M 1.6
> GHz)
>



Le plus souvent c'est parceque la structure CONTEXT n'est pas crée au bon
endroit.
Tu fais un new ou c'est sur la pile.
Sur la pile il y a de forte chance que la structure ait disparue quand tu


y
accèdes.
La différence de comportement entre XP et 2000 c'est que sous XP
miraculeusement ton espace mémoire n'est pas écrasé après sa libération.
Sous 2000 oui.



la pile n'est jamais écrasé (le systeme n'a pas que ca à faire), elle est
simplement utilisé... sous forme d'une pile. Les conséquences de cette
utilisation vont faire que les locales utilisées par une fonction seront
plus ou moins longtemps valide (en terme de contenu, car une pile est
toujours valide en terme d'adresse).

un erreur typique permet d'éclairer le propos :

long * FonctionQuiFaitUneBetise(void)
{
long n=0x12345678;
return &n;
}

ici on marque la pile d'un long dont on connais le contenu (0x12345678) et
on renvoie un pointeur dessus.
ce pointeur (toujours valide) vous permet de vérifier le contenu de la pile
à cette endroit, contenu qui sera modifié si vous appelez une fonction qui
se sert des 4 prochains octet de la pile entre temps.

long * FonctionQuiFaitUneBetisePlusFine(void)
{
char sz[1024]="";
long n=0x12345678;
return &n;
}

suivant les déclarations des locales la valeur en pile peut rester valide
plus longtemps. Ici on peut espérer que notre long sera déclaré dans la pile
après les 1024 char de notre string. (on ne peut qu'espérer car c'est
généralement le compilo 'c/c++' qui controle l'ordre de déclaration des
locales... )

VB
Avatar
Vincent Burel
"Remi THOMAS" wrote in message
news:43d79c24$0$21351$
"Olivier" écrivit
> Bonjour,
>
> J'ai un probleme avec les fonctions SetThreadContext et GetThreadContext
> sous Windows XP cela fonctionne
> mais sous Windows 2000 sur certains postes (apparemment du Pentium M 1.6
> GHz)
>



Le plus souvent c'est parceque la structure CONTEXT n'est pas crée au bon
endroit.
Tu fais un new ou c'est sur la pile.
Sur la pile il y a de forte chance que la structure ait disparue quand tu


y
accèdes.
La différence de comportement entre XP et 2000 c'est que sous XP
miraculeusement ton espace mémoire n'est pas écrasé après sa libération.
Sous 2000 oui.



la pile n'est jamais écrasé (le systeme n'a pas que ca à faire), elle est
simplement utilisé... sous forme d'une pile. Les conséquences de cette
utilisation vont faire que les locales utilisées par une fonction seront
plus ou moins longtemps valide (en terme de contenu, car une pile est
toujours valide en terme d'adresse).

un erreur typique permet d'éclairer le propos :

long * FonctionQuiFaitUneBetise(void)
{
long n=0x12345678;
return &n;
}

ici on marque la pile d'un long dont on connais le contenu (0x12345678) et
on renvoie un pointeur dessus.
ce pointeur (toujours valide) vous permet de vérifier le contenu de la pile
à cette endroit, contenu qui sera modifié si vous appelez une fonction qui
se sert des 4 prochains octet de la pile entre temps.

long * FonctionQuiFaitUneBetisePlusFine(void)
{
char sz[1024]="";
long n=0x12345678;
return &n;
}

suivant les déclarations des locales la valeur en pile peut rester valide
plus longtemps. Ici on peut espérer que notre long sera déclaré dans la pile
après les 1024 char de notre string. (on ne peut qu'espérer car c'est
généralement le compilo 'c/c++' qui controle l'ordre de déclaration des
locales... )

VB
Avatar
Cyrille Szymanski
"Vincent Burel" wrote in
news:43d7a39a$0$6689$:


long * FonctionQuiFaitUneBetisePlusFine(void)
{
char sz[1024]="";
long n=0x12345678;
return &n;
}



D'ailleurs en pratique tu peux "lire" l'historique de la pile tout à fait
légalement* :

#pragma optimize( "", off )
#define NB 100

void RemplirPile(void) {
int n[NB];
for(int i=0; i<NB; ++i)
n[i] = i;
}

void LirePile(void) {
int n[NB];
for(int i=0; i<NB; ++i)
if(i==n[i])
printf("%5dn", i);
}

int main(int argc, char **argv) {
RemplirPile();
LirePile();

return 0;
}

* Sauf que bien sûr cela n'a aucune garantie de renvoyer le résultat
attendu.

--
Cyrille Szymanski
Avatar
Vincent Burel
"Cyrille Szymanski" wrote in message
news:

int main(int argc, char **argv) {
RemplirPile();
LirePile();

return 0;
}

* Sauf que bien sûr cela n'a aucune garantie de renvoyer le résultat
attendu.



si tu fais rien entre les deux appels, j'ose espérer que si ! :-)

VB
Avatar
Arnaud Debaene
Patrick Philippot wrote:
Remi THOMAS wrote:
Le plus souvent c'est parceque la structure CONTEXT n'est pas crée au
bon endroit.
Tu fais un new ou c'est sur la pile.
Sur la pile il y a de forte chance que la structure ait disparue
quand tu y accèdes.



Salut Rémi,

En dehors de ce problème de gestion mémoire, j'aimerais bien ton avis
sur l'opinion que j'ai émise. A savoir que je ne vois pas pourquoi le
contexte resterait dans le même état si on laisse le thread
s'exécuter. Ou pour être plus clair, s'il a été interrompu au moins
une fois entre le Set et le Get. A moins que le scheduler ne se serve
pas de la même structure?



En tout cas, moi je suis d'accord ;-) GetTrheadContext n'a de toute façon de
sens que lorsque le thread cible est suspendu, tout simplement parce que
l'implémentation de GetThreadContext elle même va prendre plusieurs cycles
horloges, et pendant ce tmps le contexte du thread en question va changer
(EIP au moins, et peut être d'autres registres).

La doc de GetThreadContext le spécifie bien d'ailleurs :
"You cannot get a valid context for a running thread. Use the SuspendThread
function to suspend the thread
before calling GetThreadContext."

Conclusion : RTFM! ;-)

Arnaud
MVP - VC
1 2 3 4 5