2009-09-02 6 views
1

Une erreur d'exécution de débordement se produit lorsque mon programme C++ essaie d'écrire des images .png dans un répertoire.Echec d'écriture de l'image dans le répertoire

Le répertoire dans lequel les images sont écrites est donné en tant qu'argument de ligne de commande. Le programme est compilé avec gcc -ggdb3 -O3. Il est étrange que l'erreur disparaisse si je change le répertoire en un autre quand je le relance, ou si je compile mon programme sans optimisation. Je suis confus. Même si je peux obtenir les images produites par un exécutable non optimisé ou dans un autre répertoire, je doute que les résultats soient fiables car l'exécutable optimisé peut avoir une erreur d'exécution? Ou est-il possible que l'optimisation produise un exécutable sujet aux erreurs? Quelqu'un pourrait-il expliquer cela?

J'ai essayé de déboguer l'exécutable optimisé car il est compilé avec gcc -ggdb3 -O3, mais l'endroit où il produit une erreur de débordement ne donne pas le code source, que je ne peux pas obtenir une idée de:

(BDG) bt

# 0 0x00007fbd29573fb5 en augmentation() à partir de /lib/libc.so.6

# 1 0x00007fbd29575bc3 dans abort() à partir de /lib/libc.so.6

# 2 0x00007fbd295b3228 dans ??() À partir de /lib/libc.so.6

# 3 0x00007fbd296402c7 dans __fortify_fail() à partir de /lib/libc.so.6

# 4 0x00007fbd2963e170 dans __chk_fail() à partir de /lib/libc.so. 6

# 5 0x00007fbd2963d519 dans ??() À partir de /lib/libc.so.6

# 6 0x00007fbd295b7426 dans _IO_default_xsputn() à partir de /lib/libc.so.6

# 7 0x00007fbd29586fdb dans vfprintf() à partir de /lib/libc.so. 6

# 8 0x00007fbd2963d5b9 dans __vsprintf_chk() à partir de /lib/libc.so.6

# 9 0x00007fbd2963d500 dans __sprintf_chk() à partir de /lib/libc.so.6

# 10 0x0000000000408695 dans principal()

(gdb) f 10

# 10 0x0000000000408695 en main()

Langue actuelle: auto; actuellement asm

(gdb) Liste

1 /build/buildd/glibc-2.9/build-tree/amd64-libc/csu/crtn.S: Aucun fichier ou répertoire.

dans /build/buildd/glibc-2.9/build-tree/amd64-libc/csu/crtn.S

(gdb)

Je ne sais pas si la sortie du moteur d'exécution erreur pourrait aider à analyser le problème.Si elle pouvait, voici comment le message d'erreur ressemble, un peu grand temps que:

* débordement de tampon détecté *:/cis/home/tim/recherche/absurde/absurditylinux/binio21/libération/absurdité terminée

[Nouveau fil 0x7fbd2acd9740 (LWP 2347)]

======= Backtrace: =========

/lib/libc.so.6 (__fortify_fail + 0x37) [0x7fbd296402c7]

/lib/libc.so.6[0x7fbd2963e170]

/lib/libc.so.6[0x7fbd2963d519]

/lib/libc.so.6(_IO_default_xsputn+0x96)[0x7fbd295b7426]

/lib/libc.so.6(_IO_vfprintf+0x63b)[0x7fbd29586fdb]

/lib/libc.so.6(__vsprintf_chk+0x99)[0x7fbd2963d5b9]

/lib/libc.so.6 (__sprintf_chk + 0x80) [0x7fbd2963d500]

/cis/home/tim/recherche/absurde/absurditylinux/binio21/release/absurdité [0x408695]

/lib/libc.so.6(__libc_start_main+0xe6)[0x7fbd2955f5a6]

/cis/Accueil/tim/recherche/absurde/absurditylinux/binio21/release/absurdité [0x4045d9]

======= carte mémoire: ========

00400000-00471000 r-xp 00000000 00:39 52084894/cis/home/tim/recherche/absurdité/absurditylinux/binio21/libération/absurdité

