OVH Cloud OVH Cloud

gestionnaire d'erreurs rudimentaire

23 réponses
Avatar
nico
Salut,

Dans mes programmes, je suis toujours embété par la gestion des
désallocation d'objets lorsque survient une erreur quelconque...


par exemple, lors de la construction d'un objet important pour le
programme, il y a échec, je dois détruire tous les objets créés
auparavant afin de quitter proprement.. celà demande toujours des tests
ennuyeux, et de plus, la liste de ces objets à détruire n'est jamais la
même suivant l'endroit du programme où l'erreur survient.


J'ai donc dans l'idée de programmer un petit gestionnaire d'erreur, je
pensais à un objet qui contiendrait la liste des objets crées
(pointeurs) ainsi qu'un pointeur vers leur destructeur respecif et un
message char* approprié (tel que le nom etc...)

ainsi lors d'une erreur, il serait "facile" de détruire un à un les
objets alloués en affichant ça à l'utilisateur... :

objet 1... détruit
objet 2... détruit
objet 3... détruit
...
objet n... détruit

Cependant je pense à une chose délicate, afin d'etre le plus général
possible mon gestionnaire ne doit pas accumuler une liste d'objets sans
ordre... en effet il se peut que certains objets soient dépendant
d'autres, et que leur destructeur requiert qu'un des autres objets soit
encore en vie... il faudrait donc une sorte d'arborescence d'objets à
tuer...


Quelqu'un à -t-il déjà fait quelque chose de similaire ? avez-vous
une/des bonne(s) idée(s) à me proposer ?

merci
bon surf
a+


--
Nicolas Aunai
http:\\nicolas.auanai.free.fr

10 réponses

1 2 3
Avatar
Emmanuel Delahaye
nico wrote on 25/06/05 :
Emmanuel Delahaye wrote:

En principe, si on utilise sytématiquement les constructeurs pour créer et
les destructeurs pour détruire, y compris en cas d'erreur, il n'y a aucun
problème. Il est cependant important de correctement gérer l'état des
pointeurs. Si ils sont ou si ils deviennent invalides, les forcer à NULL.


okay mais regarde :

typeA objA = typeA_new()
if(!objA)
return EXIT_FAILURE;

typeB objB = typeB_new()
if(!objB)
{
typeA_free(objA);
return EXIT_FAILURE;
}

typeC objC = typeC_new();
if(!objC)
{
typeA_free(objA);
typeB_free(objB);
return EXIT_FAILURE;
}


Une variation sur cette réalié...

typeA objA = typeA_new();

if(objA != NULL)
{
typeB objB = typeB_new();

if(objB != NULL)
{
typeC objC = typeC_new();
if(objC != NULL)
{
}
else
{
typeA_free(objA), objA = NULL;
typeB_free(objB), objB = NULL;
}
}
else
{
typeA_free(objA), objA = NULL;
}
}

etc etc etc...
à chaque erreur eventuelle de construction, je dois détruire les objets
précédents, cette répétition de code m'agace, d'où l'idée d'avoir une liste
d'objets valides à détruire en cas d'erreur ...


Rien n'empêche de chainer les objets avec leur destructeur. C'est même
une idée intéressante...

/* obj.h */
typedef struct obj *obj;
typedef void obj_free_f (void *);

obj obj_create (void);
void obj_delete (obj self);

void obj_add (obj self, void *p_obj, obj_free_f * pf_free);
void obj_free_all (obj self);

/* A.h */
typedef struct typeA *typeA;

typeA typeA_new (void);
obj_free_f typeA_free;

/* B.h */
typedef struct typeB *typeB;

typeB typeB_new (void);
obj_free_f typeB_free;

/* C.h */
typedef struct typeC *typeC;

typeC typeC_new (void);
obj_free_f typeC_free;

/* main.h */
int main (void)
{
obj o = obj_create ();

if (o != NULL)
{
typeA objA = typeA_new ();

if (objA != NULL)
{
obj_add (o, objA, typeA_free);

typeB objB = typeB_new ();

if (objB != NULL)
{
obj_add (o, objB, typeB_free);

typeC objC = typeC_new ();

if (objC != NULL)
{
obj_add (o, objC, typeC_free);

/* le code operationnel ici. */

}
else
{
obj_free_all (o);
}
}
else
{
obj_free_all (o);
}
}

obj_delete (o), o = NULL;
}
return 0;
}

