• STATISTIQUES
  • Il y a eu un total de 4 membres et 4775 visiteurs sur le site dans les dernières 24h pour un total de 4 779 personnes!


    2 membres se sont inscrits dans les dernières 24h!


    Membres: 2 608
    Discussions: 3 580
    Messages: 32 820
    Tutoriels: 78
    Téléchargements: 38
    Sites dans l'annuaire: 58


  • ANNUAIRE
  • [EN] Astalavista
    Un site aux ressources incontournable depuis plusieurs années, Astalavista est réellement devenue un cl...
    Hacking
    [EN] social-engineer
    Site dédié au Social Engineering en général.
    Hacking
    [EN] osix
    Site de challenge qui utilise un système de level on chaque épreuve doit être réussie avant d'accédÃ...
    Challenges
    [EN] Reddit
    Subreddit dédié à la sécurité informatique.
    Hacking
    [FR] Cyber-Hacker
    CH - Cyber Hacker est un jeu par navigateur de simulation de hack, programmez et envoyez vos virus et piratez les aut...
    Hacking
    [EN] Sabre Films
    Site de challenge présenté sous la forme d'une quête. Vous êtes un détective et devrez résoudre d...
    Challenges
    [EN] phrack
    Lot's of stuff !
    Hacking

  • DONATION
  • Si vous avez trouvé ce site internet utile, nous vous invitons à nous faire un don du montant de votre choix via Paypal. Ce don servira à financer notre hébergement.

    MERCI!

    €



Note de ce sujet :
  • Moyenne : 0 (0 vote(s))
  • 1
  • 2
  • 3
  • 4
  • 5
[C TOTW 4] Equivalent de try / catch / throw en C
15-09-2014, 10h00
Message : #1
ark Hors ligne
Psyckomodo!
*****



Messages : 1,033
Sujets : 48
Points: 317
Inscription : Sep 2011
[C TOTW 4] Equivalent de try / catch / throw en C
Encore un lundi, encore un Tip Of The Week :D (Faut croire que j'avais zappe qu'on était lundi, mais bon comme je suis prévoyant, tout va bien !)

Alors, celui la vient de quand je tentais de trouver une solution alternative au challenge de ce thread : http://n-pn.fr/forum/showthread.php?tid=3737 et plus particulièrement sur la partie updated par Wapiflapi.

Mon idée était donc de partir sur comment faire l’équivalent des jmp asm, mais en utilisant uniquement des fonctions de la libc. Bref, j'ai donc fouille un peu dans les pages de man, et je suis tombe sur deux fonctions plutôt intéressantes.
Code C :

int setjmp(jmp_buf env);
void longjmp(jmp_buf env, int val);
 


La première, setjmp() permet de créer un contexte, c'est a dire sauvegarder tous les registres en cours. La seconde, longjmp() va prendre un contexte en paramètre et réinitialiser tous les registres avec ca. Il y a aussi moyen de sauvegarder les signaux, mais je vous laisse le plaisir de le découvrir en lisant le man ;)

Bref, donc j'ai fait deux 3 tests au debut avec ca, voici les codes, je vous laisse lire :

Exemple 1 :
Code C :

#include <stdio.h>
#include <setjmp.h>

int main(void) {

  int i = 0;
  jmp_buf here;

  setjmp(here);
  ++i;
  if (i < 8) {
    printf("Jumping, i = %d\n", i);
    longjmp(here, 0);
  }
  else
    printf("Yay! %d\n", i);

  return 0;
}
 


Ici en utilisant ces fonctions, on arrive a faire une boucle afin de donner a i la valeur 8.
Et l'exemple 2 montre cette utilisation dans une autre fonction :
Code C :

#include <stdio.h>
#include <setjmp.h>

void func(int *i, jmp_buf *here) {
  printf("Jumping: %d\n", *i);
  ++*i;
  longjmp(*here, 1);
}

int main(void) {

  int i = 0;
  jmp_buf here;

  setjmp(here);
  if (i < 8) {
    func(&i, &here);
  }
  else
    printf("Yay! %d\n", i);

  return 0;
}
 


