Page 1 sur 1

[RESOLU] Erreur de type Invalid memory access

Publié : mer. 26/déc./2007 23:40
par Sami
Bonsoir,

Je programme actuellement un logiciel pour mes besoins. Celui-ci doit traduire une liste de mots en différente en langue via le service de traduction de google.

J'ai actuellement une erreur de type "Invalid memory access" lors de l'execution de mon programme avec la procédure ci-dessous. L'erreur apparait sur le "EndProcedure"

Code : Tout sélectionner

Procedure CreateTranslation(HackNull.b)
  AddMsgToLog("---------- Creation des fichiers de translation .tran ----------")
  ; Choix des traductions 
  Protected ErrorCode.b = 0 
  Protected WebPageSrc.s = LoadWebPageToString("http://www.google.fr/language_tools", @ErrorCode.b)        
  ; Selon le résultat de la fonction
  Select ErrorCode.b
    Case #HTTP_OK
      Debug WebPageSrc.s
    Case #HTTP_ERROR_PARAMETER
      AddMsgToLog("Error of parameters for the function LoadWebPageToMemory")
      EndBackgroundTask()
      ProcedureReturn
    Case #HTTP_ERROR_CONNECT
      AddMsgToLog("Connexion failed to the web site www.google.fr")
      EndBackgroundTask()
      ProcedureReturn    
    Case #HTTP_ERROR_MEMORY
      AddMsgToLog("Not enough memory to the buffer")
      EndBackgroundTask()
      ProcedureReturn    
  EndSelect
  EndBackgroundTask()
EndProcedure
Si je commente l'appel à la procedure "LoadWebPageToString", mon programme fonctionne parfaitement.
Je ne conprends pas les causes de cette erreur. J'ai cherché sur google les cas possibles pour ce type de problémes. Mais le peu de résultat concernant les exes PureBasic n'a pu éclairer ma lanterne.
J'aimerais connaitre les techniques pour traquer l'origine de ce message d'erreur.
J'ai cherché du coté des pointeurs que j'utilise beaucoup dans la procédure "LoadWebPageToString" mais rien ne me semble incorrecte.
Je ne peut poster l'ensembe du code source sur le forum. Cela représente 3000 lignes environ. Si nécessaire je peut créer une archive à télécharger avec l'ensemble du code.

Merci d'avance pour votre aide et de vos suggestions.

Publié : jeu. 27/déc./2007 1:19
par Backup
l'erreur a peut etre lieu dans ta procedure "EndBackgroundTask() " non ? :)

met un calldebugger et trace pas a pas ... :)

Publié : jeu. 27/déc./2007 11:29
par Sami
Bonjour,
Malheureusement non!
J'utilise cette procédure dans d'autres endroit du code et ca ne plante pas. De plus si je commente la fonction "LoadWebPageToString" le probléme disparait complétement.
J'ai suivit ton conseil au cas où. En mode pas à pas le probléme intervient bien lors de l'appel de "EndProcedure".
Je viens d'avoir un cas particulier aussi. J'ai une autre erreur "Invalid memory access" dans une procedure incluse dans "LoadWebPageToString".

Voici la procédure en question.

Code : Tout sélectionner

Procedure SendHTTPRequest(Con.q, Host.s, Path.s)
  If Con.q =< 0 Or Host.s = "" Or Path.s = "" 
    ProcedureReturn 
  EndIf
  ; On écrit la commande que l'on veut envoyer
  Protected Request.s = "GET " + Path.s + " HTTP/1.0" + #CRLF$
  Request.s = Request.s + "Host: " + Host.s + #CRLF$ 
  Request.s = Request.s + "Connection: Close" + #CRLF$ + #CRLF$ 
  ; On envoye la requête
  SendNetworkString(Con.q, Request.s) 
EndProcedure
Cela plante sur la déclaration de Protected Request.s.
Dans cette partie de code je n'utilise aucun pointeur.
A noter que ces fonctions fonctionne dans un thread. Donc la présence de la procédure "EndBackgroundTask()" m'est nécessaire pour terminer le thread proprement.

Merci de ton aide Dobro.
Ce bug va me rendre fou voila plus d'une semaine qu'il me même la vie dure.

Publié : jeu. 27/déc./2007 11:44
par Backup
Sami a écrit : A noter que ces fonctions fonctionne dans un thread.

as tu pensé a activer le mode "Thread Safe "des options de compilation ?? 8O

parceque le probleme peut venir de la !! :)