Je te laisse les details d'implémentation...

question bonus
les prototypes de mes destructeurs sont tous identiques :

void type_free(type *)

comment déclare -t-on un pointeur de fonction générique sur ce genre de
prototype ?


Vour ci-dessus...

--
Emmanuel
The C-FAQ: http://www.eskimo.com/~scs/C-faq/faq.html
The C-library: http://www.dinkumware.com/refxc.html

I once asked an expert COBOL programmer, how to
declare local variables in COBOL, the reply was:
"what is a local variable?"


Avatar
Richard Delorme

Dans le dernier cas, le problème ne se pose pas vraiment, si ce n'est
pour des raisons esthétiques: C'est le système d'exploitation qui va de
toute façon libérer tout ce qui a été alloué, en tout cas c'est comme
cela que ça fonctionne sur les OS que je connais.


Il me semble que les OS rudimentaires, comme MSDOS, ne libérait rien du
tout quand le programme quittait.

--
Richard

Avatar
Charlie Gordon
"Richard Delorme" wrote in message
news:42bd7ccb$0$308$

Dans le dernier cas, le problème ne se pose pas vraiment, si ce n'est
pour des raisons esthétiques: C'est le système d'exploitation qui va de
toute façon libérer tout ce qui a été alloué, en tout cas c'est comme
cela que ça fonctionne sur les OS que je connais.


Il me semble que les OS rudimentaires, comme MSDOS, ne libérait rien du
tout quand le programme quittait.


Bien sur que si !
D'ailleurs il est très facile pour un OS de taguer les blocs mémoire alloués par
un process pour tous les libérer à la fin.
En général, ces blocs sont ensuite utilisés par les process pour y implémenter
des arènes pour malloc/free. L'overhead n'est donc pas significatif. Dans les
OS modernes, c'est au niveau de la mémoire virtuelle que tout ceci est géré.

Chqrlie.


Avatar
Emmanuel Delahaye
Richard Delorme wrote on 25/06/05 :

Dans le dernier cas, le problème ne se pose pas vraiment, si ce n'est
pour des raisons esthétiques: C'est le système d'exploitation qui va de
toute façon libérer tout ce qui a été alloué, en tout cas c'est comme
cela que ça fonctionne sur les OS que je connais.


Il me semble que les OS rudimentaires, comme MSDOS, ne libérait rien du
tout quand le programme quittait.


J'ai des cas précis avec BOrland C 3.1. Si on quitte par exit() ou
return de main(), c'est OK. Si on quitte par abort() (assert(), par
exemple)), rien n'est libéré, et le crash de la machine se produit
souvent à la compilation suivante...

--
Emmanuel
The C-FAQ: http://www.eskimo.com/~scs/C-faq/faq.html
The C-library: http://www.dinkumware.com/refxc.html

"There are 10 types of people in the world today;
those that understand binary, and those that dont."


Avatar
Charlie Gordon
"Emmanuel Delahaye" wrote in message
news:
Richard Delorme wrote on 25/06/05 :

Dans le dernier cas, le problème ne se pose pas vraiment, si ce n'est
pour des raisons esthétiques: C'est le système d'exploitation qui va de
toute façon libérer tout ce qui a été alloué, en tout cas c'est comme
cela que ça fonctionne sur les OS que je connais.


Il me semble que les OS rudimentaires, comme MSDOS, ne libérait rien du
tout quand le programme quittait.


J'ai des cas précis avec BOrland C 3.1. Si on quitte par exit() ou
return de main(), c'est OK. Si on quitte par abort() (assert(), par
exemple)), rien n'est libéré, et le crash de la machine se produit
souvent à la compilation suivante...


