GNT sans publicité, site mobile, fonctionnalitées exclusives...

Bug indétectable via printf() / cout

Le
AG
Bonjour à tous,

Je travaille dans une équipe de personnes pour lesquels le débugger
n'est pas l'outil qui tombe sous le sens lorsqu'il s'agit de trouver
les bugs des outils qu'ils ont développé.

Afin de les sensibiliser, je recherche un exemple de bug difficile
(voir impossible) a détecter via des printf()/cout qui n'afficheraient
que les contenus des variables. (Je me rends bien compte qu'on doit
pouvoir tout débugger avec printf()/cout, mais il faut parfois
afficher les adresses des variable (en plus de leur valeur), voir
parfois la mémoire à certains endroits.)

Je voudrais construire un exemple simple (notions de C++ pas trop
compliquées) et court (un seul fichier, 100 lignes max) pour qu'on
puisse l'étudier en un quart d'heure, mais le débugger en un temps
presque infini sans débugger.

Il est possible que l'exemple, puisqu'il y a un bug, dépende de la
plateforme mais c'est un peu inévitable.

L'idéal serait que le plantage ait lieu bien après le bugça rajout=
e
du piment. Bref, vous voyez l'idée quoi

J'avais plusieurs pistes d'exploitation de bug:

Piste 1:
Boucle for décroissante sur un entier non signé : for(size_t i = N;
0<= i; i--)

Piste 2:
comparaison de double : double x; ; x == 0.0

Piste 3:
retour de malloc() non testé

Piste 4:
caractère de fin de ligne non testé (\0)

Mais jusque là, je crains qu'il ne soit trop facile de détecter le
bug

J'ai donc ensuite pensé aux références. Mais ce code est encore un pe=
u
trop voyant. Dans le main(), on peut facilement se demander pourquoi
f1 et f2 sont des références, ce qui met directement la puce à
l'oreille. Peut être trouvez vous ce code bien trop compliqué, ou
auriez vous en tête un manière de "l'améliorer" :-)

A bon entendeur salut.

AG.




#include <iostream>

using namespace std;

#define BUFFER_LENGTH 10

template<int N, class T>
class fifo_circular
{
private:
T * position;
size_t pos_offset;
T buffer[N];

public:
fifo_circular() { pos_offset = N-1; position = buffer + pos_offset;
for(int i=0;i<N;i++) buffer[i]=T(0);};

T step(T &input)
{
*position = input;

if(pos_offset>0) // ici il y aurait peut être moyen de glisser le
bug de la piste 1
pos_offset--;
else
pos_offset = N-1;

position = buffer + pos_offset;
return *position;
};

template<int M, class U> friend ostream & operator<<(ostream & o,
const fifo_circular<M,U> &f);
};

template<int N, class T>
fifo_circular<N,T> & Init(T & value)
{
fifo_circular<N,T> & f = fifo_circular<N,T>(); // hé hé hé

for(size_t i = 0; i < N; i++)
f.step(value);
return f;
}

template<int M, class U>
ostream & operator<<(ostream & o, const fifo_circular<M,U> &f)
{
for(size_t i = 0; i < M; i++)
o << f.buffer[i] << " ";
return o;
}

int main(int argc, char * argv[])
{
int a = 1;
fifo_circular<5,int> & f1 = Init<5,int>(a); // ici, c'est un peu trop
voyant. On se demande pourquoi f1 est déclaré en tant que
référence
a = 2;
fifo_circular<5,int> & f2 = Init<5,int>(a);

cout << "fifo f1: " << f1 << "";
cout << "fifo f2: " << f2 << "";

return 0;
}
Lire les 148 réponses

Vidéos High-Tech et Jeu Vidéo
Téléchargements
Vos réponses Page 1 / 30
Gagnez chaque mois un abonnement Premium avec GNT : Inscrivez-vous !
Trier par : date / pertinence
Marc Boyer
Le #20664081
Le 30-11-2009, AG
Je travaille dans une équipe de personnes pour lesquels le débugger
n'est pas l'outil qui tombe sous le sens lorsqu'il s'agit de trouver
les bugs des outils qu'ils ont développé.