00671000-00672000 r - p 00071000 52084894 00h39/cis/home/tim/recherche/absurde/absurditylinux/binio21/release/absurdité

00672000-00673000 rw-p 00072000 52084894 00h39/cis/Accueil/tim/recherche/absurde/absurditylinux/binio21/release/absurdité

00673000-00675000 rw-p 00673000 00:00 0

00943000-00964000 rw-p 00943000 00:00 0 [tas]

7fbd273f7000-7fbd29339000 rw-p 7fbd273f7000 00:00 0

7fbd29339000-7fbd29340000 r-xp 00000000 35791448 08:01 /lib/librt-2.9.so

7fbd29340000-7fbd2953f000 --- p 00007000 35791448 08:01 /lib/librt-2.9.so

7fbd2953f000 -7fbd29540000 r - p 00006000 35791448 08:01 /lib/librt-2.9.so

7fbd29540000-7fbd29541000 rw-p 00007000 35791448 08:01 /lib/librt-2.9.so

7fbd29541000-7fbd296a9000 r -xp 00000000 08:01 35791428 /lib/libc-2.9.si

7fbd296a9000-7fbd298a9000 --- p 00168000 35791428 08:01 /lib/libc-2.9.so

7fbd298a9000-7fbd298ad000 r - p 00168000 35791428 08:01 /lib/libc-2.9.so

7fbd298ad000-7fbd298ae000 rw-p 0016c000 08:01 35791428 /lib/libc-2.9.so

7fbd298ae000-7fbd298b3000 rw-p 7fbd298ae000 00:00 0

7fbd298b3000-7fbd298c9000 r-xp 00.000.000 08: 01 35790870 /lib/libgcc_s.so.1

7fbd298c9000-7fbd29ac9000 --- p 00016000 35790870 08:01 /lib/libgcc_s.so.1

7fbd29ac9000-7fbd29aca000 r - p 00016000 35790870 08:01 /lib/libgcc_s.so.1

7fbd29aca000-7fbd29acb000 rw-p 00017000 35790870 08:01 /lib/libgcc_s.so.1

7fbd29acb000-7fbd29ad3000 r-xp 00000000 71705955 08:01 /usr/lib/libgomp.so.1.0.0

7fbd29ad3000-7fbd29cd2000 --- p 00008000 08:01 71705955 /usr/lib/libgomp.so.1.0.0

7fbd29cd2000-7fbd29cd3000 r - p 00007000 71705955 08h01 /usr/lib/libgomp.so.1.0.0

7fbd29cd3000-7fbd29cd4000 rw-p 00008000 71705955 08h01/usr/lib/libgomp. so.1.0.0

7fbd29cd4000-7fbd29d58000 r-xp 00000000 35791436 08:01 /lib/libm-2.9.so

7fbd29d58000-7fbd29f57000 --- p 00084000 35791436 08:01 /lib/libm-2.9 .so

7fbd29f57000-7fbd29f58000 r - p 00083000 08:01 35791436 /lib/libm-2.9.so

7fbd29f58000-7fbd29f59000 rw-p 00084000 35791436 08:01 /lib/libm-2.9.so

7fbd29f59000-7fbd2a04a000 r-xp 00000000 71704918 08:01 /usr/lib/libstdc++.so.6.0.10

7fbd2a04a000-7fbd2a24a000 --- p 000f1000 08:01 71704918 /usr/lib/libstdc++.so.6.0.10

7fbd2a24a000-7fbd2a251000 r - p 000f1000 08:01 71704918/usr/lib/libstdC++ .so.6.0.10

7fbd2a251000-7fbd2a253000 rw-p 000f8000 08:01 71704918 /usr/lib/libstdc++.so.6.0.10

7fbd2a253000-7fbd2a266000 rw-p 7fbd2a253000 00:00 0

7fbd2a266000-7fbd2a27d000 r-xp 00000000 35791446 08:01 /lib/libpthread-2.9.so

7fbd2a27d000-7fbd2a47c000 --- p 00017000 35791446 08h01 /lib/libpthread-2.9.so

7fbd2a47c000-7fbd2a47d000 r - p 00016000 35791446 08h01 /lib/libpthread-2.9.si