Publié : jeu. 27/déc./2007 11:54
par Anonyme2
Cela peut venir de plusieurs raisons
Problème d'allocation mémoire, de variable de chaine, de liste chainée, d'API ne fonctionnant pas correctement dans les Threads etc mais c'est aussi typique d'un écrasement des valeurs de retour de la pile

Dans ta procédure que tu incrimines, utiliserais-tu une structure prédéclarée par PureBasic ?
Si oui, controles sur le site de MS qu'elle correspond bien aux derniers OS car plusieurs structures dont la taille est "fausse" peuvent entraîner ce problème.

Je suis preneur du code pour chercher le problème, plus on est de fou plus on pleure :D

Publié : jeu. 27/déc./2007 11:57
par Sami
Oui l'option de compilation "Activer la gestion des threads" est coché.
J'ai oublié de préciser mais je compile le code avec PureBasic v4.10 sous windows XP.
Je vais tester afin de voir si j'ai le même probléme sous Linux ou MacOs.

Publié : jeu. 27/déc./2007 11:59
par Anonyme2
Essayes aussi d'ajouter à la fin de la procedure CreateTranslation, des instructions qui ne font rien , c'est pour ajouter des octets juste avant le retour de la procedure, ces nouveaux octets seront écrasés en lieu et place de ceux de la pile si le problème vient de là

On peut voir la procedure CreateTranslation ?

Publié : jeu. 27/déc./2007 12:07
par Sami
Dans la procedure "LoadWebPageToString" je n'utilise pas de fonctions API, ni de liste chainée, ni de structure prédéclarée.
Par contre, j'ai des allocations mémoire interne aux procédures et une sur une variable globale. J'utilise aussi des chaines de caractéres.

Voici l'archive contenant l'ensemble du code source.
http://samueldidier.free.fr/Data/TGE%20 ... anager.zip

Publié : jeu. 27/déc./2007 12:23
par Sami
J'ai rajouté la ligne Debug "Test" aprés "EndBackgroundTask()"
Cela ne change rien au probléme.
Par contre il arrive de maniére erratique que j'ai le même type d'erreur
dans la procédure "SendHTTPRequest" comme indiqué plus haut.

Code : Tout sélectionner

Procedure CreateTranslation(HackNull.b)
  AddMsgToLog("---------- Creation des fichiers de translation .tran ----------")
  ; Choix des traductions 
  Protected ErrorCode.b = 0 
  Protected WebPageSrc.s = LoadWebPageToString("http://www.google.fr/language_tools", @ErrorCode.b)        
  ; Selon le résultat de la fonction
  Select ErrorCode.b
    Case #HTTP_OK
      Debug WebPageSrc.s
    Case #HTTP_ERROR_PARAMETER
      AddMsgToLog("Error of parameters for the function LoadWebPageToMemory")
      EndBackgroundTask()
      ProcedureReturn
    Case #HTTP_ERROR_CONNECT
      AddMsgToLog("Connexion failed to the web site www.google.fr")
      EndBackgroundTask()
      ProcedureReturn    
    Case #HTTP_ERROR_MEMORY
      AddMsgToLog("Not enough memory to the buffer")
      EndBackgroundTask()
      ProcedureReturn    
  EndSelect

  EndBackgroundTask()
  Debug "Test"
EndProcedure
Ce qui est bizarre, c'est que dans les deux cas, il retourne une adresse qui reste la même entre deux executions. Mais qui est différente entre les deux erreurs.
Je m'explique dans le cas de l'erreur sur le "EndProcedure" dans "CreateTranslation", j'ai toujours (read error at address 118).
Dans le cas de l'erreur sur "Protected Request.s = ...", j'ai toujours (write error at address 114).
Comment visualiser le Heap à ces addresses? Je ne suis pas un pro de l'assembleur!! :D Il falloir que je trouve un bout de code tout prêt!

Publié : jeu. 27/déc./2007 16:36
par Anonyme2
Sami,

après quelques essais voilà ou se trouve le problème

J'ai d'abord eu une erreur du compilateur sur la procedure OpenHTTPConnection

il faut initialiser avec InitNetwork(), bien que cette instruction soit présente dans la procedure InitHTTPConnection(), j'avais l'erreur, peut-être que l'on passe sur cette instruction après et pas avant (?)

J'ai initialisé au début pour mes tests puis je suis arrivé à la procédure

Code : Tout sélectionner

ParseHTTPurl(URL.s, *Host, *Path, *Port)
qui faisait vraiment le plantage.

Dans cette procedure, les 3 derniers paramètres sont des pointeurs, jusque là pas de problème, mais j'ai regardé d'ou venait l'appel, par chance il n'y en a qu'un dans ton code et c'est dans la procedure