Mais est-ce grave ? J'avoue ne quasiment jamais me servir
de débugger. Je travaille surtout en précondition/invariant
(assert) + tests unitaires, et éventuellement valgrind
quand je soupsonne une corruption mémoire.

Et une fois le bug identifié, à grand coups de cerr
+ assert.

D'autant que souvent, le bug n'apparait pas en mode débug ;-)

Marc Boyer
--
En prenant aux 10% des francais les plus riches 12% de leurs revenus,
on pourrait doubler les revenus des 10% les plus pauvres.
http://www.inegalites.fr/spip.php?a...amp;id_mot0
AG
Le #20664071
On Nov 30, 2:27 pm, Marc Boyer wrote:
  Mais est-ce grave ? J'avoue ne quasiment jamais me servir
de débugger. Je travaille surtout en précondition/invariant
(assert) + tests unitaires, et éventuellement valgrind
quand je soupsonne une corruption mémoire.

  Et une fois le bug identifié, à grand coups de cerr
+ assert.

  D'autant que souvent, le bug n'apparait pas en mode débug ;-)



Bonjour Marc,

Je pense que c'est grave effectivement. Tout ce que tu écris pour
débugger est inutile avec un débugger. C'est donc un gain de temps
immédiat.
Ensuite d'aucun diront que leur debugger (type gdb) est mal
pratique...peut être. Mais avec un débugger pratique, c'est un gain de
temps certain.

Cela dit, qu'on me le dise si les debugger ne sont pas intensivement
utilisés dans l'industrie, je serais content de me tromper. Dans mon
entourage, tout ceux à qui j'ai montré un debugger pratique l'ont
adopté.

Alexandre.

PS: tes élèves, tu ne leur apprends pas le débugger ?
Jean-Marc Bourguet
Le #20664281
AG
Cela dit, qu'on me le dise si les debugger ne sont pas intensivement
utilisés dans l'industrie, je serais content de me tromper.



Ca depend des gens, du probleme a debugger et du domaine. En general, je
trouve que j'abandonne de debuggeur pour autre chose trop lentement plutot
que trop vite. Et plus le probleme est complexe, moins ils sont utiles.
Un systeme de log et des assertions bien concues sont plus efficaces pour
les vrais problemes compliques.

A+

--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++...index.html
Site de usenet-fr: http://www.usenet-fr.news.eu.org
JKB
Le #20664481
Le 30-11-2009, ? propos de
Re: Bug indétectable via printf() / cout,
AG ?crivait dans fr.comp.lang.c++ :
On Nov 30, 2:27 pm, Marc Boyer wrote:
  Mais est-ce grave ? J'avoue ne quasiment jamais me servir
de débugger. Je travaille surtout en précondition/invariant
(assert) + tests unitaires, et éventuellement valgrind
quand je soupsonne une corruption mémoire.

  Et une fois le bug identifié, à grand coups de cerr
+ assert.

  D'autant que souvent, le bug n'apparait pas en mode débug ;-)



Bonjour Marc,

Je pense que c'est grave effectivement. Tout ce que tu écris pour
débugger est inutile avec un débugger. C'est donc un gain de temps
immédiat.
Ensuite d'aucun diront que leur debugger (type gdb) est mal
pratique...peut être. Mais avec un débugger pratique, c'est un gain de
temps certain.

Cela dit, qu'on me le dise si les debugger ne sont pas intensivement
utilisés dans l'industrie, je serais content de me tromper. Dans mon
entourage, tout ceux à qui j'ai montré un debugger pratique l'ont
adopté.

Alexandre.

PS: tes élèves, tu ne leur apprends pas le débugger ?



Bonjour,

Je ne programme pas en C++, tout au plus je corrige des choses parce
que j'ai une certaine phobie de la programmation objet. Néanmoins, en C
si j'utilise assez régulièrement gdb/ddd, c'est toujours après avoir
généré un core pour l'analyser. J'ai un tas de bugs sous la main qui
ne se produisent _jamais_ lorsque je lance le truc à débugguer sous
un quelconque debugger (code multithreadé, choses bizarres sur des
variables, mutexes, sémaphores...). En général, je préfère une macro()
style assert() qui me crache sur la sortie quelques informations et qui
envoie un SIGBUS pour générer un core, un peu la même technique que Marc.