7fbd2a47d000-7fbd2a47e000 rw-p 00017000 35791446 08h01 /lib/libpthread-2.9.so

7fbd2a47e000-7fbd2a482000 rw-p 7fbd2a47e000 00:00 0

7F

Programme a reçu signal SIGABRT, abandonné.

[Mise à Enfiler 0x7fbd2acd9740 (LWP 2347)]

0x00007fbd29573fb5 en augmentation() de /lib/libc.so.6

vraiment apprécier votre aide!

Merci pour votre intérêt!


@@ @@ MISE A JOUR: gars vous avez raison! J'ai augmenté la taille de la matrice char pour le nom de fichier long et maintenant c'est bien! L'exécutable est/cis/home/tim/research/absurdity/absurditylinux/binio21/release/absurdity. L'exécutable est/cis/home/tim/research/absurdity/absurditylinux/binio21/release/absurdity. Le répertoire qui ne fonctionne pas est spécifié en tant qu'argument de ligne de commande --result-path = ../results1/FrancContinuity1/noise0/train-imgs, qui est stocké dans global.result_path dans ce qui suit. Pourriez-vous me dire comment vous pensez que c'est le problème que vous avez mentionné? __sprintf_chk() et __vsprintf_chk() sont-ils toujours appelés par sprintf()?

Voici le code.

Partie 1:

 char filename[50]; 
     sprintf(filename, "%s/%d_%d.png", global.result_path, train_samples[n].label, train_samples[n].label==1 ? ++nb_pos : ++nb_neg); 
     train_samples[n].write_png(filename); 

Partie 2:

class Global { //parameters of program 
public: 
    int niceness; //The process scheduling priority 
    int random_seed; //The seed for the random sequence used in the computation 
    char result_path[1024]; //Where to store the generated results (images, logs, etc.) 
... 
} 

Global global; 
+0

Avez-vous du code disponible? Il me semble que vous avez un problème avec les arguments d'un appel à sprintf. comme peut-être la chaîne que vous imprimez aussi est trop petite? – Matt

+1

Hungry ... besoin de code! – count0

+0

Merci! S'il vous plaît voir mon édition à la fin de l'article original. – Tim

Répondre

3

Combien de temps est le nom du répertoire, et combien de temps est le tampon que vous essayez de le stocker dans? Vous ne nous avez pas donné grand chose à faire ... que diriez-vous de montrer du code? Peut-être un appel à sprintf quelque part dans main(), et les déclarations de toutes les variables impliquées?

Modifier: Il semble que le nom de fichier doit être un plus grand tableau, compte tenu de votre répertoire d'entrée et du nom de fichier que vous y ajoutez! Correctif rapide: essayez de le déclarer comme, disons, 1500 caractères au lieu de 50. Meilleure solution: puisque vous utilisez C++, regardez dans les classes std :: string et ostringstream, qui se redimensionneront pour éviter les dépassements de tampon.

Pour répondre à vos questions de suivi:

Le « ../ » dans votre résultat chemin ne devrait pas obtenir élargi dans un chemin absolu. Mon sentiment que sprintf() était impliqué était une supposition chanceuse, basée sur le message "buffer overflow" et les dernières lignes dans la traceback gdb. Je ne suis pas si familier avec les internes de la glibc, mais peut-être __sprintf_chk() et __vsprintf_chk() sont des variantes de vérification de dépassement de tampon de sprintf()?

+0

Merci! S'il vous plaît voir ma mise à jour à la fin de la publication originale. – Tim

+0

Merci! Un peu curieux cependant, pourquoi sans l'exécution de l'exécutable fonctionne bien, pas de débordement de tampon de rapport? – Tim

+0

@Tim: Ce bug engendre ce que l'on appelle un "comportement indéfini", c'est-à-dire qu'il peut s'écraser, il peut fonctionner correctement, il peut faire sortir des démons de votre nez. Probablement, le compilateur a réarrangé la disposition des données dans la version optimisée, donc quand vous débordez le tampon il clobffe quelque chose d'autre, provoquant le message d'erreur que vous avez vu. –

