[C] System.AccessViolationException

Résolu/Fermé
Utilisateur anonyme - Modifié par Saachaa le 4/10/2012 à 20:44
 Utilisateur anonyme - 8 oct. 2012 à 12:19
Bonjour, bonsoir,

De ce que j'ai vu ici : https://stackoverflow.com/questions/4269938/an-unhandled-exception-of-type-system-access-violation-exception-occured-in-h

Je merdouille avec les tableaux...

Pourtant je ne fais rien de mal me semble-t-il !

char * db_registry [size_reg_key][2] = {{"HKEY_LOCAL_MACHINE", "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run"},  
          {"HKEY_LOCAL_MACHINE", "SOFTWARE\\Microsoft"}};  

fprintf(rapport, "\n\n::::: Registry :::::\n\n\n");  
    
 HKEY key;  

 printf(db_registry[0][0]);  
 printf(db_registry[0][1]);  

 printf("\n\n");  

 printf(db_registry[1][0]);  
 printf(db_registry[1][1]);  
    
 system("pause");  

// ici, j'obtiens bien ce que j'ai dans mon tableau, mais dès que je sors de la pause, boum, le message de violation.  

 for (i = 0 ; i < size_reg_key ; i++)  
 {  
 char * full_key = strcat(db_registry[i][0], db_registry[i][1]);  

  if (RegOpenKeyExA((HKEY) db_registry[i][0], db_registry[i][1], 0, KEY_READ, &key) == ERROR_SUCCESS)  
  {  
   fprintf(rapport, full_key);  
  }  
 }  


Donc deux questions :

1 - Comment se fait-il qu'un tableau commence à 0 ??

2 - Qu'est-ce qui provoque cette erreur, car j'ai le même soucis dans un autre morceau de code...

Merci à vous !


Edit:: Capture: http://puu.sh/1bnwY



♪♪ Slowin' Cleaner development, Windows Optimizer

8 réponses

fiddy Messages postés 11069 Date d'inscription samedi 5 mai 2007 Statut Contributeur Dernière intervention 23 avril 2022 1 842
4 oct. 2012 à 20:57
1 - Comment se fait-il qu'un tableau commence à 0 ??
Ben, ça toujours été comme ça. Et c'est logique :
toto[0] signifie toto+0, on ne perd pas de case mémoire.

printf(db_registry[0][0]);
Ecriture très dangereuse. Mets plutôt : printf("%s",db_registry[0][0]);

char * full_key = strcat(db_registry[i][0], db_registry[i][1]);
Aïe.
db_registry[i][j] est de type char* (c'est-à-dire pointeur sur une zone en lecture seule). Autrement dis, tu cherches à écriture dans une lecture en lecture seule. Et là, ça passe pas.
Utilise plutôt un malloc au lieu du char*. Et alloue une zone suffisamment grande.
1
Utilisateur anonyme
4 oct. 2012 à 21:19
Coucou Fiddy,

printf(db_registry[0][0]);
Ecriture très dangereuse. Mets plutôt : printf("%s",db_registry[0][0]); 


Pourquoi ?

Ben, ça toujours été comme ça. Et c'est logique :
toto[0] signifie toto+0, on ne perd pas de case mémoire. 


toto[0] ne vaut pas le nombre de lignes ?

db_registry[i][j] est de type char* (c'est-à-dire pointeur sur une zone en lecture seule)


Peux-tu m'expliquer cela ?

char * = C'est un pointeur (zone en mémoire) vers une chaîne de caractères, elle n'est pas modifiable ?

Et je le place comment mon malloc ?

Qu'est-ce que je dois mettre en mémoire ?

Pas de sizeof() pour le malloc ?

Merci de ta réponse :-)
0
fiddy Messages postés 11069 Date d'inscription samedi 5 mai 2007 Statut Contributeur Dernière intervention 23 avril 2022 1 842
Modifié par fiddy le 4/10/2012 à 21:58
printf(db_registry[0][0]);
Ecriture très dangereuse. Mets plutôt : printf("%s",db_registry[0][0]);

Car printf est de type printf(const char*format, ...). Avec ce genre de code, un pirate pourrait s'amuser à lire des zones en mémoire. Par exemple si db_registry[0][0] contient des %s ou autre.

toto[0] ne vaut pas le nombre de lignes ?
Non. int toto[3]={1,2,3}; En mémoire, l'adresse mémoire est toto qui contient la valeur 1, à l'adresse toto+1, on a 2, et à toto+2 on a 3.

char * = C'est un pointeur (zone en mémoire) vers une chaîne de caractères, elle n'est pas modifiable ?
Cela dépend de ce que tu mets derrière.
char *chaine="toucou"; A l'adresse mémoire toto, tu as l'adresse de la chaîne "toucou" (stocké dans la zone en lecture seule). Tu ne pourras donc pas faire chaine[0]='c';
En revanche, tu pourras bien faire chaine="coucou"; (mais ce sera une autre chaîne).

Et je le place comment mon malloc ?
Par exemple, char * db_registry [size_reg_key][2]=malloc(255); ou alors db_registry [size_reg_key][2][255] =

Pas de sizeof() pour le malloc ?
Si tu fais char*toto=malloc(10);
sizeof(toto)=4 (cela dépend de la machine) car toto est un pointeur (char *)
Mais, si tu fais char toto[10], sizeof(toto) = 10; car toto est un tableau.
0
Utilisateur anonyme
4 oct. 2012 à 23:22
 Avec ce genre de code, un pirate pourrait s'amuser à lire des zones en mémoire. Par exemple si db_registry[0][0] contient des %s ou autre. 


Puis-je avoir un peu plus d'explication là dessus ? Il lira le contenu de mon: db_registry ?

</code> malloc(sizeof(db_registry));</code>

ça ça ne marche pas ? J'aimerais un truc du genre pour ne pas avoir à déclarer un buffer trop grand ou trop petit, ce n'est pas "propre". :-)