Au pire, j'utilise valgrind lorsqu'il est disponible voire des
choses comme efence lorsque je suis sur une architecture non
supportée par valgrind.

Cordialement,

JKB

--
Le cerveau, c'est un véritable scandale écologique. Il représente 2% de notre
masse corporelle, mais disperse à lui seul 25% de l'énergie que nous
consommons tous les jours.
Marc Boyer
Le #20664471
Le 30-11-2009, AG
On Nov 30, 2:27 pm, Marc Boyer wrote:
  Mais est-ce grave ? J'avoue ne quasiment jamais me servir
de débugger. Je travaille surtout en précondition/invariant
(assert) + tests unitaires, et éventuellement valgrind
quand je soupsonne une corruption mémoire.

  Et une fois le bug identifié, à grand coups de cerr
+ assert.

  D'autant que souvent, le bug n'apparait pas en mode débug ;-)



Bonjour Marc,

Je pense que c'est grave effectivement. Tout ce que tu écris pour
débugger est inutile avec un débugger. C'est donc un gain de temps
immédiat.



Mais tout ce que tu fais avec ton débuger est non rejouable
(à moins que tu ne scriptes ton deboggeur, mais j'ai rencontré
peu de personnes qui le fassent).

En plus, les precond/invariants servent aussi de documentation,
et puis tu les écris quand tu écris la fonctions, donc tu sais ce
que ça va faire.

Et puis c'est aussi facile d'écrire
PRINT_VALUE(toto)
avec une macro du type
#define PRINT_VALUE(X) if (debug) { cerr<<#X "="<<(X)<<endl;}
que de faire click-gauche, 'suivre-variable'

Et puis les débogueurs que je connaissais ne montraient pas d'historique.
Souvent, la question c'est "pourquoi cette var vaut ça ?", et tu remontes
le temps. En affichant les variables en console, la console se souvient.

De plus, en ce qui concerne les fuites mémoires, valgrind est
bien plus efficace que de suivre pas à pas le débogueur.

Ensuite d'aucun diront que leur debugger (type gdb) est mal
pratique...peut être. Mais avec un débugger pratique, c'est un gain de
temps certain.



Possible. J'utilisais le deboggeur avant, sous Win* il y a plus
de 10 ans, puis SunStudio puis ddd/gdb/xemacs, puis plus rien...

Cela dit, qu'on me le dise si les debugger ne sont pas intensivement
utilisés dans l'industrie, je serais content de me tromper. Dans mon
entourage, tout ceux à qui j'ai montré un debugger pratique l'ont
adopté.



On verra ce que disent les autres contributeurs. Je ne parle que de
mon expérience.

PS: tes élèves, tu ne leur apprends pas le débugger ?



Je leur apprenais, oui, mais pas avec gdb/ddd, ils y perdaient trop
de temps: avancer pas à pas, saisir les entrées, faire un "run-until",
voir qu'on est allé trop loin, recommencer, re-saisir les entrées...

Non, tests unitaires / assert / printf, c'était la méthodologie.

On présentait gdb/ddd en illustration des cours sur l'allocation
dynamique, pour qu'ils "voient" leurs listes chainées.

Et quand en projet ils galéraient à rechercher un bug, et qu'ils
finissaient par m'appeller, au bord de la crise, parfois me montraient
leur problème avec gdb/ddd, mais toujours, j'allais à la pèche aux
infos à coup d'assert/printf, et, éventuellement valgrind.

Marc Boyer
--
En prenant aux 10% des francais les plus riches 12% de leurs revenus,
on pourrait doubler les revenus des 10% les plus pauvres.
http://www.inegalites.fr/spip.php?a...amp;id_mot0
Publicité
Suivre les réponses
Poster une réponse
Anonyme