diff options
author | Cyrille Bagard <nocbos@gmail.com> | 2023-07-07 06:32:43 (GMT) |
---|---|---|
committer | Cyrille Bagard <nocbos@gmail.com> | 2023-07-07 06:32:43 (GMT) |
commit | 4c10dfa2a95cea6fc704d68066d0c284cfd79342 (patch) | |
tree | 5827bbc411459800747e21929daecdf99fde7dfd /src/analysis/scan/exprs | |
parent | 3f996be1e5858b54740bf92515795982a16b169a (diff) |
Rewrite core parts of the ROST API.
Diffstat (limited to 'src/analysis/scan/exprs')
-rw-r--r-- | src/analysis/scan/exprs/Makefile.am | 6 | ||||
-rw-r--r-- | src/analysis/scan/exprs/access-int.h | 69 | ||||
-rw-r--r-- | src/analysis/scan/exprs/access.c | 471 | ||||
-rw-r--r-- | src/analysis/scan/exprs/access.h | 63 | ||||
-rw-r--r-- | src/analysis/scan/exprs/arithmop-int.h | 4 | ||||
-rw-r--r-- | src/analysis/scan/exprs/arithmop.c | 210 | ||||
-rw-r--r-- | src/analysis/scan/exprs/boolop.c | 161 | ||||
-rw-r--r-- | src/analysis/scan/exprs/call-int.h | 13 | ||||
-rw-r--r-- | src/analysis/scan/exprs/call.c | 223 | ||||
-rw-r--r-- | src/analysis/scan/exprs/call.h | 7 | ||||
-rw-r--r-- | src/analysis/scan/exprs/literal-int.h | 2 | ||||
-rw-r--r-- | src/analysis/scan/exprs/literal.c | 113 | ||||
-rw-r--r-- | src/analysis/scan/exprs/literal.h | 3 | ||||
-rw-r--r-- | src/analysis/scan/exprs/relop-int.h | 4 | ||||
-rw-r--r-- | src/analysis/scan/exprs/relop.c | 156 | ||||
-rw-r--r-- | src/analysis/scan/exprs/strop-int.h (renamed from src/analysis/scan/exprs/str-int.h) | 15 | ||||
-rw-r--r-- | src/analysis/scan/exprs/strop.c (renamed from src/analysis/scan/exprs/str.c) | 258 | ||||
-rw-r--r-- | src/analysis/scan/exprs/strop.h (renamed from src/analysis/scan/exprs/str.h) | 8 |
18 files changed, 1208 insertions, 578 deletions
diff --git a/src/analysis/scan/exprs/Makefile.am b/src/analysis/scan/exprs/Makefile.am index f164864..efe25fc 100644 --- a/src/analysis/scan/exprs/Makefile.am +++ b/src/analysis/scan/exprs/Makefile.am @@ -3,6 +3,8 @@ noinst_LTLIBRARIES = libanalysisscanexprs.la libanalysisscanexprs_la_SOURCES = \ + access-int.h \ + access.h access.c \ arithmop-int.h \ arithmop.h arithmop.c \ boolop-int.h \ @@ -13,8 +15,8 @@ libanalysisscanexprs_la_SOURCES = \ literal.h literal.c \ relop-int.h \ relop.h relop.c \ - str-int.h \ - str.h str.c + strop-int.h \ + strop.h strop.c libanalysisscanexprs_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) diff --git a/src/analysis/scan/exprs/access-int.h b/src/analysis/scan/exprs/access-int.h new file mode 100644 index 0000000..2212b48 --- /dev/null +++ b/src/analysis/scan/exprs/access-int.h @@ -0,0 +1,69 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * access-int.h - prototypes internes pour l'accès à un élément d'expression sous-jacent + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_EXPRS_ACCESS_INT_H +#define _ANALYSIS_SCAN_EXPRS_ACCESS_INT_H + + +#include "access.h" + + +#include "../expr-int.h" + + + +/* Accès à un élément d'expression sous-jacent (instance) */ +struct _GNamedAccess +{ + GScanExpression parent; /* A laisser en premier */ + + union + { + GRegisteredItem *base; /* Base de recherche */ + GRegisteredItem *resolved; /* Elément ciblé au final */ + GObject *any; /* Accès indistinct */ + }; + + char *target; /* Cible dans l'espace */ + + struct _GNamedAccess *next; /* Evnetuel prochain élément */ + +}; + +/* Accès à un élément d'expression sous-jacent (classe) */ +struct _GNamedAccessClass +{ + GScanExpressionClass parent; /* A laisser en premier */ + +}; + + +/* Met en place une expression d'accès. */ +bool g_named_access_create(GNamedAccess *, const sized_string_t *); + +/* Réduit une expression à une forme plus simple. */ +bool _g_named_access_reduce(GNamedAccess *, GScanContext *, GScanScope *, GScanExpression **); + + + +#endif /* _ANALYSIS_SCAN_EXPRS_ACCESS_INT_H */ diff --git a/src/analysis/scan/exprs/access.c b/src/analysis/scan/exprs/access.c new file mode 100644 index 0000000..ad66f60 --- /dev/null +++ b/src/analysis/scan/exprs/access.c @@ -0,0 +1,471 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * access.c - accès à un élément d'expression sous-jacent + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "access.h" + + +#include <assert.h> +#include <malloc.h> +#include <string.h> + + +#include "access-int.h" +#include "../../../core/global.h" + + + +/* --------------------- INTRODUCTION D'UNE NOUVELLE EXPRESSION --------------------- */ + + +/* Initialise la classe des appels de fonction avec arguments. */ +static void g_named_access_class_init(GNamedAccessClass *); + +/* Initialise une instance d'appel de fonction avec arguments. */ +static void g_named_access_init(GNamedAccess *); + +/* Supprime toutes les références externes. */ +static void g_named_access_dispose(GNamedAccess *); + +/* Procède à la libération totale de la mémoire. */ +static void g_named_access_finalize(GNamedAccess *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Reproduit une expression en place dans une nouvelle instance. */ +static void g_named_access_copy(GNamedAccess *, const GNamedAccess *); + +/* Réduit une expression à une forme plus simple. */ +static bool g_named_access_reduce(GNamedAccess *, GScanContext *, GScanScope *, GScanExpression **); + + + +/* ---------------------------------------------------------------------------------- */ +/* INTRODUCTION D'UNE NOUVELLE EXPRESSION */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour un appel de fonction enregistrée. */ +G_DEFINE_TYPE(GNamedAccess, g_named_access, G_TYPE_SCAN_EXPRESSION); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des appels de fonction avec arguments. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_named_access_class_init(GNamedAccessClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GScanExpressionClass *expr; /* Version de classe parente */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_named_access_dispose; + object->finalize = (GObjectFinalizeFunc)g_named_access_finalize; + + expr = G_SCAN_EXPRESSION_CLASS(klass); + + expr->cmp_rich = (compare_expr_rich_fc)NULL; + expr->copy = (copy_expr_fc)g_named_access_copy; + expr->reduce = (reduce_expr_fc)g_named_access_reduce; + +} + + +/****************************************************************************** +* * +* Paramètres : access = instance à initialiser. * +* * +* Description : Initialise une instance d'appel de fonction avec arguments. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_named_access_init(GNamedAccess *access) +{ + access->any = NULL; + access->target = NULL; + + access->next = NULL; + +} + + +/****************************************************************************** +* * +* Paramètres : access = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_named_access_dispose(GNamedAccess *access) +{ + g_clear_object(&access->any); + + g_clear_object(&access->next); + + G_OBJECT_CLASS(g_named_access_parent_class)->dispose(G_OBJECT(access)); + +} + + +/****************************************************************************** +* * +* Paramètres : access = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_named_access_finalize(GNamedAccess *access) +{ + if (access->target != NULL) + free(access->target); + + G_OBJECT_CLASS(g_named_access_parent_class)->finalize(G_OBJECT(access)); + +} + + +/****************************************************************************** +* * +* Paramètres : target = désignation de l'objet d'appel à identifier. * +* * +* Description : Organise un accès à un élément d'expression sous-jacent. * +* * +* Retour : Fonction mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanExpression *g_named_access_new(const sized_string_t *target) +{ + GScanExpression *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_NAMED_ACCESS, NULL); + + if (!g_named_access_create(G_NAMED_ACCESS(result), target)) + g_clear_object(&result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : access = instance à initialiser pleinement. * +* target = désignation de l'objet d'appel à identifier. * +* * +* Description : Met en place une expression d'accès. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_named_access_create(GNamedAccess *access, const sized_string_t *target) +{ + bool result; /* Bilan à retourner */ + + result = g_scan_expression_create(G_SCAN_EXPRESSION(access), EVT_PENDING); + if (!result) goto exit; + + access->target = strndup(target->data, target->len); + + exit: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : access = expression d'appel à actualiser. * +* base = zone de recherche pour la résolution à venir. * +* * +* Description : Définit une base de recherche pour la cible d'accès. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_named_access_set_base(GNamedAccess *access, GRegisteredItem *base) +{ + g_clear_object(&access->base); + + access->base = base; + g_object_ref(G_OBJECT(base)); + +} + + +/****************************************************************************** +* * +* Paramètres : access = expression d'appel à compléter. * +* next = expression d'appel suivante dans la chaîne. * +* * +* Description : Complète la chaine d'accès à des expressions. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_named_access_attach_next(GNamedAccess *access, GNamedAccess *next) +{ + if (access->next != NULL) + g_named_access_attach_next(access->next, next); + + else + { + access->next = next; + g_object_ref(G_OBJECT(next)); + } + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : dest = emplacement d'enregistrement à constituer. [OUT] * +* src = expression source à copier. * +* * +* Description : Reproduit une expression en place dans une nouvelle instance.* +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_named_access_copy(GNamedAccess *dest, const GNamedAccess *src) +{ + GScanExpressionClass *class; /* Classe parente à solliciter */ + + class = G_SCAN_EXPRESSION_CLASS(g_named_access_parent_class); + + class->copy(G_SCAN_EXPRESSION(dest), G_SCAN_EXPRESSION(src)); + + if (src->any != NULL) + { + dest->any = src->any; + g_object_ref(src->any); + } + + if (src->target != NULL) + dest->target = strdup(src->target); + + if (src->next != NULL) + dest->next = G_NAMED_ACCESS(g_scan_expression_duplicate(G_SCAN_EXPRESSION(src->next))); + +} + + +/****************************************************************************** +* * +* Paramètres : expr = expression à consulter. * +* ctx = contexte de suivi de l'analyse courante. * +* scope = portée courante des variables locales. * +* out = zone d'enregistrement de la réduction opérée. [OUT] * +* * +* Description : Réduit une expression à une forme plus simple. * +* * +* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool _g_named_access_reduce(GNamedAccess *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out) +{ + bool result; /* Bilan à retourner */ + GRegisteredItem *base; /* Base de recherche courante */ + GRegisteredItem *resolved; /* Cible concrète obtenue */ + GNamedAccess *new; /* Copie mise en place */ + + result = true; + + if (expr->target != NULL) + { + if (expr->base != NULL) + { + base = expr->base; + g_object_ref(G_OBJECT(base)); + } + else + base = G_REGISTERED_ITEM(get_rost_root_namespace()); + + result = g_registered_item_resolve(base, expr->target, ctx, scope, &resolved); + + g_object_unref(G_OBJECT(base)); + + if (result && resolved != NULL) + { + new = G_NAMED_ACCESS(g_scan_expression_duplicate(G_SCAN_EXPRESSION(expr))); + + g_clear_object(&new->base); + + free(new->target); + new->target = NULL; + + new->resolved = resolved; + + *out = G_SCAN_EXPRESSION(new); + + } + + } + + /** + * Si plus aucune indication n'est diponible pour avancer dans les réductions, + * c'est que l'opération est déjà conclue. + */ + else + { + assert(expr->resolved != NULL); + + *out = G_SCAN_EXPRESSION(expr); + g_object_ref(G_OBJECT(*out)); + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : expr = expression à consulter. * +* ctx = contexte de suivi de l'analyse courante. * +* scope = portée courante des variables locales. * +* out = zone d'enregistrement de la réduction opérée. [OUT] * +* * +* Description : Réduit une expression à une forme plus simple. * +* * +* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_named_access_reduce(GNamedAccess *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out) +{ + bool result; /* Bilan à retourner */ + GNamedAccess *new; /* Eventuel étage suivant */ + GScanExpression *final; /* Expression d'évaluation */ + GScanExpression *new_next; /* Nouvelle version du suivant */ + + result = _g_named_access_reduce(expr, ctx, scope, out); + + if (result && *out != NULL) + { + assert(G_IS_NAMED_ACCESS(*out)); + + new = G_NAMED_ACCESS(*out); + *out = NULL; + + assert(new->target == NULL); + assert(G_IS_NAMED_ACCESS(new)); + assert(G_IS_REGISTERED_ITEM(new->resolved)); + + /** + * Si l'élément résolu se trouve en fin de chaîne, alors cet élément + * est sollicité pour obtenir une expression d'évaluation classique. + * Le produit de cette réduction finale bénéficie d'une promotion et + * représente à lui seul la réduction produite pour la chaîne. + */ + if (new->next == NULL) + { + result = g_registered_item_reduce(new->resolved, ctx, scope, &final); + + if (result && final != NULL) + { + g_clear_object(out); + *out = final; + } + + } + + /** + * Sinon, l'élément résolu constitue une base pour l'étage suivant de + * la chaîne de résolution. + */ + else + { + new_next = g_scan_expression_duplicate(G_SCAN_EXPRESSION(new->next)); + assert(G_IS_NAMED_ACCESS(new_next)); + + g_named_access_set_base(G_NAMED_ACCESS(new_next), new->resolved); + + g_clear_object(out); + + result = g_scan_expression_reduce(new_next, ctx, scope, out); + + if (result && *out == NULL) + *out = new_next; + + } + + g_object_unref(G_OBJECT(new)); + + } + + return result; + +} diff --git a/src/analysis/scan/exprs/access.h b/src/analysis/scan/exprs/access.h new file mode 100644 index 0000000..a04adc7 --- /dev/null +++ b/src/analysis/scan/exprs/access.h @@ -0,0 +1,63 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * access.h - prototypes pour l'accès à un élément d'expression sous-jacent + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_EXPRS_ACCESS_H +#define _ANALYSIS_SCAN_EXPRS_ACCESS_H + + +#include "../expr.h" +#include "../item.h" +#include "../../../common/szstr.h" + + + +#define G_TYPE_NAMED_ACCESS g_named_access_get_type() +#define G_NAMED_ACCESS(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_NAMED_ACCESS, GNamedAccess)) +#define G_IS_NAMED_ACCESS(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_NAMED_ACCESS)) +#define G_NAMED_ACCESS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_NAMED_ACCESS, GNamedAccessClass)) +#define G_IS_NAMED_ACCESS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_NAMED_ACCESS)) +#define G_NAMED_ACCESS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_NAMED_ACCESS, GNamedAccessClass)) + + +/* Accès à un élément d'expression sous-jacent (instance) */ +typedef struct _GNamedAccess GNamedAccess; + +/* Accès à un élément d'expression sous-jacent (classe) */ +typedef struct _GNamedAccessClass GNamedAccessClass; + + +/* Indique le type défini pour un appel de fonction enregistrée. */ +GType g_named_access_get_type(void); + +/* Organise un accès à un élément d'expression sous-jacent. */ +GScanExpression *g_named_access_new(const sized_string_t *); + +/* Définit une base de recherche pour la cible d'accès. */ +void g_named_access_set_base(GNamedAccess *, GRegisteredItem *); + +/* Complète la chaine d'accès à des expressions. */ +void g_named_access_attach_next(GNamedAccess *, GNamedAccess *); + + + +#endif /* _ANALYSIS_SCAN_EXPRS_ACCESS_H */ diff --git a/src/analysis/scan/exprs/arithmop-int.h b/src/analysis/scan/exprs/arithmop-int.h index 75f1dbb..031de84 100644 --- a/src/analysis/scan/exprs/arithmop-int.h +++ b/src/analysis/scan/exprs/arithmop-int.h @@ -39,8 +39,8 @@ struct _GArithmOperation ArithmeticExpressionOperator operator; /* Type d'opération menée */ - GScanExpression *first; /* Expression impactée #1 */ - GScanExpression *second; /* Expression impactée #2 */ + GScanExpression *left; /* Expression impactée #1 */ + GScanExpression *right; /* Expression impactée #2 */ }; diff --git a/src/analysis/scan/exprs/arithmop.c b/src/analysis/scan/exprs/arithmop.c index f57e260..5f9e3f1 100644 --- a/src/analysis/scan/exprs/arithmop.c +++ b/src/analysis/scan/exprs/arithmop.c @@ -52,11 +52,11 @@ static void g_arithmetic_operation_finalize(GArithmOperation *); /* Réalise une comparaison entre objets selon un critère précis. */ static bool g_arithmetic_operation_compare_rich(const GArithmOperation *, const GArithmOperation *, RichCmpOperation, bool *); -/* Initialise une instance d'opération de relation. */ -static GScanExpression *g_arithmetic_operation_duplicate(const GArithmOperation *); +/* Reproduit une expression en place dans une nouvelle instance. */ +static void g_arithmetic_operation_copy(GArithmOperation *, const GArithmOperation *); /* Réduit une expression à une forme plus simple. */ -GScanExpression *g_arithmetic_operation_reduce(GArithmOperation *, GScanContext *, bool); +static bool g_arithmetic_operation_reduce(GArithmOperation *, GScanContext *, GScanScope *, GScanExpression **); @@ -94,7 +94,7 @@ static void g_arithmetic_operation_class_init(GArithmOperationClass *klass) expr = G_SCAN_EXPRESSION_CLASS(klass); expr->cmp_rich = (compare_expr_rich_fc)g_arithmetic_operation_compare_rich; - expr->dup = (dup_expr_fc)g_arithmetic_operation_duplicate; + expr->copy = (copy_expr_fc)g_arithmetic_operation_copy; expr->reduce = (reduce_expr_fc)g_arithmetic_operation_reduce; } @@ -114,8 +114,8 @@ static void g_arithmetic_operation_class_init(GArithmOperationClass *klass) static void g_arithmetic_operation_init(GArithmOperation *op) { - op->first = NULL; - op->second = NULL; + op->left = NULL; + op->right = NULL; } @@ -134,8 +134,8 @@ static void g_arithmetic_operation_init(GArithmOperation *op) static void g_arithmetic_operation_dispose(GArithmOperation *op) { - g_clear_object(&op->first); - g_clear_object(&op->second); + g_clear_object(&op->left); + g_clear_object(&op->right); G_OBJECT_CLASS(g_arithmetic_operation_parent_class)->dispose(G_OBJECT(op)); @@ -164,8 +164,8 @@ static void g_arithmetic_operation_finalize(GArithmOperation *op) /****************************************************************************** * * * Paramètres : operator = type d'opération arithmétique à représenter. * -* first = premier opérande concerné. * -* second = éventuel second opérande impliqué ou NULL. * +* left = premier opérande concerné. * +* right = éventuel second opérande impliqué ou NULL. * * * * Description : Organise une opération arithmétique entre expressions. * * * @@ -175,13 +175,13 @@ static void g_arithmetic_operation_finalize(GArithmOperation *op) * * ******************************************************************************/ -GScanExpression *g_arithmetic_operation_new(ArithmeticExpressionOperator operator, GScanExpression *first, GScanExpression *second) +GScanExpression *g_arithmetic_operation_new(ArithmeticExpressionOperator operator, GScanExpression *left, GScanExpression *right) { GScanExpression *result; /* Structure à retourner */ result = g_object_new(G_TYPE_ARITHMETIC_OPERATION, NULL); - if (!g_arithmetic_operation_create(G_ARITHMETIC_OPERATION(result), operator, first, second)) + if (!g_arithmetic_operation_create(G_ARITHMETIC_OPERATION(result), operator, left, right)) g_clear_object(&result); return result; @@ -193,8 +193,8 @@ GScanExpression *g_arithmetic_operation_new(ArithmeticExpressionOperator operato * * * Paramètres : op = instance à initialiser pleinement. * * operator = type d'opération booléenne à représenter. * -* first = premier opérande concerné. * -* second = éventuel second opérande impliqué ou NULL. * +* left = premier opérande concerné. * +* right = éventuel second opérande impliqué ou NULL. * * * * Description : Met en place une opération arithmétique entre expressions. * * * @@ -204,19 +204,19 @@ GScanExpression *g_arithmetic_operation_new(ArithmeticExpressionOperator operato * * ******************************************************************************/ -bool g_arithmetic_operation_create(GArithmOperation *op, ArithmeticExpressionOperator operator, GScanExpression *first, GScanExpression *second) +bool g_arithmetic_operation_create(GArithmOperation *op, ArithmeticExpressionOperator operator, GScanExpression *left, GScanExpression *right) { bool result; /* Bilan à retourner */ ExprValueType vtype; /* Type de valeur portée */ result = false; - vtype = g_scan_expression_get_value_type(first); + vtype = g_scan_expression_get_value_type(left); if (vtype != EVT_INTEGER && vtype != EVT_PENDING) goto exit; - vtype = g_scan_expression_get_value_type(second); + vtype = g_scan_expression_get_value_type(right); if (vtype != EVT_INTEGER && vtype != EVT_PENDING) goto exit; @@ -226,11 +226,11 @@ bool g_arithmetic_operation_create(GArithmOperation *op, ArithmeticExpressionOpe op->operator = operator; - op->first = first; - g_object_ref(G_OBJECT(op->first)); + op->left = left; + g_object_ref(G_OBJECT(op->left)); - op->second = second; - g_object_ref(G_OBJECT(op->second)); + op->right = right; + g_object_ref(G_OBJECT(op->right)); result = true; @@ -265,9 +265,9 @@ bool g_arithmetic_operation_create(GArithmOperation *op, ArithmeticExpressionOpe static bool g_arithmetic_operation_compare_rich(const GArithmOperation *item, const GArithmOperation *other, RichCmpOperation op, bool *status) { bool result; /* Etat à retourner */ - bool equal; /* Bilan intermédiaire */ - result = true; // TODO : cmp parent()->type + result = g_type_is_a(G_TYPE_FROM_INSTANCE(other), G_TYPE_ARITHMETIC_OPERATION); + if (!result) goto done; if (item->operator != other->operator) { @@ -275,18 +275,16 @@ static bool g_arithmetic_operation_compare_rich(const GArithmOperation *item, co goto done; } - equal = g_comparable_item_compare_rich(G_COMPARABLE_ITEM(item), G_COMPARABLE_ITEM(other), RCO_EQ, status); + result = g_comparable_item_compare_rich(G_COMPARABLE_ITEM(item), G_COMPARABLE_ITEM(other), RCO_EQ, status); + if (!result || STATUS_NOT_EQUAL(*status, op)) goto done; - if (!equal) - { - result = g_comparable_item_compare_rich(G_COMPARABLE_ITEM(item->first), - G_COMPARABLE_ITEM(other->first), - op, status); - goto done; - } + result = g_comparable_item_compare_rich(G_COMPARABLE_ITEM(item->left), + G_COMPARABLE_ITEM(other->left), + op, status); + if (!result || STATUS_NOT_EQUAL(*status, op)) goto done; - result = g_comparable_item_compare_rich(G_COMPARABLE_ITEM(item->second), - G_COMPARABLE_ITEM(other->second), + result = g_comparable_item_compare_rich(G_COMPARABLE_ITEM(item->right), + G_COMPARABLE_ITEM(other->right), op, status); done: @@ -298,23 +296,29 @@ static bool g_arithmetic_operation_compare_rich(const GArithmOperation *item, co /****************************************************************************** * * -* Paramètres : expr = expression à copier. * +* Paramètres : dest = emplacement d'enregistrement à constituer. [OUT] * +* src = expression source à copier. * * * * Description : Reproduit une expression en place dans une nouvelle instance.* * * -* Retour : Nouvelle instance d'expression. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -static GScanExpression *g_arithmetic_operation_duplicate(const GArithmOperation *expr) +static void g_arithmetic_operation_copy(GArithmOperation *dest, const GArithmOperation *src) { - GScanExpression *result; /* Instance copiée à retourner */ + GScanExpressionClass *class; /* Classe parente à solliciter */ - result = g_arithmetic_operation_new(expr->operator, expr->first, expr->second); + class = G_SCAN_EXPRESSION_CLASS(g_arithmetic_operation_parent_class); - return result; + class->copy(G_SCAN_EXPRESSION(dest), G_SCAN_EXPRESSION(src)); + + dest->operator = src->operator; + + dest->left = g_scan_expression_duplicate(src->left); + dest->right = g_scan_expression_duplicate(src->right); } @@ -323,92 +327,110 @@ static GScanExpression *g_arithmetic_operation_duplicate(const GArithmOperation * * * Paramètres : expr = expression à consulter. * * ctx = contexte de suivi de l'analyse courante. * -* final = impose une conversion finale de dernier tour. * +* scope = portée courante des variables locales. * +* out = zone d'enregistrement de la réduction opérée. [OUT] * * * * Description : Réduit une expression à une forme plus simple. * * * -* Retour : Réduction correspondante, expression déjà réduite, ou NULL. * +* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. * * * * Remarques : - * * * ******************************************************************************/ -GScanExpression *g_arithmetic_operation_reduce(GArithmOperation *expr, GScanContext *ctx, bool final) +static bool g_arithmetic_operation_reduce(GArithmOperation *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out) { - GScanExpression *result; /* Instance à renvoyer */ - GScanExpression *new; /* Nouvelle expression obtenue */ + bool result; /* Bilan à retourner */ + GScanExpression *new_left; /* Expression réduite (gauche) */ + GScanExpression *new_right; /* Expression réduite (droite) */ + GLiteralExpression *op_left; /* Opérande gauche final */ + GLiteralExpression *op_right; /* Opérande droite final */ unsigned long long val_1; /* Première valeur à traiter */ - unsigned long long val_2; /* Second valeur à traiter */ - bool valid; /* Validité de ce bilan obtenu */ + unsigned long long val_2; /* Seconde valeur à traiter */ unsigned long long reduced; /* Valeur réduite finale */ - result = NULL; - /* Réduction des éléments considérés */ - new = g_scan_expression_reduce(expr->first, ctx, final); - - if (new != NULL) - { - g_object_unref(G_OBJECT(expr->first)); - expr->first = new; - } + new_left = NULL; + new_right = NULL; - if (expr->second != NULL) - { - new = g_scan_expression_reduce(expr->second, ctx, final); + result = g_scan_expression_reduce(expr->left, ctx, scope, &new_left); + if (!result) goto exit; - if (new != NULL) - { - g_object_unref(G_OBJECT(expr->second)); - expr->second = new; - } - - } + result = g_scan_expression_reduce(expr->right, ctx, scope, &new_right); + if (!result) goto exit; /* Construction d'une réduction locale ? */ - if (G_IS_LITERAL_EXPRESSION(expr->first) && G_IS_LITERAL_EXPRESSION(expr->second)) + if (G_IS_LITERAL_EXPRESSION(new_left) && G_IS_LITERAL_EXPRESSION(new_right)) { - valid = g_literal_expression_get_integer_value(G_LITERAL_EXPRESSION(expr->first), &val_1); + op_left = G_LITERAL_EXPRESSION(new_left); + op_right = G_LITERAL_EXPRESSION(new_right); - if (valid) - valid = g_literal_expression_get_integer_value(G_LITERAL_EXPRESSION(expr->second), &val_2); + result = g_literal_expression_get_integer_value(op_left, &val_1); + if (!result) goto exit; - if (valid) - switch (expr->operator) - { - case AEO_PLUS: - reduced = val_1 + val_2; - break; + result = g_literal_expression_get_integer_value(op_right, &val_2); + if (!result) goto exit; - case AEO_MINUS: - reduced = val_1 - val_2; - break; + switch (expr->operator) + { + case AEO_PLUS: + reduced = val_1 + val_2; + break; + + case AEO_MINUS: + reduced = val_1 - val_2; + break; + + case AEO_MUL: + reduced = val_1 * val_2; + break; + + case AEO_DIV: + result = (val_2 != 0); + if (result) + reduced = val_1 / val_2; + break; + + case AEO_MOD: + result = (val_2 != 0); + if (result) + reduced = val_1 % val_2; + break; - case AEO_MUL: - reduced = val_1 * val_2; - break; + } - case AEO_DIV: - valid = (val_2 != 0); - if (valid) - reduced = val_1 / val_2; - break; + if (result) + *out = g_literal_expression_new(EVT_INTEGER, &reduced); - case AEO_MOD: - valid = (val_2 != 0); - if (valid) - reduced = val_1 % val_2; - break; + } - } + /* Mise à jour de la progression ? */ - if (valid) - result = g_literal_expression_new(EVT_INTEGER, &reduced); + else if ((new_left != NULL && new_left != expr->left) || (new_right != NULL && new_right != expr->right)) + { + if (new_left == NULL) + { + new_left = expr->left; + g_object_ref(G_OBJECT(new_left)); + } + + if (new_right == NULL) + { + new_right = expr->right; + g_object_ref(G_OBJECT(new_right)); + } + + *out = g_arithmetic_operation_new(expr->operator, new_left, new_right); } + exit: + + g_clear_object(&new_left); + g_clear_object(&new_right); + return result; } diff --git a/src/analysis/scan/exprs/boolop.c b/src/analysis/scan/exprs/boolop.c index 2902fdd..f6a80dd 100644 --- a/src/analysis/scan/exprs/boolop.c +++ b/src/analysis/scan/exprs/boolop.c @@ -56,10 +56,10 @@ static void g_boolean_operation_finalize(GBoolOperation *); static bool g_boolean_operation_compare_rich(const GBoolOperation *, const GBoolOperation *, RichCmpOperation, bool *); /* Reproduit une expression en place dans une nouvelle instance. */ -static GScanExpression *g_boolean_operation_duplicate(const GBoolOperation *); +static void g_boolean_operation_copy(GBoolOperation *, const GBoolOperation *); /* Réduit une expression à une forme plus simple. */ -GScanExpression *g_boolean_operation_reduce(GBoolOperation *, GScanContext *, bool); +static bool g_boolean_operation_reduce(GBoolOperation *, GScanContext *, GScanScope *, GScanExpression **); @@ -97,7 +97,7 @@ static void g_boolean_operation_class_init(GBoolOperationClass *klass) expr = G_SCAN_EXPRESSION_CLASS(klass); expr->cmp_rich = (compare_expr_rich_fc)g_boolean_operation_compare_rich; - expr->dup = (dup_expr_fc)g_boolean_operation_duplicate; + expr->copy = (copy_expr_fc)g_boolean_operation_copy; expr->reduce = (reduce_expr_fc)g_boolean_operation_reduce; } @@ -278,9 +278,9 @@ bool g_boolean_operation_create(GBoolOperation *op, BooleanOperationType type, G static bool g_boolean_operation_compare_rich(const GBoolOperation *item, const GBoolOperation *other, RichCmpOperation op, bool *status) { bool result; /* Etat à retourner */ - bool equal; /* Bilan intermédiaire */ - result = true; + result = g_type_is_a(G_TYPE_FROM_INSTANCE(other), G_TYPE_BOOLEAN_OPERATION); + if (!result) goto done; if (item->type != other->type) { @@ -288,15 +288,13 @@ static bool g_boolean_operation_compare_rich(const GBoolOperation *item, const G goto done; } - equal = g_comparable_item_compare_rich(G_COMPARABLE_ITEM(item), G_COMPARABLE_ITEM(other), RCO_EQ, status); + result = g_comparable_item_compare_rich(G_COMPARABLE_ITEM(item), G_COMPARABLE_ITEM(other), RCO_EQ, status); + if (!result || STATUS_NOT_EQUAL(*status, op)) goto done; - if (!equal) - { - *status = g_comparable_item_compare_rich(G_COMPARABLE_ITEM(item->first), - G_COMPARABLE_ITEM(other->first), - op, status); - goto done; - } + result = g_comparable_item_compare_rich(G_COMPARABLE_ITEM(item->first), + G_COMPARABLE_ITEM(other->first), + op, status); + if (!result || STATUS_NOT_EQUAL(*status, op)) goto done; if (item->second == NULL) { @@ -321,9 +319,9 @@ static bool g_boolean_operation_compare_rich(const GBoolOperation *item, const G } else - *status = g_comparable_item_compare_rich(G_COMPARABLE_ITEM(item->second), - G_COMPARABLE_ITEM(other->second), - op, status); + result = g_comparable_item_compare_rich(G_COMPARABLE_ITEM(item->second), + G_COMPARABLE_ITEM(other->second), + op, status); done: @@ -334,23 +332,31 @@ static bool g_boolean_operation_compare_rich(const GBoolOperation *item, const G /****************************************************************************** * * -* Paramètres : expr = expression à copier. * +* Paramètres : dest = emplacement d'enregistrement à constituer. [OUT] * +* src = expression source à copier. * * * * Description : Reproduit une expression en place dans une nouvelle instance.* * * -* Retour : Nouvelle instance d'expression. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -static GScanExpression *g_boolean_operation_duplicate(const GBoolOperation *expr) +static void g_boolean_operation_copy(GBoolOperation *dest, const GBoolOperation *src) { - GScanExpression *result; /* Instance copiée à retourner */ + GScanExpressionClass *class; /* Classe parente à solliciter */ - result = g_boolean_operation_new(expr->type, expr->first, expr->second); + class = G_SCAN_EXPRESSION_CLASS(g_boolean_operation_parent_class); - return result; + class->copy(G_SCAN_EXPRESSION(dest), G_SCAN_EXPRESSION(src)); + + dest->type = src->type; + + dest->first = g_scan_expression_duplicate(src->first); + + if (src->second != NULL) + dest->second = g_scan_expression_duplicate(src->second); } @@ -359,92 +365,115 @@ static GScanExpression *g_boolean_operation_duplicate(const GBoolOperation *expr * * * Paramètres : expr = expression à consulter. * * ctx = contexte de suivi de l'analyse courante. * -* final = impose une conversion finale de dernier tour. * +* scope = portée courante des variables locales. * +* out = zone d'enregistrement de la réduction opérée. [OUT] * * * * Description : Réduit une expression à une forme plus simple. * * * -* Retour : Réduction correspondante, expression déjà réduite, ou NULL. * +* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. * * * * Remarques : - * * * ******************************************************************************/ -GScanExpression *g_boolean_operation_reduce(GBoolOperation *expr, GScanContext *ctx, bool final) +static bool g_boolean_operation_reduce(GBoolOperation *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out) { - GScanExpression *result; /* Instance à renvoyer */ - GScanExpression *new; /* Nouvelle expression obtenue */ + bool result; /* Bilan à retourner */ + GScanExpression *new_first; /* Expression réduite (gauche) */ + GScanExpression *new_second; /* Expression réduite (droite) */ bool values[2]; /* Valeurs des éléments portés */ bool valid[2]; /* Validité de ces valeurs */ - result = NULL; - /* Réduction des éléments considérés */ - new = g_scan_expression_reduce(expr->first, ctx, final); + new_first = NULL; + new_second = NULL; + + result = g_scan_expression_reduce(expr->first, ctx, scope, &new_first); + if (!result) goto exit; - if (new != NULL) + if (expr->second == NULL) + new_second = NULL; + else { - g_object_unref(G_OBJECT(expr->first)); - expr->first = new; + result = g_scan_expression_reduce(expr->second, ctx, scope, &new_second); + if (!result) goto exit; } - if (expr->second != NULL) - { - new = g_scan_expression_reduce(expr->second, ctx, final); + /* Construction d'une réduction locale ? */ - if (new != NULL) - { - g_object_unref(G_OBJECT(expr->second)); - expr->second = new; - } + valid[0] = G_IS_LITERAL_EXPRESSION(new_first); - } + if (valid[0]) + valid[0] = g_literal_expression_get_boolean_value(G_LITERAL_EXPRESSION(new_first), &values[0]); - /* Construction d'une réduction locale ? */ + valid[1] = G_IS_LITERAL_EXPRESSION(new_second); + + if (valid[1]) + valid[1] = g_literal_expression_get_boolean_value(G_LITERAL_EXPRESSION(new_second), &values[1]); switch (expr->type) { case BOT_AND: - if (G_IS_LITERAL_EXPRESSION(expr->first) && G_IS_LITERAL_EXPRESSION(expr->second)) - { - valid[0] = g_literal_expression_get_boolean_value(G_LITERAL_EXPRESSION(expr->first), &values[0]); - valid[1] = g_literal_expression_get_boolean_value(G_LITERAL_EXPRESSION(expr->second), &values[1]); + if (valid[0] && valid[1]) + *out = g_literal_expression_new(EVT_BOOLEAN, (bool []) { values[0] && values[1] }); - if (valid[0] && valid[1]) - result = g_literal_expression_new(EVT_BOOLEAN, (bool []) { values[0] && values[1] }); + else if (valid[0] && !values[0]) + *out = g_literal_expression_new(EVT_BOOLEAN, (bool []) { false }); - else - /* Etre malin si 0 && x => bilan (si ctx->quick) */ - ; + else if (valid[1] && !values[1]) + *out = g_literal_expression_new(EVT_BOOLEAN, (bool []) { false }); - } break; case BOT_OR: - if (G_IS_LITERAL_EXPRESSION(expr->first) && G_IS_LITERAL_EXPRESSION(expr->second)) - { - valid[0] = g_literal_expression_get_boolean_value(G_LITERAL_EXPRESSION(expr->first), &values[0]); - valid[1] = g_literal_expression_get_boolean_value(G_LITERAL_EXPRESSION(expr->second), &values[1]); + if (valid[0] && valid[1]) + *out = g_literal_expression_new(EVT_BOOLEAN, (bool []) { values[0] || values[1] }); - if (valid[0] && valid[1]) - result = g_literal_expression_new(EVT_BOOLEAN, (bool []) { values[0] || values[1] }); + else if (valid[0] && values[0]) + *out = g_literal_expression_new(EVT_BOOLEAN, (bool []) { true }); + + else if (valid[1] && values[1]) + *out = g_literal_expression_new(EVT_BOOLEAN, (bool []) { true }); - } break; case BOT_NOT: - if (G_IS_LITERAL_EXPRESSION(expr->first)) - { - valid[0] = g_literal_expression_get_boolean_value(G_LITERAL_EXPRESSION(expr->first), &values[0]); + if (valid[0]) + *out = g_literal_expression_new(EVT_BOOLEAN, (bool []) { !values[0] }); + break; - if (valid[0]) - result = g_literal_expression_new(EVT_BOOLEAN, (bool []) { !values[1] }); + } + + /* Mise à jour de la progression ? */ + + if (*out == NULL) + { + if ((new_first != NULL && new_first != expr->first) || (new_second != NULL && new_second != expr->second)) + { + if (new_first == NULL) + { + new_first = expr->first; + g_object_ref(G_OBJECT(new_first)); + } + if (new_second == NULL) + { + new_second = expr->second; + g_object_ref(G_OBJECT(new_second)); } - break; + + *out = g_boolean_operation_new(expr->type, new_first, new_second); + + } } + exit: + + g_clear_object(&new_first); + g_clear_object(&new_second); + return result; } diff --git a/src/analysis/scan/exprs/call-int.h b/src/analysis/scan/exprs/call-int.h index d68977f..631a25b 100644 --- a/src/analysis/scan/exprs/call-int.h +++ b/src/analysis/scan/exprs/call-int.h @@ -28,35 +28,30 @@ #include "call.h" -#include "../expr-int.h" +#include "access-int.h" /* Exécution d'une fonction auxiliaire d'analyse (instance) */ struct _GPendingCall { - GScanExpression parent; /* A laisser en premier */ - - GRegisteredItem *base; /* Base de recherche */ - char *target; /* Cible dans l'espace */ + GNamedAccess parent; /* A laisser en premier */ GScanExpression **args; /* Arguments d'appel fournis */ size_t count; /* Quantité de ces arguments */ - struct _GPendingCall *next; /* Evnetuel prochain élément */ - }; /* Exécution d'une fonction auxiliaire d'analyse (classe) */ struct _GPendingCallClass { - GScanExpressionClass parent; /* A laisser en premier */ + GNamedAccessClass parent; /* A laisser en premier */ }; /* Met en place une expression d'appel. */ -bool g_pending_call_create(GPendingCall *, const char *, size_t, GScanExpression **, size_t); +bool g_pending_call_create(GPendingCall *, const sized_string_t *, GScanExpression **, size_t); diff --git a/src/analysis/scan/exprs/call.c b/src/analysis/scan/exprs/call.c index 76f5fc3..dde627c 100644 --- a/src/analysis/scan/exprs/call.c +++ b/src/analysis/scan/exprs/call.c @@ -24,6 +24,7 @@ #include "call.h" +#include <assert.h> #include <malloc.h> #include <string.h> @@ -48,19 +49,16 @@ static void g_pending_call_dispose(GPendingCall *); /* Procède à la libération totale de la mémoire. */ static void g_pending_call_finalize(GPendingCall *); -/* Définit une base de recherche pour la cible d'appel. */ -static void g_pending_call_set_base(GPendingCall *, GRegisteredItem *); - /* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ /* Reproduit une expression en place dans une nouvelle instance. */ -static GScanExpression *g_pending_call_duplicate(const GPendingCall *); +static void g_pending_call_copy(GPendingCall *, const GPendingCall *); /* Réduit une expression à une forme plus simple. */ -GScanExpression *g_pending_call_reduce(GPendingCall *, GScanContext *, bool); +static bool g_pending_call_reduce(GPendingCall *, GScanContext *, GScanScope *, GScanExpression **); @@ -70,7 +68,7 @@ GScanExpression *g_pending_call_reduce(GPendingCall *, GScanContext *, bool); /* Indique le type défini pour un appel de fonction enregistrée. */ -G_DEFINE_TYPE(GPendingCall, g_pending_call, G_TYPE_SCAN_EXPRESSION); +G_DEFINE_TYPE(GPendingCall, g_pending_call, G_TYPE_NAMED_ACCESS); /****************************************************************************** @@ -98,7 +96,7 @@ static void g_pending_call_class_init(GPendingCallClass *klass) expr = G_SCAN_EXPRESSION_CLASS(klass); expr->cmp_rich = (compare_expr_rich_fc)NULL; - expr->dup = (dup_expr_fc)g_pending_call_duplicate; + expr->copy = (copy_expr_fc)g_pending_call_copy; expr->reduce = (reduce_expr_fc)g_pending_call_reduce; } @@ -118,14 +116,9 @@ static void g_pending_call_class_init(GPendingCallClass *klass) static void g_pending_call_init(GPendingCall *call) { - call->base = NULL; - call->target = NULL; - call->args = NULL; call->count = 0; - call->next = NULL; - } @@ -145,13 +138,9 @@ static void g_pending_call_dispose(GPendingCall *call) { size_t i; /* Boucle de parcours */ - g_clear_object(&call->base); - for (i = 0; i < call->count; i++) g_clear_object(&call->args[i]); - g_clear_object(&call->next); - G_OBJECT_CLASS(g_pending_call_parent_class)->dispose(G_OBJECT(call)); } @@ -171,9 +160,6 @@ static void g_pending_call_dispose(GPendingCall *call) static void g_pending_call_finalize(GPendingCall *call) { - if (call->target != NULL) - free(call->target); - if (call->args != NULL) free(call->args); @@ -185,7 +171,6 @@ static void g_pending_call_finalize(GPendingCall *call) /****************************************************************************** * * * Paramètres : target = désignation de l'objet d'appel à identifier. * -* len = taille de cette désignation. * * args = éventuelle liste d'arguments à actionner. * * count = quantité de ces arguments. * * * @@ -197,13 +182,13 @@ static void g_pending_call_finalize(GPendingCall *call) * * ******************************************************************************/ -GScanExpression *g_pending_call_new(const char *target, size_t len, GScanExpression **args, size_t count) +GScanExpression *g_pending_call_new(const sized_string_t *target, GScanExpression **args, size_t count) { GScanExpression *result; /* Structure à retourner */ result = g_object_new(G_TYPE_PENDING_CALL, NULL); - if (!g_pending_call_create(G_PENDING_CALL(result), target, len, args, count)) + if (!g_pending_call_create(G_PENDING_CALL(result), target, args, count)) g_clear_object(&result); return result; @@ -215,7 +200,6 @@ GScanExpression *g_pending_call_new(const char *target, size_t len, GScanExpress * * * Paramètres : call = instance à initialiser pleinement. * * target = désignation de l'objet d'appel à identifier. * -* len = taille de cette désignation. * * args = éventuelle liste d'arguments à actionner. * * count = quantité de ces arguments. * * * @@ -227,16 +211,14 @@ GScanExpression *g_pending_call_new(const char *target, size_t len, GScanExpress * * ******************************************************************************/ -bool g_pending_call_create(GPendingCall *call, const char *target, size_t len, GScanExpression **args, size_t count) +bool g_pending_call_create(GPendingCall *call, const sized_string_t *target, GScanExpression **args, size_t count) { bool result; /* Bilan à retourner */ size_t i; /* Boucle de parcours */ - result = g_scan_expression_create(G_SCAN_EXPRESSION(call), EVT_PENDING); + result = g_named_access_create(G_NAMED_ACCESS(call), target); if (!result) goto exit; - call->target = strndup(target, len); - call->args = malloc(count * sizeof(GScanExpression *)); call->count = count; @@ -253,48 +235,6 @@ bool g_pending_call_create(GPendingCall *call, const char *target, size_t len, G } -/****************************************************************************** -* * -* Paramètres : call = expression d'appel à actualiser. * -* base = zone de recherche pour la résolution à venir. * -* * -* Description : Définit une base de recherche pour la cible d'appel. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_pending_call_set_base(GPendingCall *call, GRegisteredItem *base) -{ - call->base = base; - g_object_ref(G_OBJECT(base)); - -} - - -/****************************************************************************** -* * -* Paramètres : call = expression d'appel à compléter. * -* next = expression d'appel suivante dans la chaîne. * -* * -* Description : Complète la chaine d'expressions d'appel. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void g_pending_call_attach_next(GPendingCall *call, GPendingCall *next) -{ - call->next = next; - g_object_ref(G_OBJECT(next)); - -} - - /* ---------------------------------------------------------------------------------- */ /* IMPLEMENTATION DES FONCTIONS DE CLASSE */ @@ -303,23 +243,31 @@ void g_pending_call_attach_next(GPendingCall *call, GPendingCall *next) /****************************************************************************** * * -* Paramètres : expr = expression à copier. * +* Paramètres : dest = emplacement d'enregistrement à constituer. [OUT] * +* src = expression source à copier. * * * * Description : Reproduit une expression en place dans une nouvelle instance.* * * -* Retour : Nouvelle instance d'expression. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -static GScanExpression *g_pending_call_duplicate(const GPendingCall *expr) +static void g_pending_call_copy(GPendingCall *dest, const GPendingCall *src) { - GScanExpression *result; /* Instance copiée à retourner */ + GScanExpressionClass *class; /* Classe parente à solliciter */ + size_t i; /* Boucle de parcours */ - result = g_pending_call_new(expr->target, strlen(expr->target), expr->args, expr->count); + class = G_SCAN_EXPRESSION_CLASS(g_pending_call_parent_class); - return result; + class->copy(G_SCAN_EXPRESSION(dest), G_SCAN_EXPRESSION(src)); + + dest->args = malloc(src->count * sizeof(GScanExpression *)); + dest->count = src->count; + + for (i = 0; i < src->count; i++) + dest->args[i] = g_scan_expression_duplicate(src->args[i]); } @@ -328,99 +276,100 @@ static GScanExpression *g_pending_call_duplicate(const GPendingCall *expr) * * * Paramètres : expr = expression à consulter. * * ctx = contexte de suivi de l'analyse courante. * -* final = indique une ultime conversion dans le cycle en cours.* +* scope = portée courante des variables locales. * +* out = zone d'enregistrement de la réduction opérée. [OUT] * * * * Description : Réduit une expression à une forme plus simple. * * * -* Retour : Réduction correspondante, expression déjà réduite, ou NULL. * +* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. * * * * Remarques : - * * * ******************************************************************************/ -GScanExpression *g_pending_call_reduce(GPendingCall *expr, GScanContext *ctx, bool final) +static bool g_pending_call_reduce(GPendingCall *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out) { - GScanExpression *result; /* Instance à renvoyer */ + bool result; /* Bilan à retourner */ + GNamedAccess *new; /* Eventuel étage suivant */ + GPendingCall *new_call; /* Version en appel */ size_t i; /* Boucle de parcours */ - GScanExpression *new; /* Nouvelle expression obtenue */ - bool last; /* Détection de fin de chaîne */ - GRegisteredItem *base; /* Base de recherche courante */ - GRegisteredItem *rebase; /* Nouvelle base résolue */ + GScanExpression *arg; /* Argument réduit à échanger */ + GObject *final; /* Expression ou élément ? */ GScanExpression *new_next; /* Nouvelle version du suivant */ - for (i = 0; i < expr->count; i++) + result = _g_named_access_reduce(G_NAMED_ACCESS(expr), ctx, scope, out); + + if (result && *out != NULL) { - new = g_scan_expression_reduce(expr->args[i], ctx, final); + assert(G_IS_NAMED_ACCESS(*out)); - if (new != NULL) - { - g_object_unref(G_OBJECT(expr->args[i])); - expr->args[i] = new; - } + new = G_NAMED_ACCESS(*out); + *out = NULL; - } + assert(new->target == NULL); + assert(G_IS_PENDING_CALL(new)); + assert(G_IS_REGISTERED_ITEM(new->resolved)); - last = (expr->next == NULL); + new_call = G_PENDING_CALL(new); - if (!last) - new_next = g_scan_expression_duplicate(G_SCAN_EXPRESSION(expr->next)); - else - new_next = NULL; - - if (expr->target != NULL) - { - if (expr->base != NULL) + for (i = 0; i < new_call->count; i++) { - base = expr->base; - g_object_ref(G_OBJECT(base)); - } - else - base = G_REGISTERED_ITEM(get_rost_root_namespace()); + result = g_scan_expression_reduce(new_call->args[i], ctx, scope, &arg); + if (!result) goto exit; - rebase = g_registered_item_resolve(base, expr->target, ctx, - last ? NULL : expr->args, last ? 0 : expr->count, - last, final); + if (arg != NULL) + { + g_object_unref(G_OBJECT(new_call->args[i])); + new_call->args[i] = arg; + } - g_object_unref(G_OBJECT(base)); - if (rebase == NULL) - { - result = NULL; - goto done; } - if (last) - { - g_pending_call_set_base(expr, rebase); + result = g_registered_item_run_call(new->resolved, + new_call->args, + new_call->count, + ctx, scope, &final); - free(expr->target); - expr->target = NULL; + if (result && final != NULL) + { + /** + * Si le produit de l'appel à la fonction est une expression d'évaluation + * classique, alors ce produit constitue la réduction finale de la chaîne. + * + * Ce cas de figure ne se rencontre normalement qu'en bout de chaîne. + */ + if (!G_IS_REGISTERED_ITEM(final)) + { + assert(new->next == NULL); + *out = G_SCAN_EXPRESSION(final); + } + else + { + assert(new->next != NULL); + + new_next = g_scan_expression_duplicate(G_SCAN_EXPRESSION(new->next)); + assert(G_IS_NAMED_ACCESS(new_next)); + + g_named_access_set_base(G_NAMED_ACCESS(new_next), G_REGISTERED_ITEM(final)); + + result = g_scan_expression_reduce(new_next, ctx, scope, out); + + if (result && *out == NULL) + *out = new_next; + else + g_object_unref(G_OBJECT(new_next)); + + } } - else - g_pending_call_set_base(G_PENDING_CALL(new_next), rebase); - - } - if (last) - result = g_registered_item_reduce(expr->base, ctx, expr->args, expr->count, final); + exit: - else - { - result = g_scan_expression_reduce(new_next, ctx, final); - - if (result == NULL) - { - g_object_ref(G_OBJECT(new_next)); - result = new_next; - } + g_object_unref(G_OBJECT(new)); } - done: - - g_clear_object(&new_next); - return result; } diff --git a/src/analysis/scan/exprs/call.h b/src/analysis/scan/exprs/call.h index b69ca85..c344036 100644 --- a/src/analysis/scan/exprs/call.h +++ b/src/analysis/scan/exprs/call.h @@ -26,7 +26,7 @@ #include "../expr.h" -#include "../item.h" +#include "../../../common/szstr.h" @@ -49,10 +49,7 @@ typedef struct _GPendingCallClass GPendingCallClass; GType g_pending_call_get_type(void); /* Organise un appel de fonction avec ses arguments. */ -GScanExpression *g_pending_call_new(const char *, size_t, GScanExpression **, size_t); - -/* Complète la chaine d'expressions d'appel. */ -void g_pending_call_attach_next(GPendingCall *, GPendingCall *); +GScanExpression *g_pending_call_new(const sized_string_t *, GScanExpression **, size_t); diff --git a/src/analysis/scan/exprs/literal-int.h b/src/analysis/scan/exprs/literal-int.h index d803d30..875b3de 100644 --- a/src/analysis/scan/exprs/literal-int.h +++ b/src/analysis/scan/exprs/literal-int.h @@ -46,7 +46,7 @@ struct _GLiteralExpression { bool boolean; /* Valeur booléenne */ unsigned long long integer; /* Valeur entière 64 bits */ - char *string; /* Chaîne de caractères */ + sized_string_t string; /* Chaîne de caractères */ struct { char *regex; /* Formulation d'origine */ diff --git a/src/analysis/scan/exprs/literal.c b/src/analysis/scan/exprs/literal.c index f40747d..119b871 100644 --- a/src/analysis/scan/exprs/literal.c +++ b/src/analysis/scan/exprs/literal.c @@ -57,10 +57,10 @@ static void g_literal_expression_finalize(GLiteralExpression *); static bool g_literal_expression_compare_rich(const GLiteralExpression *, const GLiteralExpression *, RichCmpOperation, bool *); /* Reproduit une expression en place dans une nouvelle instance. */ -static GScanExpression *g_literal_expression_duplicate(const GLiteralExpression *); +static void g_literal_expression_copy(GLiteralExpression *, const GLiteralExpression *); /* Réduit une expression à une forme plus simple. */ -GScanExpression *g_literal_expression_reduce(GLiteralExpression *, GScanContext *, bool); +static bool g_literal_expression_reduce(GLiteralExpression *, GScanContext *, GScanScope *, GScanExpression **); @@ -98,7 +98,7 @@ static void g_literal_expression_class_init(GLiteralExpressionClass *klass) expr = G_SCAN_EXPRESSION_CLASS(klass); expr->cmp_rich = (compare_expr_rich_fc)g_literal_expression_compare_rich; - expr->dup = (dup_expr_fc)g_literal_expression_duplicate; + expr->copy = (copy_expr_fc)g_literal_expression_copy; expr->reduce = (reduce_expr_fc)g_literal_expression_reduce; } @@ -215,7 +215,8 @@ bool g_literal_expression_create(GLiteralExpression *expr, ExprValueType vtype, va_list ap; /* Liste d'arguements */ const bool *boolean; /* Valeur booléenne */ const unsigned long long *integer; /* Valeur entière 64 bits */ - const char *string; /* Chaîne de caractères */ + const sized_string_t *string; /* Chaîne de caractères */ + const char *raw; /* Chaîne de caractères brute */ size_t len; /* Taille de la chaîne */ int cflags; /* Détails de compilation */ unsigned int i; /* Boucle de parcours */ @@ -241,15 +242,15 @@ bool g_literal_expression_create(GLiteralExpression *expr, ExprValueType vtype, break; case EVT_STRING: - string = va_arg(ap, const char *); - expr->value.string = strdup(string); + string = va_arg(ap, const sized_string_t *); + szstrdup(&expr->value.string, string); break; case EVT_REG_EXPR: - string = va_arg(ap, const char *); - len = strlen(string); + raw = va_arg(ap, const char *); + len = strlen(raw); - result = (len > 2 && string[0] == '/'); + result = (len > 2 && raw[0] == '/'); cflags = REG_EXTENDED | REG_NOSUB; @@ -257,38 +258,38 @@ bool g_literal_expression_create(GLiteralExpression *expr, ExprValueType vtype, { result = (len > 2); - if (string[len - 1] == 'i') + if (raw[len - 1] == 'i') { cflags |= REG_ICASE; len -= 1; } - else if (string[len - 1] == 's') + else if (raw[len - 1] == 's') { cflags |= REG_NEWLINE; len -= 1; } - else if (string[len - 1] == '/') + else if (raw[len - 1] == '/') break; } if (result) - result = (string[len - 1] == '/'); + result = (raw[len - 1] == '/'); if (result) { assert(len > 2); - tmp = strndup(&string[1], len - 2); + tmp = strndup(&raw[1], len - 2); ret = regcomp(&expr->value.preg, tmp, cflags); free(tmp); result = (ret == 0); if (result) - expr->value.regex = strdup(string); + expr->value.regex = strdup(raw); } @@ -378,14 +379,14 @@ bool g_literal_expression_get_integer_value(const GLiteralExpression *item, unsi * * ******************************************************************************/ -bool g_literal_expression_get_string_value(const GLiteralExpression *item, const char **value) +bool g_literal_expression_get_string_value(const GLiteralExpression *item, const sized_string_t **value) { bool result; /* Etat à retourner */ result = (item->value_type == EVT_STRING); if (result) - *value = item->value.string; + *value = &item->value.string; return result; @@ -445,10 +446,12 @@ static bool g_literal_expression_compare_rich(const GLiteralExpression *item, co bool result; /* Etat à retourner */ int cmp; /* Bilan intermédiaire */ + result = g_type_is_a(G_TYPE_FROM_INSTANCE(other), G_TYPE_LITERAL_EXPRESSION); + if (!result) goto done; + if (item->value_type != other->value_type) { *status = compare_rich_integer_values(item->value_type, other->value_type, op); - result = true; goto done; } @@ -480,7 +483,7 @@ static bool g_literal_expression_compare_rich(const GLiteralExpression *item, co break; case EVT_STRING: - cmp = strcmp(item->value.string, other->value.string); + cmp = szstrcmp(&item->value.string, &other->value.string); *status = compare_rich_integer_values(cmp, 0, op); result = true; break; @@ -506,51 +509,51 @@ static bool g_literal_expression_compare_rich(const GLiteralExpression *item, co /****************************************************************************** * * -* Paramètres : expr = expression à copier. * +* Paramètres : dest = emplacement d'enregistrement à constituer. [OUT] * +* src = expression source à copier. * * * * Description : Reproduit une expression en place dans une nouvelle instance.* * * -* Retour : Nouvelle instance d'expression. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -static GScanExpression *g_literal_expression_duplicate(const GLiteralExpression *expr) +static void g_literal_expression_copy(GLiteralExpression *dest, const GLiteralExpression *src) { - GScanExpression *result; /* Instance copiée à retourner */ - const void *ptr; /* Pointeur vers des données */ + GScanExpressionClass *class; /* Classe parente à solliciter */ + + class = G_SCAN_EXPRESSION_CLASS(g_literal_expression_parent_class); + + class->copy(G_SCAN_EXPRESSION(dest), G_SCAN_EXPRESSION(src)); - switch (expr->value_type) + dest->value_type = src->value_type; + + switch (src->value_type) { case EVT_BOOLEAN: - ptr = &expr->value.boolean; + dest->value.boolean = src->value.boolean; break; case EVT_INTEGER: - ptr = &expr->value.integer; + dest->value.integer = src->value.integer; break; case EVT_STRING: - ptr = &expr->value.string; + szstrdup(&dest->value.string, &src->value.string); break; case EVT_REG_EXPR: - ptr = &expr->value.regex; + /*ptr = &expr->value.regex*//* FIXME */; break; default: - ptr = NULL; + assert(false); break; } - assert(ptr != NULL); - - result = g_literal_expression_new(expr->value_type, ptr); - - return result; - } @@ -558,47 +561,25 @@ static GScanExpression *g_literal_expression_duplicate(const GLiteralExpression * * * Paramètres : expr = expression à consulter. * * ctx = contexte de suivi de l'analyse courante. * -* force = impose une conversion en booléen si possible. * +* scope = portée courante des variables locales. * +* out = zone d'enregistrement de la réduction opérée. [OUT] * * * * Description : Réduit une expression à une forme plus simple. * * * -* Retour : Réduction correspondante, expression déjà réduite, ou NULL. * +* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. * * * * Remarques : - * * * ******************************************************************************/ -GScanExpression *g_literal_expression_reduce(GLiteralExpression *expr, GScanContext *ctx, bool force) +static bool g_literal_expression_reduce(GLiteralExpression *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out) { - GScanExpression *result; /* Instance à renvoyer */ - - if (!force) - result = NULL; - - else - switch (expr->value_type) - { - case EVT_BOOLEAN: - result = NULL; - break; - - case EVT_INTEGER: - result = g_literal_expression_new(EVT_BOOLEAN, (bool []) { expr->value.integer > 0 }); - break; - - case EVT_STRING: - result = g_literal_expression_new(EVT_BOOLEAN, (bool []) { strlen(expr->value.string) > 0 }); - break; - - case EVT_REG_EXPR: - result = g_literal_expression_new(EVT_BOOLEAN, (bool []) { strlen(expr->value.regex) > 0 }); - break; + bool result; /* Bilan à retourner */ - default: - result = NULL; - break; + result = true; - } + *out = G_SCAN_EXPRESSION(expr); + g_object_ref(G_OBJECT(expr)); return result; diff --git a/src/analysis/scan/exprs/literal.h b/src/analysis/scan/exprs/literal.h index ac5724f..7120c07 100644 --- a/src/analysis/scan/exprs/literal.h +++ b/src/analysis/scan/exprs/literal.h @@ -29,6 +29,7 @@ #include "../expr.h" +#include "../../../common/szstr.h" @@ -60,7 +61,7 @@ bool g_literal_expression_get_boolean_value(const GLiteralExpression *, bool *); bool g_literal_expression_get_integer_value(const GLiteralExpression *, unsigned long long *); /* Indique la valeur portée par une expression de chaîne. */ -bool g_literal_expression_get_string_value(const GLiteralExpression *, const char **); +bool g_literal_expression_get_string_value(const GLiteralExpression *, const sized_string_t **); /* Indique la valeur portée par une expression rationnelle. */ bool g_literal_expression_get_regex_value(const GLiteralExpression *, const regex_t **); diff --git a/src/analysis/scan/exprs/relop-int.h b/src/analysis/scan/exprs/relop-int.h index 273b543..3adbcf0 100644 --- a/src/analysis/scan/exprs/relop-int.h +++ b/src/analysis/scan/exprs/relop-int.h @@ -39,8 +39,8 @@ struct _GRelOperation RichCmpOperation rel_type; /* Type de relation étudiée */ - GScanExpression *first; /* Expression impactée #1 */ - GScanExpression *second; /* Expression impactée #2 */ + GScanExpression *left; /* Expression impactée #1 */ + GScanExpression *right; /* Expression impactée #2 */ }; diff --git a/src/analysis/scan/exprs/relop.c b/src/analysis/scan/exprs/relop.c index 94ce77d..7dc6864 100644 --- a/src/analysis/scan/exprs/relop.c +++ b/src/analysis/scan/exprs/relop.c @@ -52,11 +52,11 @@ static void g_relational_operation_finalize(GRelOperation *); /* Réalise une comparaison entre objets selon un critère précis. */ static bool g_relational_operation_compare_rich(const GRelOperation *, const GRelOperation *, RichCmpOperation, bool *); -/* Initialise une instance d'opération de relation. */ -static GScanExpression *g_relational_operation_duplicate(const GRelOperation *); +/* Reproduit une expression en place dans une nouvelle instance. */ +static void g_relational_operation_copy(GRelOperation *, const GRelOperation *); /* Réduit une expression à une forme plus simple. */ -GScanExpression *g_relational_operation_reduce(GRelOperation *, GScanContext *, bool); +static bool g_relational_operation_reduce(GRelOperation *, GScanContext *, GScanScope *, GScanExpression **); @@ -94,7 +94,7 @@ static void g_relational_operation_class_init(GRelOperationClass *klass) expr = G_SCAN_EXPRESSION_CLASS(klass); expr->cmp_rich = (compare_expr_rich_fc)g_relational_operation_compare_rich; - expr->dup = (dup_expr_fc)g_relational_operation_duplicate; + expr->copy = (copy_expr_fc)g_relational_operation_copy; expr->reduce = (reduce_expr_fc)g_relational_operation_reduce; } @@ -114,8 +114,8 @@ static void g_relational_operation_class_init(GRelOperationClass *klass) static void g_relational_operation_init(GRelOperation *op) { - op->first = NULL; - op->second = NULL; + op->left = NULL; + op->right = NULL; } @@ -134,8 +134,8 @@ static void g_relational_operation_init(GRelOperation *op) static void g_relational_operation_dispose(GRelOperation *op) { - g_clear_object(&op->first); - g_clear_object(&op->second); + g_clear_object(&op->left); + g_clear_object(&op->right); G_OBJECT_CLASS(g_relational_operation_parent_class)->dispose(G_OBJECT(op)); @@ -163,9 +163,9 @@ static void g_relational_operation_finalize(GRelOperation *op) /****************************************************************************** * * -* Paramètres : type = type d'opération booléenne à représenter. * -* first = premier opérande concerné. * -* second = éventuel second opérande impliqué ou NULL. * +* Paramètres : type = type d'opération booléenne à représenter. * +* left = premier opérande concerné. * +* right = éventuel second opérande impliqué ou NULL. * * * * Description : Organise une opération relationnelle entre expressions. * * * @@ -175,13 +175,13 @@ static void g_relational_operation_finalize(GRelOperation *op) * * ******************************************************************************/ -GScanExpression *g_relational_operation_new(RichCmpOperation type, GScanExpression *first, GScanExpression *second) +GScanExpression *g_relational_operation_new(RichCmpOperation type, GScanExpression *left, GScanExpression *right) { GScanExpression *result; /* Structure à retourner */ result = g_object_new(G_TYPE_RELATIONAL_OPERATION, NULL); - if (!g_relational_operation_create(G_RELATIONAL_OPERATION(result), type, first, second)) + if (!g_relational_operation_create(G_RELATIONAL_OPERATION(result), type, left, right)) g_clear_object(&result); return result; @@ -191,10 +191,10 @@ GScanExpression *g_relational_operation_new(RichCmpOperation type, GScanExpressi /****************************************************************************** * * -* Paramètres : op = instance à initialiser pleinement. * -* type = type d'opération booléenne à représenter. * -* first = premier opérande concerné. * -* second = éventuel second opérande impliqué ou NULL. * +* Paramètres : op = instance à initialiser pleinement. * +* type = type d'opération booléenne à représenter. * +* left = premier opérande concerné. * +* right = éventuel second opérande impliqué ou NULL. * * * * Description : Met en place une opération relationnelle entre expressions. * * * @@ -204,13 +204,13 @@ GScanExpression *g_relational_operation_new(RichCmpOperation type, GScanExpressi * * ******************************************************************************/ -bool g_relational_operation_create(GRelOperation *op, RichCmpOperation type, GScanExpression *first, GScanExpression *second) +bool g_relational_operation_create(GRelOperation *op, RichCmpOperation type, GScanExpression *left, GScanExpression *right) { bool result; /* Bilan à retourner */ result = false; - if (g_scan_expression_get_value_type(first) != g_scan_expression_get_value_type(first)) + if (g_scan_expression_get_value_type(left) != g_scan_expression_get_value_type(left)) goto exit; if (!g_scan_expression_create(G_SCAN_EXPRESSION(op), EVT_BOOLEAN)) @@ -218,11 +218,11 @@ bool g_relational_operation_create(GRelOperation *op, RichCmpOperation type, GSc op->rel_type = type; - op->first = first; - g_object_ref(G_OBJECT(op->first)); + op->left = left; + g_object_ref(G_OBJECT(op->left)); - op->second = second; - g_object_ref(G_OBJECT(op->second)); + op->right = right; + g_object_ref(G_OBJECT(op->right)); result = true; @@ -257,28 +257,26 @@ bool g_relational_operation_create(GRelOperation *op, RichCmpOperation type, GSc static bool g_relational_operation_compare_rich(const GRelOperation *item, const GRelOperation *other, RichCmpOperation op, bool *status) { bool result; /* Etat à retourner */ - bool equal; /* Bilan intermédiaire */ - result = true; // TODO : cmp parent()->type + result = g_type_is_a(G_TYPE_FROM_INSTANCE(other), G_TYPE_RELATIONAL_OPERATION); + if (!result) goto done; if (item->rel_type != other->rel_type) { - result = compare_rich_integer_values(item->rel_type, other->rel_type, op); + *status = compare_rich_integer_values(item->rel_type, other->rel_type, op); goto done; } - equal = g_comparable_item_compare_rich(G_COMPARABLE_ITEM(item), G_COMPARABLE_ITEM(other), RCO_EQ, status); + result = g_comparable_item_compare_rich(G_COMPARABLE_ITEM(item), G_COMPARABLE_ITEM(other), RCO_EQ, status); + if (!result || STATUS_NOT_EQUAL(*status, op)) goto done; - if (!equal) - { - result = g_comparable_item_compare_rich(G_COMPARABLE_ITEM(item->first), - G_COMPARABLE_ITEM(other->first), - op, status); - goto done; - } + result = g_comparable_item_compare_rich(G_COMPARABLE_ITEM(item->left), + G_COMPARABLE_ITEM(other->left), + op, status); + if (!result || STATUS_NOT_EQUAL(*status, op)) goto done; - result = g_comparable_item_compare_rich(G_COMPARABLE_ITEM(item->second), - G_COMPARABLE_ITEM(other->second), + result = g_comparable_item_compare_rich(G_COMPARABLE_ITEM(item->right), + G_COMPARABLE_ITEM(other->right), op, status); done: @@ -290,23 +288,29 @@ static bool g_relational_operation_compare_rich(const GRelOperation *item, const /****************************************************************************** * * -* Paramètres : expr = expression à copier. * +* Paramètres : dest = emplacement d'enregistrement à constituer. [OUT] * +* src = expression source à copier. * * * * Description : Reproduit une expression en place dans une nouvelle instance.* * * -* Retour : Nouvelle instance d'expression. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -static GScanExpression *g_relational_operation_duplicate(const GRelOperation *expr) +static void g_relational_operation_copy(GRelOperation *dest, const GRelOperation *src) { - GScanExpression *result; /* Instance copiée à retourner */ + GScanExpressionClass *class; /* Classe parente à solliciter */ - result = g_relational_operation_new(expr->rel_type, expr->first, expr->second); + class = G_SCAN_EXPRESSION_CLASS(g_relational_operation_parent_class); - return result; + class->copy(G_SCAN_EXPRESSION(dest), G_SCAN_EXPRESSION(src)); + + dest->rel_type = src->rel_type; + + dest->left = g_scan_expression_duplicate(src->left); + dest->right = g_scan_expression_duplicate(src->right); } @@ -315,60 +319,74 @@ static GScanExpression *g_relational_operation_duplicate(const GRelOperation *ex * * * Paramètres : expr = expression à consulter. * * ctx = contexte de suivi de l'analyse courante. * -* final = impose une conversion finale de dernier tour. * +* scope = portée courante des variables locales. * +* out = zone d'enregistrement de la réduction opérée. [OUT] * * * * Description : Réduit une expression à une forme plus simple. * * * -* Retour : Réduction correspondante, expression déjà réduite, ou NULL. * +* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. * * * * Remarques : - * * * ******************************************************************************/ -GScanExpression *g_relational_operation_reduce(GRelOperation *expr, GScanContext *ctx, bool final) +static bool g_relational_operation_reduce(GRelOperation *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out) { - GScanExpression *result; /* Instance à renvoyer */ - GScanExpression *new; /* Nouvelle expression obtenue */ + bool result; /* Bilan à retourner */ + GScanExpression *new_left; /* Expression réduite (gauche) */ + GScanExpression *new_right; /* Expression réduite (droite) */ bool status; /* Bilan d'une comparaison */ bool valid; /* Validité de ce bilan obtenu */ - result = NULL; - /* Réduction des éléments considérés */ - new = g_scan_expression_reduce(expr->first, ctx, final); + new_left = NULL; + new_right = NULL; - if (new != NULL) - { - g_object_unref(G_OBJECT(expr->first)); - expr->first = new; - } + result = g_scan_expression_reduce(expr->left, ctx, scope, &new_left); + if (!result) goto exit; + + result = g_scan_expression_reduce(expr->right, ctx, scope, &new_right); + if (!result) goto exit; + + /* Construction d'une réduction locale ? */ - if (expr->second != NULL) + if (G_IS_LITERAL_EXPRESSION(new_left) && G_IS_LITERAL_EXPRESSION(new_right)) { - new = g_scan_expression_reduce(expr->second, ctx, final); + valid = g_comparable_item_compare_rich(G_COMPARABLE_ITEM(new_left), + G_COMPARABLE_ITEM(new_right), + expr->rel_type, &status); - if (new != NULL) - { - g_object_unref(G_OBJECT(expr->second)); - expr->second = new; - } + if (valid) + *out = g_literal_expression_new(EVT_BOOLEAN, (bool []) { status }); } - /* Construction d'une réduction locale ? */ + /* Mise à jour de la progression ? */ - if (G_IS_LITERAL_EXPRESSION(expr->first) && G_IS_LITERAL_EXPRESSION(expr->second)) + else if ((new_left != NULL && new_left != expr->left) || (new_right != NULL && new_right != expr->right)) { - valid = g_comparable_item_compare_rich(G_COMPARABLE_ITEM(expr->first), - G_COMPARABLE_ITEM(expr->second), - expr->rel_type, &status); + if (new_left == NULL) + { + new_left = expr->left; + g_object_ref(G_OBJECT(new_left)); + } - if (valid) - result = g_literal_expression_new(EVT_BOOLEAN, (bool []) { status }); + if (new_right == NULL) + { + new_right = expr->right; + g_object_ref(G_OBJECT(new_right)); + } + + *out = g_relational_operation_new(expr->rel_type, new_left, new_right); } + exit: + + g_clear_object(&new_left); + g_clear_object(&new_right); + return result; } diff --git a/src/analysis/scan/exprs/str-int.h b/src/analysis/scan/exprs/strop-int.h index 9bed5cf..234ae8f 100644 --- a/src/analysis/scan/exprs/str-int.h +++ b/src/analysis/scan/exprs/strop-int.h @@ -1,6 +1,6 @@ /* Chrysalide - Outil d'analyse de fichiers binaires - * str-int.h - prototypes internes pour la gestion des opérations booléennes + * strop-int.h - prototypes internes pour la gestion des opérations booléennes * * Copyright (C) 2022 Cyrille Bagard * @@ -21,14 +21,15 @@ */ -#ifndef _ANALYSIS_SCAN_EXPRS_STR_INT_H -#define _ANALYSIS_SCAN_EXPRS_STR_INT_H +#ifndef _ANALYSIS_SCAN_EXPRS_STROP_INT_H +#define _ANALYSIS_SCAN_EXPRS_STROP_INT_H -#include "str.h" +#include "strop.h" #include "../expr-int.h" +#include "../../../common/extstr.h" @@ -40,8 +41,8 @@ struct _GStringOperation StringOperationType type; /* Type d'opération menée */ bool case_sensitive; /* Respect de la casse ? */ - GScanExpression *first; /* Expression impactée #1 */ - GScanExpression *second; /* Expression impactée #2 */ + GScanExpression *left; /* Expression impactée #1 */ + GScanExpression *right; /* Expression impactée #2 */ }; @@ -58,4 +59,4 @@ bool g_string_operation_create(GStringOperation *, StringOperationType, GScanExp -#endif /* _ANALYSIS_SCAN_EXPRS_STR_INT_H */ +#endif /* _ANALYSIS_SCAN_EXPRS_STROP_INT_H */ diff --git a/src/analysis/scan/exprs/str.c b/src/analysis/scan/exprs/strop.c index 675b2f6..145e8da 100644 --- a/src/analysis/scan/exprs/str.c +++ b/src/analysis/scan/exprs/strop.c @@ -1,6 +1,6 @@ /* Chrysalide - Outil d'analyse de fichiers binaires - * str.c - gestion des opérations booléennes + * strop.c - gestion des opérations booléennes * * Copyright (C) 2022 Cyrille Bagard * @@ -21,7 +21,7 @@ */ -#include "str.h" +#include "strop.h" #include <assert.h> @@ -29,7 +29,7 @@ #include <strings.h> -#include "str-int.h" +#include "strop-int.h" #include "literal.h" @@ -55,10 +55,10 @@ static void g_string_operation_finalize(GStringOperation *); /* Reproduit une expression en place dans une nouvelle instance. */ -static GScanExpression *g_string_operation_duplicate(const GStringOperation *); +static void g_string_operation_copy(GStringOperation *, const GStringOperation *); /* Réduit une expression à une forme plus simple. */ -GScanExpression *g_string_operation_reduce(GStringOperation *, GScanContext *, bool); +static bool g_string_operation_reduce(GStringOperation *, GScanContext *, GScanScope *, GScanExpression **); @@ -96,7 +96,7 @@ static void g_string_operation_class_init(GStringOperationClass *klass) expr = G_SCAN_EXPRESSION_CLASS(klass); expr->cmp_rich = (compare_expr_rich_fc)NULL; - expr->dup = (dup_expr_fc)g_string_operation_duplicate; + expr->copy = (copy_expr_fc)g_string_operation_copy; expr->reduce = (reduce_expr_fc)g_string_operation_reduce; } @@ -116,8 +116,8 @@ static void g_string_operation_class_init(GStringOperationClass *klass) static void g_string_operation_init(GStringOperation *op) { - op->first = NULL; - op->second = NULL; + op->left = NULL; + op->right = NULL; } @@ -136,8 +136,8 @@ static void g_string_operation_init(GStringOperation *op) static void g_string_operation_dispose(GStringOperation *op) { - g_clear_object(&op->first); - g_clear_object(&op->second); + g_clear_object(&op->left); + g_clear_object(&op->right); G_OBJECT_CLASS(g_string_operation_parent_class)->dispose(G_OBJECT(op)); @@ -196,9 +196,9 @@ GScanExpression *g_string_operation_new(StringOperationType type, GScanExpressio * * * Paramètres : op = instance à initialiser pleinement. * * type = type d'opération booléenne à représenter. * -* first = premier opérande concerné. * -* second = éventuel second opérande impliqué ou NULL. * -* sensitive = détermine la prise en compte de la casse. * +* left = premier opérande concerné. * +* right = éventuel second opérande impliqué ou NULL. * +* sensitive = détermine la prise en compte de la casse. * * * * Description : Met en place une expression d'opération traite une chaîne. * * * @@ -208,19 +208,19 @@ GScanExpression *g_string_operation_new(StringOperationType type, GScanExpressio * * ******************************************************************************/ -bool g_string_operation_create(GStringOperation *op, StringOperationType type, GScanExpression *first, GScanExpression *second, bool sensitive) +bool g_string_operation_create(GStringOperation *op, StringOperationType type, GScanExpression *left, GScanExpression *right, bool sensitive) { bool result; /* Bilan à retourner */ ExprValueType vtype; /* Type de valeur portée */ result = false; - vtype = g_scan_expression_get_value_type(first); + vtype = g_scan_expression_get_value_type(left); if (vtype != EVT_STRING && vtype != EVT_PENDING) goto exit; - vtype = g_scan_expression_get_value_type(second); + vtype = g_scan_expression_get_value_type(right); if (vtype != EVT_STRING && vtype != EVT_REG_EXPR && vtype != EVT_PENDING) goto exit; @@ -245,11 +245,11 @@ bool g_string_operation_create(GStringOperation *op, StringOperationType type, G } - op->first = first; - g_object_ref(G_OBJECT(op->first)); + op->left = left; + g_object_ref(G_OBJECT(op->left)); - op->second = second; - g_object_ref(G_OBJECT(op->second)); + op->right = right; + g_object_ref(G_OBJECT(op->right)); result = true; @@ -268,170 +268,202 @@ bool g_string_operation_create(GStringOperation *op, StringOperationType type, G /****************************************************************************** * * -* Paramètres : op = expression à copier. * +* Paramètres : dest = emplacement d'enregistrement à constituer. [OUT] * +* src = expression source à copier. * * * * Description : Reproduit une expression en place dans une nouvelle instance.* * * -* Retour : Nouvelle instance d'expression. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -static GScanExpression *g_string_operation_duplicate(const GStringOperation *op) +static void g_string_operation_copy(GStringOperation *dest, const GStringOperation *src) { - GScanExpression *result; /* Instance copiée à retourner */ + GScanExpressionClass *class; /* Classe parente à solliciter */ - result = g_string_operation_new(op->type, op->first, op->second, op->case_sensitive); + class = G_SCAN_EXPRESSION_CLASS(g_string_operation_parent_class); - return result; + class->copy(G_SCAN_EXPRESSION(dest), G_SCAN_EXPRESSION(src)); + + dest->type = src->type; + dest->case_sensitive = src->case_sensitive; + + dest->left = g_scan_expression_duplicate(src->left); + dest->right = g_scan_expression_duplicate(src->right); } /****************************************************************************** * * -* Paramètres : op = expression à consulter. * +* Paramètres : expr = expression à consulter. * * ctx = contexte de suivi de l'analyse courante. * -* final = impose une conversion finale de dernier tour. * +* scope = portée courante des variables locales. * +* out = zone d'enregistrement de la réduction opérée. [OUT] * * * * Description : Réduit une expression à une forme plus simple. * * * -* Retour : Réduction correspondante, expression déjà réduite, ou NULL. * +* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. * * * * Remarques : - * * * ******************************************************************************/ -GScanExpression *g_string_operation_reduce(GStringOperation *op, GScanContext *ctx, bool final) +static bool g_string_operation_reduce(GStringOperation *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out) { - GScanExpression *result; /* Instance à renvoyer */ - GScanExpression *new; /* Nouvelle expression obtenue */ - const char *strings[2]; /* Chaînes en jeu */ - bool status; /* Bilan intermédiaire */ - char *found; /* Eventuelle portion trouvée */ - size_t len[2]; /* Tailles max. de comparaison */ - int ret; /* Bilan de comparaison */ + bool result; /* Bilan à retourner */ + GScanExpression *new_left; /* Expression réduite (gauche) */ + GScanExpression *new_right; /* Expression réduite (droite) */ + GLiteralExpression *op_left; /* Opérande gauche final */ + GLiteralExpression *op_right; /* Opérande droite final */ + const sized_string_t *strings[2]; /* Chaînes en jeu */ + const void *found; /* Présence d'une bribe ? */ + bool status; /* Bilan de comparaison #1 */ + size_t offset; /* Point de départ d'analyse */ const regex_t *preg; /* Expression rationnelle */ - - result = NULL; + int ret; /* Bilan de comparaison #2 */ /* Réduction des éléments considérés */ - new = g_scan_expression_reduce(op->first, ctx, final); + new_left = NULL; + new_right = NULL; - if (new != NULL) - { - g_object_unref(G_OBJECT(op->first)); - op->first = new; - } + result = g_scan_expression_reduce(expr->left, ctx, scope, &new_left); + if (!result) goto exit; - new = g_scan_expression_reduce(op->second, ctx, final); - - if (new != NULL) - { - g_object_unref(G_OBJECT(op->second)); - op->second = new; - } + result = g_scan_expression_reduce(expr->right, ctx, scope, &new_right); + if (!result) goto exit; /* Construction d'une réduction locale ? */ - if (!G_IS_LITERAL_EXPRESSION(op->first)) - goto exit; + if (G_IS_LITERAL_EXPRESSION(new_left) && G_IS_LITERAL_EXPRESSION(new_right)) + { + op_left = G_LITERAL_EXPRESSION(new_left); + op_right = G_LITERAL_EXPRESSION(new_right); - if (!G_IS_LITERAL_EXPRESSION(op->second)) - goto exit; + result = g_literal_expression_get_string_value(op_left, &strings[0]); + if (!result) goto exit; - status = g_literal_expression_get_string_value(G_LITERAL_EXPRESSION(op->first), &strings[0]); - if (!status) goto exit; + switch (expr->type) + { + case SOT_CONTAINS: - switch (op->type) - { - case SOT_CONTAINS: + result = g_literal_expression_get_string_value(op_right, &strings[1]); + if (!result) goto exit; - status = g_literal_expression_get_string_value(G_LITERAL_EXPRESSION(op->second), &strings[1]); - if (!status) goto exit; + if (expr->case_sensitive) + found = memmem(strings[0]->data, strings[0]->len, strings[1]->data, strings[1]->len); - if (op->case_sensitive) - found = strstr(strings[0], strings[1]); - else - found = strcasestr(strings[0], strings[1]); + else + found = memcasemem(strings[0]->data, strings[0]->len, strings[1]->data, strings[1]->len); - result = g_literal_expression_new(EVT_BOOLEAN, (bool []) { found != NULL }); - break; + result = g_literal_expression_new(EVT_BOOLEAN, (bool []) { found != NULL }); + break; - case SOT_STARTSWITH: + case SOT_STARTSWITH: - status = g_literal_expression_get_string_value(G_LITERAL_EXPRESSION(op->second), &strings[1]); - if (!status) goto exit; + result = g_literal_expression_get_string_value(op_right, &strings[1]); + if (!result) goto exit; - len[1] = strlen(strings[1]); + if (strings[0]->len < strings[1]->len) + status = false; - if (op->case_sensitive) - ret = strncmp(strings[0], strings[1], len[1]); - else - ret = strncasecmp(strings[0], strings[1], len[1]); + else + { + if (expr->case_sensitive) + ret = memcmp(strings[0]->data, strings[1]->data, strings[1]->len); + else + ret = memcasecmp(strings[0]->data, strings[1]->data, strings[1]->len); - result = g_literal_expression_new(EVT_BOOLEAN, (bool []) { ret == 0 }); - break; + status = (ret == 0); - case SOT_ENDSWITH: + } - len[0] = strlen(strings[0]); + result = g_literal_expression_new(EVT_BOOLEAN, &status); + break; - status = g_literal_expression_get_string_value(G_LITERAL_EXPRESSION(op->second), &strings[1]); - if (!status) goto exit; + case SOT_ENDSWITH: - len[1] = strlen(strings[1]); + result = g_literal_expression_get_string_value(op_right, &strings[1]); + if (!result) goto exit; - if (len[0] < len[1]) - result = g_literal_expression_new(EVT_BOOLEAN, (bool []) { false }); + if (strings[0]->len < strings[1]->len) + status = false; - else - { - if (op->case_sensitive) - ret = strncmp(strings[0] + (len[0] - len[1]), strings[1], len[1]); else - ret = strncasecmp(strings[0] + (len[0] - len[1]), strings[1], len[1]); + { + offset = strings[0]->len - strings[1]->len; - result = g_literal_expression_new(EVT_BOOLEAN, (bool []) { ret == 0 }); + if (expr->case_sensitive) + ret = memcmp(strings[0]->data + offset, strings[1]->data, strings[1]->len); + else + ret = memcasecmp(strings[0]->data + offset, strings[1]->data, strings[1]->len); - } - break; + status = (ret == 0); - case SOT_MATCHES: + } - status = g_literal_expression_get_regex_value(G_LITERAL_EXPRESSION(op->second), &preg); - if (!status) goto exit; + result = g_literal_expression_new(EVT_BOOLEAN, &status); + break; - ret = regexec(preg, strings[0], 0, NULL, 0); + case SOT_MATCHES: - result = g_literal_expression_new(EVT_BOOLEAN, (bool []) { ret != REG_NOMATCH }); - break; + result = g_literal_expression_get_regex_value(op_right, &preg); + if (!result) goto exit; - case SOT_IEQUALS: + ret = regexec(preg, strings[0]->data, 0, NULL, 0); - len[0] = strlen(strings[0]); + *out = g_literal_expression_new(EVT_BOOLEAN, (bool []) { ret != REG_NOMATCH }); + break; - status = g_literal_expression_get_string_value(G_LITERAL_EXPRESSION(op->second), &strings[1]); - if (!status) goto exit; + case SOT_IEQUALS: - len[1] = strlen(strings[1]); + result = g_literal_expression_get_string_value(op_right, &strings[1]); + if (!result) goto exit; - if (len[0] != len[1]) - result = g_literal_expression_new(EVT_BOOLEAN, (bool []) { false }); + if (strings[0]->len != strings[1]->len) + status = false; - else - { - ret = strcasecmp(strings[0], strings[1]); - result = g_literal_expression_new(EVT_BOOLEAN, (bool []) { ret == 0 }); - } - break; + else + { + ret = memcasecmp(strings[0]->data, strings[1]->data, strings[1]->len); + status = (ret == 0); + } + + result = g_literal_expression_new(EVT_BOOLEAN, &status); + break; + + } + + } + + /* Mise à jour de la progression ? */ + + else if ((new_left != NULL && new_left != expr->left) || (new_right != NULL && new_right != expr->right)) + { + if (new_left == NULL) + { + new_left = expr->left; + g_object_ref(G_OBJECT(new_left)); + } + + if (new_right == NULL) + { + new_right = expr->right; + g_object_ref(G_OBJECT(new_right)); + } + + *out = g_string_operation_new(expr->type, new_left, new_right, expr->case_sensitive); } exit: + g_clear_object(&new_left); + g_clear_object(&new_right); + return result; } diff --git a/src/analysis/scan/exprs/str.h b/src/analysis/scan/exprs/strop.h index 195f941..c7c0813 100644 --- a/src/analysis/scan/exprs/str.h +++ b/src/analysis/scan/exprs/strop.h @@ -1,6 +1,6 @@ /* Chrysalide - Outil d'analyse de fichiers binaires - * str.h - prototypes pour la gestion des opérations booléennes + * strop.h - prototypes pour la gestion des opérations booléennes * * Copyright (C) 2022 Cyrille Bagard * @@ -21,8 +21,8 @@ */ -#ifndef _ANALYSIS_SCAN_EXPRS_STR_H -#define _ANALYSIS_SCAN_EXPRS_STR_H +#ifndef _ANALYSIS_SCAN_EXPRS_STROP_H +#define _ANALYSIS_SCAN_EXPRS_STROP_H #include "../expr.h" @@ -64,4 +64,4 @@ GScanExpression *g_string_operation_new(StringOperationType, GScanExpression *, -#endif /* _ANALYSIS_SCAN_EXPRS_STR_H */ +#endif /* _ANALYSIS_SCAN_EXPRS_STROP_H */ |