1

Eh bien, vous utilisez sprintf pour imprimer dans le tampon 'filename [50]' qui bien sûr a une longueur de 50.Maintenant, la chaîne que vous imprimez est un tampon de taille 1024, cela me semble être un problème potentiel. Que se passe-t-il lorsque global.result_path est plus long que 50 (encore moins en réalité, puisque vous imprimez aussi des entiers), et vous obtenez un débordement.

Essayez d'utiliser C++ std :: string et std :: stringstream, à savoir:

//Part 1: 

std::stringstream ss; 
ss << global.result_path << /* other data */; 
train_samples[n].write_png(ss.str().c_str()); 

//Part 2: 

class Global 
{ 
    std::string result_path; 
    ... 
} 

Avec le code ci-dessus, vous ne serez jamais à vous soucier de tampons de caractère débordant ou l'une des autres choses que laid.

2

Il y a longtemps que j'ai pris l'habitude d'utiliser snprintf partout. Apprenez à l'aimer. Il peut encore échouer à écrire le bon fichier, mais au moins il ne laissera pas un trou de sécurité.

Ensuite, après avoir commencé à vous demander pourquoi votre programme crée des fichiers nommés "this_is_a_long_file_na", vous pouvez revenir en arrière et le réparer pour utiliser un tampon de PATH_MAX ou un tampon mallocdé de taille dynamique. snprintf vous aidera à trouver la bonne taille si le tampon devait être plus grand. Ou vous pouvez passer en C++ et utiliser std :: string.

+0

+1 pour la référence PATH_MAX et en mentionnant que l'allocation dynamique ou std :: string serait certainement mieux –

1

Le chemin de résultat est trop petit.

Il suffit de modifier result_path à 1024. Certains systèmes ont la macro MAX_PATH définie. Je changerais aussi sprintf en snprintf avec la taille comme sizeof (result_path).

La fonction snprintf() est similaire à sprintf(), sauf que la longueur du tampon est donnée. Cela empêche les dépassements de tampon.

La valeur de retour est le nombre de caractères écrits. Si la sortie a été tronquée en raison de la limite buff_size, la valeur de retour est le nombre de caractères (sans compter le '\ 0' final) qui aurait été écrit dans la chaîne finale si suffisamment d'espace était disponible. Comme je savais que vous aviez un problème avec Sprintf était le backtrace.

à savoir

(gdb) bt 

#0 0x00007fbd29573fb5 in raise() from /lib/libc.so.6 

#1 0x00007fbd29575bc3 in abort() from /lib/libc.so.6 

#2 0x00007fbd295b3228 in ??() from /lib/libc.so.6 

#3 0x00007fbd296402c7 in __fortify_fail() from /lib/libc.so.6 

#4 0x00007fbd2963e170 in __chk_fail() from /lib/libc.so.6 

#5 0x00007fbd2963d519 in ??() from /lib/libc.so.6 

#6 0x00007fbd295b7426 in _IO_default_xsputn() from /lib/libc.so.6 

#7 0x00007fbd29586fdb in vfprintf() from /lib/libc.so.6 

#8 0x00007fbd2963d5b9 in __vsprintf_chk() from /lib/libc.so.6 

#9 0x00007fbd2963d500 in __sprintf_chk() from /lib/libc.so.6 

#10 0x0000000000408695 in main() 

à savoir Vous avez une fonction principale dans votre code. et __sprintf_chk est l'endroit où il va ventre. Vous deviez appeler sprintf. Après cela, il est mort. Donc, je suppose que vous passiez de mauvais arguments. La seule façon dont sprintf peut mourir si mal est avec un buffer overflow. Donc, c'est une bonne hypothèse que la chaîne que vous imprimez est trop petite. Utilisez snprintf et ce sera beaucoup plus sûr. Vous pouvez ensuite imprimer pour déboguer le résultat. Si vous aviez fait cela, vous auriez vu tout de suite que le tampon était trop petit car le chemin result_path aurait été tronqué à 50 caractères et le programme ne se serait pas écrasé (à ce moment-là au moins :).

Questions connexes