Vraisemblablement à cause d'une corruption de l'arène système de MS/DOS ou des
données de l'OS en général.
Je rappelle que sous MS/DOS, il n'y a pas de séparation des process, pas de
protection de la mémoire : donc un process peut tout à fait corrompre le système
avec un crash pas toujours immédiat.

Il y a plusieurs facons de terminer un process sous MS/DOS : soit en restant
résident (int 21/31, int 27), et alors la memoire n'est bien entendu pas
libérée, soit normalement : int 20, int 21/00, int 21/4C, ret à l'adresse near
0, jmp à une adresse contenue dans le PSP... toutes font la meme chose : fermer
les descripteurs de fichiers ouverts, restaurer certains vecteurs
d'interruption, et desallouer toute la memoire associée au process, y compris le
PSP lui-meme.

Tout ceci est OT, et de plus totalement obsolète.

Chqrlie.



Avatar
Emmanuel Delahaye
Charlie Gordon wrote on 26/06/05 :
Tout ceci est OT, et de plus totalement obsolète.


Bof, je me sers de Borland C3.1 tous les jours pour écrire et tester
mon code...

--
Emmanuel
The C-FAQ: http://www.eskimo.com/~scs/C-faq/faq.html
The C-library: http://www.dinkumware.com/refxc.html

"Mal nommer les choses c'est ajouter du malheur au
monde." -- Albert Camus.

Avatar
espie
Il existe des implementations de C parfaitement conformes a la norme,
ou la memoire non liberee par free n'est pas rendue au systeme en
fin d'execution du programme.

Plus precisement, confere 5.1.2.1, Freestanding environment.

Et non, ce n'est pas une simple boutade. Omettre les free
correspondant aux allocations dynamiques limite la portabilite
d'un programme. Il existe en pratique quantite d'implementations
freestanding, avec des extensions de la bibliotheque qui sont tres
proches d'un environnement hosted, a ces quelques details de gestion
des ressources pres...
Avatar
Emmanuel Delahaye
Marc Espie wrote on 26/06/05 :
Il existe des implementations de C parfaitement conformes a la norme,
ou la memoire non liberee par free n'est pas rendue au systeme en
fin d'execution du programme.

Plus precisement, confere 5.1.2.1, Freestanding environment.

Et non, ce n'est pas une simple boutade. Omettre les free
correspondant aux allocations dynamiques limite la portabilite
d'un programme. Il existe en pratique quantite d'implementations
freestanding, avec des extensions de la bibliotheque qui sont tres
proches d'un environnement hosted, a ces quelques details de gestion
des ressources pres...


Avec Linux Embarqué, la frontière entre hosted et freestanding est
ténue...

--
Emmanuel
The C-FAQ: http://www.eskimo.com/~scs/C-faq/faq.html
The C-library: http://www.dinkumware.com/refxc.html

"There are 10 types of people in the world today;
those that understand binary, and those that dont."

Avatar
Gabriel Dos Reis
"Emmanuel Delahaye" writes:

| Marc Espie wrote on 26/06/05 :
| > Il existe des implementations de C parfaitement conformes a la norme,
| > ou la memoire non liberee par free n'est pas rendue au systeme en
| > fin d'execution du programme.
| >
| > Plus precisement, confere 5.1.2.1, Freestanding environment.
| >
| > Et non, ce n'est pas une simple boutade. Omettre les free
| > correspondant aux allocations dynamiques limite la portabilite
| > d'un programme. Il existe en pratique quantite d'implementations
| > freestanding, avec des extensions de la bibliotheque qui sont tres
| > proches d'un environnement hosted, a ces quelques details de gestion
| > des ressources pres...
|
| Avec Linux Embarqué, la frontière entre hosted et freestanding est
| ténue...

mais le monde des systèmes embarqués ne tourne pas autour de embedded
linux.

-- Gaby
Avatar
espie
In article ,
Gabriel Dos Reis wrote:
"Emmanuel Delahaye" writes:
| Avec Linux Embarqué, la frontière entre hosted et freestanding est
| ténue...

mais le monde des systèmes embarqués ne tourne pas autour de embedded
linux.


Je pense qu'Emmanuel desirais juste citer un exemple repandu parmi
d'autres...

1 2 3