Et je le place comment mon malloc ?
Par exemple, char * db_registry [size_reg_key][2]=malloc(255); ou alors db_registry [size_reg_key][2][255] =


Désolé rien compris,

Merci de ton aide,
0
Char Snipeur Messages postés 9813 Date d'inscription vendredi 23 avril 2004 Statut Contributeur Dernière intervention 3 octobre 2023 1 298
5 oct. 2012 à 14:17
sizeof(db_registry) ne te renvoi pas la longueur de la chaine.
La première chose à faire lorsque l'on utilise une fonction est de regardé son manuel http://www.linux-kheops.com/doc/man/manfr/man-html-0.9/man3/strcat.3.html
en gros,
char *fullkey=malloc(strlen(db_registry[i][0]+strlen(db_registry[i][1]) );
strcat(fullkey,db_registry[i][0]);
strcat(fullkey,db_registry[i][1]);

ne pas oublier aussi qu'à chaque malloc doit correspondre un free, sinon gare aux fuites de mémoire (ton programme prend de la taille jusqu'à l'infini).

Pour revenir sur l'histoire du toto[0]; Un pointeur est une adresse mémoire, pour lire ce qu'il y a en mémoire, on utiliser l'opérateur '*' (*toto est la valeur de la case mémoire toto). Lorsqu'on alloue de la mémoire de manière "étendu" avec malloc, on peut alors accéder à cette mémoire par block (dépendant du type sous jacent du pointeur). toto[2] est le 3ème bloc mémoire. Il y a une autre façon d'accéder à cette mémoire, toto étant toujours une adresse mémoire (le début de la zone) si on se déplace un peu on accède aux autres données : *(toto+2) est la troisième case. *(toto+0) est la première. D'où le commencement à 0.
0
fiddy Messages postés 11069 Date d'inscription samedi 5 mai 2007 Statut Contributeur Dernière intervention 23 avril 2022 1 842
6 oct. 2012 à 14:15
Char Snipeur,
Attention, malloc n'initialise pas à {0}. Donc, tu peux pas enchainer avec un strcat sans avoir pris le soin d'initialiser fullkey.
0
Utilisateur anonyme
5 oct. 2012 à 15:31
Huuummmm, d'accord !

J'ai compris, le pointeur et la mémoire :-)

Cependant, est-ce là même chose ici avec DWORD ?

#define size_files 2

char * db_files [size_files] = {"C:\\force_delete.txt", 
								"C:\\ComboFix.txt"};

DWORD Attributes;

for (i = 0 ; i < size_files ; i++)
{
	if (_access(db_files[i], 0) != -1)
	{
		hFile = CreateFileA((LPCSTR) db_files[i], GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

		if (GetFileTime(hFile, &ftCreate, &ftAccess, &ftWrite))
		{
			// Convert the created time to local time. set +1

				FileTimeToSystemTime(&ftCreate, &stUTC);
						SystemTimeToTzSpecificLocalTime(NULL, &stUTC, &stLocal);

				Attributes = GetFileAttributesA(db_files[i]);

			fprintf(rapport, "0x%x - [%02d/%02d/%d %02d:%02d] - %s\n", Attributes, stLocal.wDay, stLocal.wMonth, stLocal.wYear, stLocal.wHour, stLocal.wMinute, db_files[i]);
		}
		else
		{
			fprintf(rapport, "[error: %d] : %s\n", GetLastError(), db_files[i]);
		}

		CloseHandle(hFile);   
	}
}

0
Char Snipeur Messages postés 9813 Date d'inscription vendredi 23 avril 2004 Statut Contributeur Dernière intervention 3 octobre 2023 1 298
5 oct. 2012 à 19:16
je n'ai pas compris le sens de ta question...
Tu as encore une erreur ?
0
Utilisateur anonyme
5 oct. 2012 à 20:40
Oui, là même, mais avec un autre bout de code.

Cela se produit lorsque je mets:

fprintf(rapport, "0x%x - [%02d/%02d/%d %02d:%02d] - %s\n", Attributes, stLocal.wDay, stLocal.wMonth, stLocal.wYear, stLocal.wHour, stLocal.wMinute, db_files[i]);


Dans le fprintf.

Et je ne sais pas d'où cela peut provenir, souhaites-tu une capture ?
0
Char Snipeur Messages postés 9813 Date d'inscription vendredi 23 avril 2004 Statut Contributeur Dernière intervention 3 octobre 2023 1 298
5 oct. 2012 à 21:48
non, la capture ne sert à rien.
C'est quoi rapport ? donne noous sa définition et son initialisation
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
Utilisateur anonyme
6 oct. 2012 à 12:13
Bonjour,

J'ai préféré te donner tout le code, il n'y a pas grand chose:

https://pjjoint.malekal.com/files.php?read=20121006_z14u8k12n14g9

Sachant aussi que j'ai un autre sujet en cours:

https://forums.commentcamarche.net/forum/affich-26195289-c-handle

Pour pouvoir créer un handle sur un dossier :-)

Deux sujets car deux problèmes différents,

Merci ;-)
0
fiddy Messages postés 11069 Date d'inscription samedi 5 mai 2007 Statut Contributeur Dernière intervention 23 avril 2022 1 842
6 oct. 2012 à 12:22
fprintf(rapport, "[%02d/%02d/%d %02d:%02d] - %s\n", Attributes, stLocal.wDay, stLocal.wMonth, stLocal.wYear, stLocal.wHour, stLocal.wMinute, db_files[i]);
Tu as 5%d et 1%s pour 7 variables. Il manque quelquechose.