Voila voila, plutot simple. Bon, a partir de la j'ai commencer a chercher une solution pour le challenge, mais je l'ai pas mener a bout (pour l'instant ! x))
Et donc j'en suis arrive a me dire qu'avec ce genre de truc, on doit pouvoir coder des trucs intéressants, en particulier si on y ajoute les fonctions signal() et kill().

Du coup, j'en suis venu a faire l’implémentation d'un équivalent a try, catch et throw en C++.

Voici le code, je vous explique après :
Code C :

#include <unistd.h>
#include <sys/types.h>
#include <string.h>
#include <stdio.h>
#include <setjmp.h>
#include <signal.h>

static jmp_buf recover;
static int exception;

void abort_handler(int __attribute__((unused)) sig) {
  longjmp(recover, 1);
}

/* try catch macro */
#define try(x, y) signal(SIGABRT, &abort_handler), (setjmp(recover) == 0) ? x : y

/* throw macro */
#define throw(x, y) ((x) != 0) ? exception = y, kill(getpid(), SIGABRT) : 0


/* Exception handling */
enum Exceptions {
  ERROR_NO_ARGS,
  ERROR_I_DONT_KNOW,
  NB_ERRORS
};

static char *err_msgs[NB_ERRORS] = {
  "not enough arguments given",
  "i don't know!"
};

#define GET_MSG(x) err_msgs[x]


/* Programm's code */

void function(char **argv) {

  /* If condition is true, we throw with the given message */
  throw(argv[1] == NULL,  ERROR_NO_ARGS);
  throw(!strcmp(argv[1], "except"), 42);

  while (*argv) {
    printf("%s\n", *argv++);
  }
}

int main(int __attribute__((unused)) argc, char *argv[]) {

  try(({
        function(argv);
      }),
    ({
      /* catch */
      if (exception == ERROR_NO_ARGS)
        printf("%s:%d: %s\n", __FILE__, __LINE__, GET_MSG(ERROR_NO_ARGS));
      else
        printf("%s:%d: Unknown exception catched\n", __FILE__, __LINE__);
    }));

  return 0;
}
 


Donc, premièrement, je définis deux variables globales, static (pas besoin dans ce cas de les réutiliser ailleurs, mais il pourrait être mieux de les mettre dans un .h et les appeler en externe si vous compter utiliser ce truc dans un vrai projet.). Ces deux variables vont permettre de store le contexte et le type d'erreur.

Je crée ensuite une fonction handler pour le signal abort, que la macro throw lancera lorsqu'il sera appelé. C'est elle qui va restaurer le contexe en appelant longjmp().

Voici ensuite la définition de mes deux macros,
Code C :

#define try(x, y) signal(SIGABRT, &abort_handler), (setjmp(recover) == 0) ? x : y
#define throw(x, y) ((x) != 0) ? exception = y, kill(getpid(), SIGABRT) : 0
 


Alors, tout simplement, ma macro try va set le handler pour le SIGABRT puis il set le contexte pour setjmp. Si setjmp renvoi 0, c'est qu'il a été appelé directement, si il renvoi 1, c'est qu'il a été call depuis un longjmp. Donc, dans le cas ou c'est 0, on est dans le try (on exec x) et sinon, on est dans le catch et on va exec y.

La macro throw va quand a elle prendre deux paramètres, le premier étant une expression, et l'autre, le type d'erreur qu'on va retourner si l'expression est fausse.

Ensuite, ben j'ai définis un enum d'exceptions, et leur types dans un tableau statique en dessous.

Et enfin, un peu de code pour le test ! :p
Donc, voici quelques tests :

Code BASH :

$> ./a.out
try_catch.c:61: not enough arguments given
$> ./a.out toto
./a.out
toto
$> ./a.out toto titi tata tutu
./a.out
toto
titi
tata
tutu
$> ./a.out except toot
try_catch.c:61: Unknown exception catched
$>
 


Voila, ca sera tout ! Vous pouvez retrouver le code sur mon github : https://github.com/Ark444/PoCz/tree/master/try_catch_c
C'est la dessus que je ferrai des updates! ;)

Bref, si vous avez des questions, des remarques, etc, n’hésitez pas !
+1 (6) -1 (0) Répondre


Sujets apparemment similaires…
Sujet Auteur Réponses Affichages Dernier message
  [C TOTW 6] Xor tricks ark 7 468 06-03-2016, 23h36
Dernier message: Commodor
  [C TOTW 2] Parcours de tableau ark 5 312 29-09-2014, 17h44
Dernier message: crown
  [C TOTW 5] bitfields ! ark 4 228 23-09-2014, 11h17
Dernier message: Aniem
  [C TOTW 3] #warning, #error ark 1 175 10-09-2014, 11h49
Dernier message: ark
  [C TOTW 1] Trick avec #include ark 10 461 01-09-2014, 18h23
Dernier message: Commodor

Atteindre :


Utilisateur(s) parcourant ce sujet : 1 visiteur(s)
N-PN
Accueil | Challenges | Tutoriels | Téléchargements | Forum | Retourner en haut