Code : Tout sélectionner

GetHTTP(URL.s, *ErrorCode, Folder.s = "", FileName.s = "")
Le problème vient de ces 2 lignes :

Code : Tout sélectionner

   Protected Host.s = "" ; Server's hostname 
  Protected Path.s = "" ; Remote path 
Lorsqu'une variable chaine est créée même vide comme c'est ton cas, il n'y a pas de mémoire allouée pour la chaine, le pointeur pointe sur un emplacement qui vaut 0, mais si de la place mémoire est allouée, alors à cet emplacement il y a l'adresse mémoire de la zone allouée.

Tu as plusieurs solutions comme par exemple allouer à ces chaines une taille plus grande que nécessaire, c'est ce que j'ai fait pour mes exemples.

Code : Tout sélectionner

  Protected Host.s = Space(100) ; Server's hostname 
  Protected Path.s = Space(100) ; Remote path 
Avec ce code, plus de plantage dans mes tests et j'ai une réponse
Par contre, ce n'est pas "élégant" et il n'est pas toujours possible de définir une taille suffisante à l'avance.
Le problème du code c'est que les chaines sont définies après le passage des pointeurs, c'est le contraire qu'il faudrait faire.

Voilà, tu n'as plus qu'à modifier et vérifier si tu n'utilises pas la même technique ailleurs.

A+
Denis

Publié : jeu. 27/déc./2007 19:37
par Sami
Denis,

Merci de ton aide.

J'ai suivit ton conseil et effectivement ca fonctionne.
J'ai réfléchit à la structure de la fonction "ParseHTTPurl" afin d'éviter ce genre de probléme.
Le mieux pour retourner plusieurs paramétres avec une procédure est d'utiliser les structures.
Voir ce lien pour plus d'infos.
http://www.purebasic.fr/english/viewtop ... 607a1828c0

Voici le code dans mon cas :

Code : Tout sélectionner

Structure HTTP_Url
  Host.s  ; Server's hostname 
  Path.s  ; Remote path 
  Port.l  ; Port number
EndStructure

Procedure ParseHTTPurl(URL.s, *ReturnData.HTTP_Url)
  If URL.s = "" Or *ReturnData.HTTP_Url =< 0 
    ProcedureReturn 
  EndIf
  
  ; Parse URL: 
  If FindString(URL.s, "http://", 1) = 1 
    URL.s = Right(URL.s, Len(URL.s) - 7)
  EndIf
  
  Protected Pos.l = FindString(URL.s, "/", 1) 
  If Pos.l = 0 
    Protected Host.s = URL.s 
    Protected Path.s = "/" 
  Else 
    Host.s = Left(URL.s, Pos.l - 1) 
    Path.s = Right(URL.s, Len(URL.s) - Pos.l + 1) 
  EndIf 
  
  Pos.l = FindString(Host.s, ":", 1) 
  If Pos.l > 0 
    Protected Port.l = Val(Right(Host.s, Len(Host.s) - Pos.l)) 
    Host.s = Left(Host.s, Pos.l - 1) 
  EndIf   
  
  ; On stocke les résultats
  *ReturnData\Host = Host.s
  *ReturnData\Path = Path.s
  If Port.l <> 0
    *ReturnData\Port = Port.l
  EndIf  
EndProcedure

  Protected WebSiteURL.HTTP_Url
  WebSiteURL\Port = #HTTP_DEFAULT_PORT 
  ParseHTTPurl(URL.s, WebSiteURL)

Cela résoud le probléme de limite pour les chaines de caractéres. On n'a pas besoin de la remplir avec un Spac(200).

Il serait peut être interressant que le compilateur de PureBasic génére un warning à la compilation ou à l'execution pour ce type d'erreur. Cela serait plus simple pour debugger.

En cas tout l'erreur venait d'une mauvais stucture dans mon code.

Encore une fois merci de ton aide Denis, tu me retire une sacré épine du pied. :wink:

Samuel

Publié : jeu. 27/déc./2007 22:25
par Anonyme2
Ca m'a changé les idées, à force d'être sur le même truc, je sature un peu.

Et puis j'ai vu ta technique de prog qui est différente de la mienne, c'est toujours intéressant.

Publié : ven. 28/déc./2007 11:33
par Sami
Denis,

Qu'en tu par technique de prog? Tu parle de l'architecture du programme?

Samuel

Publié : ven. 28/déc./2007 12:13
par Anonyme2
Sami a écrit :Denis,

Qu'en tu par technique de prog? Tu parle de l'architecture du programme?

Samuel
Oui, c'est ça, tu décomposes beaucoup plus que moi