const char * report_path = strcat(getenv("HOMEDRIVE"),"\\SHZ_LookUp.txt");
Bizarre que cela ne plante pas.
Pour info, strcat concatène les deux arguments et mets le résultat dans la première variable (ici getenv("HOMEDRIVE")).
0
Utilisateur anonyme
6 oct. 2012 à 12:32
 Tu as 5%d et 1%s pour 7 variables. Il manque quelquechose. 

J'ai enlevé le: " 0x%x", mais oublié d'enlever le: Attributes (à force de test), si je rajoute le: " 0x%x", j'obtiens l'erreur.

Je pensais à balancer trop d'informations dans le printf / fptrintf qui le faisait hurler pour la mémoire.

Pour info, strcat concatène les deux arguments et mets le résultat dans la première variable (ici getenv("HOMEDRIVE")).

Je ne comprends pas ce que tu veux, dire... Mais comme je l'ai fait, cela fonctionne parfaitement, pour cela que j'étais étonné que ça ne fonctionne pas (voir mon post initial).
0
Char Snipeur Messages postés 9813 Date d'inscription vendredi 23 avril 2004 Statut Contributeur Dernière intervention 3 octobre 2023 1 298
6 oct. 2012 à 13:49
mon message est passé à la trappe, mais ça viens peut être de rapport ? C'est quoi cette variable ?
0
fiddy Messages postés 11069 Date d'inscription samedi 5 mai 2007 Statut Contributeur Dernière intervention 23 avril 2022 1 842
6 oct. 2012 à 14:15
Je pensais à balancer trop d'informations dans le printf / fptrintf qui le faisait hurler pour la mémoire.
Pas avec si peu d'informations. Il y a certainement une erreur ailleurs.

Je ne comprends pas ce que tu veux, dire... Mais comme je l'ai fait, cela fonctionne parfaitement, pour cela que j'étais étonné que ça ne fonctionne pas (voir mon post initial).
Ce n'est pas parce que ça fonctionne cette fois que c'est correct. Cela provoque des débordements en écriture en mémoire. Cela fonctionne jusqu'au jour où on se demande ce qui se passe. C'est ce genre d'erreur qui peut modifier des variables, et provoquer des bugs plus loin dans le code...
Je rexplique plus en détails :
char dest[100]="Bonjour ";
char src[]="Saachaa";

strcat(dest,src);
//dest a été modifié. Désormais dest vaut : "Bonjour Saachaa";
Là j'ai mis : char dest[100]; donc il y a de la place pour contenir "Saachaa". S'il n'y avait pas la place (genre char dest[9];) cela pourrait s'avérer catastrophique (sans pour autant bugguer immédiatement).
Dans ton strcat(getenv(...)), tu vas faire pareil. Tu vas rajouter "\\SHZ_..." à la suite de la chaîne pointée par getenv(...) dont tu ne peux pas gérer l'allocation.
Il faut donc allouer une chaîne :
char fichier[255]; //ou avec malloc
strcpy(fichier,getenv(...)); //ou encore mieux avec strncpy
strcat(fichier, "\\SHZ_...");
0
Utilisateur anonyme
6 oct. 2012 à 15:00
@Char Sniper,
rapport = fopen("chemin_de_mon_rapport", "w");


Cela me permet de tout écrire (mes résultats) dans un rapport avec fprintf().

@Fiddy,

Donc,

strcat("1","2");


Dans le 1, il n'y a pas assez de place pour avoir 2. Il faut donc allouer un espace en mémoire c'est ça ?

Pourquoi est-ce mieux d'utiliser strcpy ?

J'ai modifié ainsi:

char home[255];
	strcpy(home, getenv("HOMEDRIVE"));
	const char * report_path = strcat(home,"\\SHZ_LookUp.txt");


Et cela passe avec Attributes !

C'était donc ça ! Cependant je pense que je vais encore devoir user un peu de ton temps pour assimiler cela ;-)

Merci,
0
Utilisateur anonyme
6 oct. 2012 à 16:03
D'accord merci pour ces réponses, je progresse petit à petit,

Pour sptrinf() je pensais que ça affichait le résultat à l'écran un peu comme printf(), mais visiblement non...

Je suppose qu'avec malloc, on peut attribuer juste ce qu'il faut de mémoire ?

Car ici,

char home[255];
	strcpy(home, getenv("HOMEDRIVE"));
	const char * report_path = strcat(home,"\\SHZ_LookUp.txt");


255 me semble élevé, et d'un autre côté je ne veux pas incrémenter manuellement le bazar jusqu'à la bonne valeur :-)

Aussi, j'ai remarqué qu'il y a erreur lorsque je tente d'afficher une chaîne de caractère mal formatée, par exemple en voulant afficher du DWORD avec %s au lieu de %x...

(si ça peut aider quelqu'un)

Merci, ;-)
0
fiddy Messages postés 11069 Date d'inscription samedi 5 mai 2007 Statut Contributeur Dernière intervention 23 avril 2022 1 842
6 oct. 2012 à 16:35
Pour sptrinf() je pensais que ça affichait le résultat à l'écran un peu comme printf(), mais visiblement non...
La différence entre sprintf et printf est que le premier affiche dans une chaîne (en premier argument) et non à l'écran (fichier stdout). Voilà pourquoi sprintf est approprié ici.

Je suppose qu'avec malloc, on peut attribuer juste ce qu'il faut de mémoire ?
Yes. Encore faut-il connaître la taille. Pour info, on dit "allouer" et non "attribuer" de la mémoire.

255 me semble élevé, et d'un autre côté je ne veux pas incrémenter manuellement le bazar jusqu'à la bonne valeur :-)
Cela ne se fait pas au hasard ^^.
Il suffit de faire :
char *home;
home=malloc(strlen(getenv("HOMEDRIVE"))+strlen("\\SHZ_LookUp.txt")+1);
strcpy(home,getenv("..."));
strcat(home,"\\SHZ...");
Et tu as la bonne taille :-).

Aussi, j'ai remarqué qu'il y a erreur lorsque je tente d'afficher une chaîne de caractère mal formatée, par exemple en voulant afficher du DWORD avec %s au lieu de %x...
Normal. %s c'est pour afficher une chaîne. DWORD n'est pas une chaîne...
0
Utilisateur anonyme
6 oct. 2012 à 17:06
D'accord, je vais assimiler tout cela, merci !!

Avant de partir:

	char * home;
	(ligne 43) home = malloc(strlen (getenv("HOMEDRIVE")) + strlen("\\SHZ_LookUp.txt") +1);
	strcpy(home, getenv("HOMEDRIVE"));

	const char * report_path = strcat(home, "\\SHZ_LookUp.txt"); 


Me renvoie:

1>Database.cpp(43): error C2440: 'initialisation' : impossible de convertir de 'void *' en 'char *'
1> La conversion de 'void*' en pointeur vers non 'void' nécessite un cast explicite



Et je n'arrive pas à le caster comme il le faut...
0
fiddy Messages postés 11069 Date d'inscription samedi 5 mai 2007 Statut Contributeur Dernière intervention 23 avril 2022 1 842
7 oct. 2012 à 00:38
Database.cpp
Ah on en apprend des choses :-). Tu programmes en C++ et non en C.
Ce sont deux langages distincts. Du coup, certaines choses C ne fonctionnent pas en C++ comme la promotion automatique du type void*.
Tu dois donc mettre : (char*) devant le malloc.
Mais, je te conseille plutôt de vraiment programmer en C pour ne pas prendre de mauvaises habitudes ou alors de faire du C++. Dans ce cas, il faudra simplement utiliser l'opérateur new.
0
Utilisateur anonyme
7 oct. 2012 à 11:40
Coucou Fiddy,

Nah, pas de C++ pour le moment, je n'en n'ai pas envie et qui plus est, c'est plein de trucs incompréhensibles à mon niveau !

En fait, je suis sous Visual C++ qui, fait aussi du C.

Je devrais sans doute migrer sous CodeBlocks, mais j'aime bien Visual C++ et m'y suit habitué.

J'ai essayé de caster Malloc, mais ça n'avait pas marché me semble-t-il, je vais regarder cela.

Quel bazar, merci pour votre aide j'ai appris pas mal de choses,

Le C++ c'est pour plus tard, ;-)
0
fiddy Messages postés 11069 Date d'inscription samedi 5 mai 2007 Statut Contributeur Dernière intervention 23 avril 2022 1 842
7 oct. 2012 à 19:08
Database.cpp
Certes, mais en mettant une extension en .cpp, il s'agira de C++...
Si tu veux vraiment faire du C, renomme ton fichier en Database.c
Et là, tu n'auras pas besoin de caster ton malloc. :-)
0
Utilisateur anonyme
7 oct. 2012 à 21:13
Je te fais ça de suite et je regarde s'il braille :-)

J'espère qu'il n'y aura pas d'incompatibilité, car je l'aime bien Visual,
0
Utilisateur anonyme
8 oct. 2012 à 12:19
Oups, y'a pas mal de choses à modifier et ce n'est pas le top pour moi qui risque de tout péter (j'aime bien trifouiller les réglages).

Je pense laisser ainsi, du toute manière je vais devoir aller vers le C++ un jour prochain alors... :-)

Merci pour votre aide, j'ai beaucoup appris !

A bientôt, ...
0