Skip to content

Commit

Permalink
filterx: unwrap references where downcasts are used
Browse files Browse the repository at this point in the history
FilterXRef can mimic the functionality of its referenced value, but only
through virtual methods.

Where (implicit) downcasts are used, it is impossible to be transparent
about references, so these unwrap methods have to be used.
This is far from ideal, but doing downcasts based on is_type() is the
original and real problem here.

Signed-off-by: László Várady <laszlo.varady@anno.io>
  • Loading branch information
MrAnno committed Oct 19, 2024
1 parent e800c40 commit e5f6b7c
Show file tree
Hide file tree
Showing 28 changed files with 192 additions and 94 deletions.
17 changes: 13 additions & 4 deletions lib/filterx/expr-comparison.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include "filterx/object-datetime.h"
#include "filterx/object-message-value.h"
#include "filterx/filterx-object-istype.h"
#include "filterx/filterx-ref.h"
#include "object-primitive.h"
#include "generic-number.h"
#include "parse-number.h"
Expand Down Expand Up @@ -141,6 +142,9 @@ _evaluate_as_num(FilterXObject *lhs, FilterXObject *rhs, gint operator)
static gboolean
_evaluate_type_aware(FilterXObject *lhs, FilterXObject *rhs, gint operator)
{
filterx_assert_not_ref(lhs);
filterx_assert_not_ref(rhs);

if (lhs->type == rhs->type &&
(filterx_object_is_type(lhs, &FILTERX_TYPE_NAME(string)) ||
filterx_object_is_type(lhs, &FILTERX_TYPE_NAME(bytes)) ||
Expand All @@ -165,6 +169,9 @@ _evaluate_type_aware(FilterXObject *lhs, FilterXObject *rhs, gint operator)
static gboolean
_evaluate_type_and_value_based(FilterXObject *lhs, FilterXObject *rhs, gint operator)
{
filterx_assert_not_ref(lhs);
filterx_assert_not_ref(rhs);

if (operator == FCMPX_EQ)
{
if (lhs->type != rhs->type)
Expand Down Expand Up @@ -202,15 +209,17 @@ _eval(FilterXExpr *s)
return NULL;
}

FilterXObject *lhs = filterx_ref_unwrap_ro(lhs_object);
FilterXObject *rhs = filterx_ref_unwrap_ro(rhs_object);
gboolean result = TRUE;
if (compare_mode & FCMPX_TYPE_AWARE)
result = _evaluate_type_aware(lhs_object, rhs_object, operator);
result = _evaluate_type_aware(lhs, rhs, operator);
else if (compare_mode & FCMPX_STRING_BASED)
result = _evaluate_as_string(lhs_object, rhs_object, operator);
result = _evaluate_as_string(lhs, rhs, operator);
else if (compare_mode & FCMPX_NUM_BASED)
result = _evaluate_as_num(lhs_object, rhs_object, operator);
result = _evaluate_as_num(lhs, rhs, operator);
else if (compare_mode & FCMPX_TYPE_AND_VALUE_BASED)
result = _evaluate_type_and_value_based(lhs_object, rhs_object, operator);
result = _evaluate_type_and_value_based(lhs, rhs, operator);
else
g_assert_not_reached();

Expand Down
3 changes: 3 additions & 0 deletions lib/filterx/expr-plus-generator.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "object-string.h"
#include "filterx-eval.h"
#include "filterx/filterx-object-istype.h"
#include "filterx/filterx-ref.h"
#include "scratch-buffers.h"
#include "expr-generator.h"
#include "object-list-interface.h"
Expand All @@ -40,6 +41,8 @@ typedef struct FilterXOperatorPlusGenerator
static gboolean
_generate_obj(FilterXOperatorPlusGenerator *self, FilterXObject *obj, FilterXObject *fillable)
{
fillable = filterx_ref_unwrap_rw(fillable);

if (filterx_object_is_type(fillable, &FILTERX_TYPE_NAME(list)))
return filterx_list_merge(fillable, obj);

Expand Down
3 changes: 3 additions & 0 deletions lib/filterx/expr-regexp.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "filterx/object-dict-interface.h"
#include "filterx/expr-function.h"
#include "filterx/filterx-object-istype.h"
#include "filterx/filterx-ref.h"
#include "compat/pcre.h"
#include "scratch-buffers.h"

Expand Down Expand Up @@ -269,6 +270,8 @@ _store_matches_to_dict(pcre2_code_8 *pattern, const FilterXReMatchState *state,
static gboolean
_store_matches(pcre2_code_8 *pattern, const FilterXReMatchState *state, FilterXObject *fillable)
{
fillable = filterx_ref_unwrap_rw(fillable);

if (filterx_object_is_type(fillable, &FILTERX_TYPE_NAME(list)))
return _store_matches_to_list(pattern, state, fillable);

Expand Down
5 changes: 3 additions & 2 deletions lib/filterx/filterx-metrics-labels.c
Original file line number Diff line number Diff line change
Expand Up @@ -227,14 +227,15 @@ _format_expr_to_cache(FilterXExpr *expr, DynMetricsStore *cache)

gboolean success = FALSE;

if (!filterx_object_is_type(obj, &FILTERX_TYPE_NAME(dict)))
FilterXObject *typed_obj = filterx_ref_unwrap_ro(obj);
if (!filterx_object_is_type(typed_obj, &FILTERX_TYPE_NAME(dict)))
{
filterx_eval_push_error_info("failed to format metrics labels, labels must be a dict", expr,
g_strdup_printf("got %s instead", obj->type->name), TRUE);
goto exit;
}

success = filterx_dict_iter(obj, _format_dict_elem_to_cache, cache);
success = filterx_dict_iter(typed_obj, _format_dict_elem_to_cache, cache);
if (!success)
goto exit;

Expand Down
13 changes: 8 additions & 5 deletions lib/filterx/func-flatten.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "filterx/object-string.h"
#include "filterx/filterx-eval.h"
#include "filterx/filterx-object-istype.h"
#include "filterx/filterx-ref.h"
#include "scratch-buffers.h"

#define FILTERX_FUNC_FLATTEN_USAGE "Usage: flatten(dict, separator=\".\")"
Expand Down Expand Up @@ -71,7 +72,8 @@ _collect_modifications_from_elem(FilterXObject *key, FilterXObject *value, gpoin
GString *key_buffer = ((gpointer *) user_data)[3];
gboolean is_top_level = (gboolean) GPOINTER_TO_INT(((gpointer *) user_data)[4]);

if (filterx_object_is_type(value, &FILTERX_TYPE_NAME(dict)))
FilterXObject *dict = filterx_ref_unwrap_ro(value);
if (filterx_object_is_type(dict, &FILTERX_TYPE_NAME(dict)))
{
if (is_top_level)
*top_level_dict_keys = g_list_prepend(*top_level_dict_keys, filterx_object_ref(key));
Expand All @@ -85,7 +87,7 @@ _collect_modifications_from_elem(FilterXObject *key, FilterXObject *value, gpoin
g_string_append(key_buffer, self->separator);

gpointer inner_user_data[] = { self, flattened_kvs, NULL, key_buffer, GINT_TO_POINTER(FALSE)};
gboolean result = filterx_dict_iter(value, _collect_modifications_from_elem, inner_user_data);
gboolean result = filterx_dict_iter(dict, _collect_modifications_from_elem, inner_user_data);

g_string_truncate(key_buffer, orig_len);
return result;
Expand Down Expand Up @@ -185,12 +187,13 @@ _eval(FilterXExpr *s)
{
FilterXFunctionFlatten *self = (FilterXFunctionFlatten *) s;

FilterXObject *dict = filterx_expr_eval_typed(self->dict_expr);
if (!dict)
FilterXObject *obj = filterx_expr_eval_typed(self->dict_expr);
if (!obj)
return NULL;

gboolean result = FALSE;

FilterXObject *dict = filterx_ref_unwrap_rw(obj);
if (!filterx_object_is_type(dict, &FILTERX_TYPE_NAME(dict)))
{
filterx_eval_push_error_info("object must be a dict", self->dict_expr,
Expand All @@ -201,7 +204,7 @@ _eval(FilterXExpr *s)
result = _flatten(self, dict);

exit:
filterx_object_unref(dict);
filterx_object_unref(obj);
return result ? filterx_boolean_new(TRUE) : NULL;
}

Expand Down
5 changes: 4 additions & 1 deletion lib/filterx/func-istype.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "filterx/filterx-eval.h"
#include "filterx/filterx-globals.h"
#include "filterx/filterx-object-istype.h"
#include "filterx/filterx-ref.h"

#define FILTERX_FUNC_ISTYPE_USAGE "Usage: istype(object, type_str)"

Expand All @@ -51,7 +52,9 @@ _eval(FilterXExpr *s)
return NULL;
}

gboolean result = filterx_object_is_type(object_expr, self->type);
FilterXObject *obj = filterx_ref_unwrap_ro(object_expr);
gboolean result = filterx_object_is_type(obj, self->type);

filterx_object_unref(object_expr);
return filterx_boolean_new(result);
}
Expand Down
6 changes: 4 additions & 2 deletions lib/filterx/func-str.c
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,9 @@ _expr_affix_eval_needle(FilterXExprAffix *self)
g_ptr_array_add(needles, str_value);
return needles;
}
if (filterx_object_is_type(needle_obj, &FILTERX_TYPE_NAME(list)))

FilterXObject *list_needle = filterx_ref_unwrap_ro(needle_obj);
if (filterx_object_is_type(list_needle, &FILTERX_TYPE_NAME(list)))
{
guint64 len;
filterx_object_len(needle_obj, &len);
Expand All @@ -261,7 +263,7 @@ _expr_affix_eval_needle(FilterXExprAffix *self)

for (guint64 i = 0; i < len; i++)
{
FilterXObject *elem = filterx_list_get_subscript(needle_obj, i);
FilterXObject *elem = filterx_list_get_subscript(list_needle, i);

GString *str_value = _obj_format(elem, self->ignore_case);
filterx_object_unref(elem);
Expand Down
23 changes: 16 additions & 7 deletions lib/filterx/func-unset-empties.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include "filterx/expr-literal-generator.h"
#include "filterx/expr-literal.h"
#include "filterx/filterx-object-istype.h"
#include "filterx/filterx-ref.h"

#define FILTERX_FUNC_UNSET_EMPTIES_USAGE "Usage: unset_empties(object, " \
FILTERX_FUNC_UNSET_EMPTIES_ARG_NAME_RECURSIVE"=bool, " \
Expand Down Expand Up @@ -105,6 +106,8 @@ static gboolean _should_unset_string(FilterXFunctionUnsetEmpties *self, FilterXO
static gboolean
_should_unset(FilterXFunctionUnsetEmpties *self, FilterXObject *obj)
{
filterx_assert_not_ref(obj);

if (check_flag(self->flags, FILTERX_FUNC_UNSET_EMPTIES_FLAG_REPLACE_NULL) &&
filterx_object_is_type(obj, &FILTERX_TYPE_NAME(null)))
return TRUE;
Expand All @@ -128,6 +131,7 @@ _add_key_to_unset_list_if_needed(FilterXObject *key, FilterXObject *value, gpoin
FilterXFunctionUnsetEmpties *self = ((gpointer *) user_data)[0];
GList **keys_to_unset = ((gpointer *) user_data)[1];

value = filterx_ref_unwrap_rw(value);
if (check_flag(self->flags, FILTERX_FUNC_UNSET_EMPTIES_FLAG_RECURSIVE))
{
if (filterx_object_is_type(value, &FILTERX_TYPE_NAME(dict)) && !_process_dict(self, value))
Expand Down Expand Up @@ -189,22 +193,23 @@ _process_list(FilterXFunctionUnsetEmpties *self, FilterXObject *obj)
for (gint64 i = ((gint64) len) - 1; i >= 0; i--)
{
FilterXObject *elem = filterx_list_get_subscript(obj, i);
FilterXObject *elem_unwrapped = filterx_ref_unwrap_rw(elem);

if (check_flag(self->flags, FILTERX_FUNC_UNSET_EMPTIES_FLAG_RECURSIVE))
{
if (filterx_object_is_type(elem, &FILTERX_TYPE_NAME(dict)) && !_process_dict(self, elem))
if (filterx_object_is_type(elem_unwrapped, &FILTERX_TYPE_NAME(dict)) && !_process_dict(self, elem_unwrapped))
{
filterx_object_unref(elem);
return FALSE;
}
if (filterx_object_is_type(elem, &FILTERX_TYPE_NAME(list)) && !_process_list(self, elem))
if (filterx_object_is_type(elem_unwrapped, &FILTERX_TYPE_NAME(list)) && !_process_list(self, elem_unwrapped))
{
filterx_object_unref(elem);
return FALSE;
}
}

if (_should_unset(self, elem))
if (_should_unset(self, elem_unwrapped))
{
if (self->replacement)
{
Expand Down Expand Up @@ -248,11 +253,12 @@ _eval(FilterXExpr *s)
return NULL;
}

if (filterx_object_is_type(obj, &FILTERX_TYPE_NAME(dict)))
return _eval_on_dict(self, obj);
FilterXObject *obj_unwrapped = filterx_ref_unwrap_rw(obj);
if (filterx_object_is_type(obj_unwrapped, &FILTERX_TYPE_NAME(dict)))
return _eval_on_dict(self, obj_unwrapped);

if (filterx_object_is_type(obj, &FILTERX_TYPE_NAME(list)))
return _eval_on_list(self, obj);
if (filterx_object_is_type(obj_unwrapped, &FILTERX_TYPE_NAME(list)))
return _eval_on_list(self, obj_unwrapped);

filterx_eval_push_error("Object must be dict or list. " FILTERX_FUNC_UNSET_EMPTIES_USAGE, s, obj);
filterx_object_unref(obj);
Expand Down Expand Up @@ -351,6 +357,9 @@ _handle_target_object(FilterXFunctionUnsetEmpties *self, FilterXObject *target,
{
g_assert(target);
guint64 len;

target = filterx_ref_unwrap_ro(target);

if (filterx_object_is_type(target, &FILTERX_TYPE_NAME(null)))
set_flag(&self->flags, FILTERX_FUNC_UNSET_EMPTIES_FLAG_REPLACE_NULL, TRUE);
else if (filterx_object_is_type(target, &FILTERX_TYPE_NAME(list)))
Expand Down
3 changes: 3 additions & 0 deletions lib/filterx/object-dict-interface.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "filterx/object-string.h"
#include "filterx/object-json.h"
#include "filterx/filterx-object-istype.h"
#include "filterx/filterx-ref.h"
#include "str-utils.h"

gboolean
Expand Down Expand Up @@ -54,6 +55,7 @@ filterx_dict_merge(FilterXObject *s, FilterXObject *other)
{
FilterXDict *self = (FilterXDict *) s;

other = filterx_ref_unwrap_ro(other);
g_assert(filterx_object_is_type(other, &FILTERX_TYPE_NAME(dict)));
return filterx_dict_iter(other, _add_elem_to_dict, self);
}
Expand Down Expand Up @@ -215,6 +217,7 @@ filterx_dict_init_instance(FilterXDict *self, FilterXType *type)
static FilterXObject *
_add(FilterXObject *lhs_object, FilterXObject *rhs_object)
{
rhs_object = filterx_ref_unwrap_ro(rhs_object);
if (!filterx_object_is_type(rhs_object, &FILTERX_TYPE_NAME(dict)))
return NULL;

Expand Down
11 changes: 7 additions & 4 deletions lib/filterx/object-json-array.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include "filterx/expr-function.h"
#include "filterx/filterx-eval.h"
#include "filterx/filterx-object-istype.h"
#include "filterx/filterx-ref.h"

#include "logmsg/type-hinting.h"
#include "str-repr/encode.h"
Expand Down Expand Up @@ -328,7 +329,8 @@ filterx_json_array_new_from_args(FilterXExpr *s, GPtrArray *args)

FilterXObject *arg = (FilterXObject *) g_ptr_array_index(args, 0);

if (filterx_object_is_type(arg, &FILTERX_TYPE_NAME(json_array)))
FilterXObject *json_arr = filterx_ref_unwrap_ro(arg);
if (filterx_object_is_type(json_arr, &FILTERX_TYPE_NAME(json_array)))
return filterx_object_ref(arg);

struct json_object *jso;
Expand All @@ -354,22 +356,23 @@ filterx_json_array_new_empty(void)
const gchar *
filterx_json_array_to_json_literal(FilterXObject *s)
{
FilterXJsonArray *self = (FilterXJsonArray *) s;

s = filterx_ref_unwrap_ro(s);
if (!filterx_object_is_type(s, &FILTERX_TYPE_NAME(json_array)))
return NULL;

FilterXJsonArray *self = (FilterXJsonArray *) s;
return _json_string(self);
}

/* NOTE: Consider using filterx_object_extract_json_array() to also support message_value. */
struct json_object *
filterx_json_array_get_value(FilterXObject *s)
{
s = filterx_ref_unwrap_ro(s);
if (!filterx_object_is_type(s, &FILTERX_TYPE_NAME(json_array)))
return NULL;

FilterXJsonArray *self = (FilterXJsonArray *) s;

return self->jso;
}

Expand Down
8 changes: 5 additions & 3 deletions lib/filterx/object-json-object.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "filterx/filterx-weakrefs.h"
#include "filterx/object-dict-interface.h"
#include "filterx/filterx-object-istype.h"
#include "filterx/filterx-ref.h"
#include "syslog-ng.h"
#include "str-utils.h"
#include "logmsg/type-hinting.h"
Expand Down Expand Up @@ -293,22 +294,23 @@ filterx_json_object_new_empty(void)
const gchar *
filterx_json_object_to_json_literal(FilterXObject *s)
{
FilterXJsonObject *self = (FilterXJsonObject *) s;

s = filterx_ref_unwrap_ro(s);
if (!filterx_object_is_type(s, &FILTERX_TYPE_NAME(json_object)))
return NULL;

FilterXJsonObject *self = (FilterXJsonObject *) s;
return _json_string(self);
}

/* NOTE: Consider using filterx_object_extract_json_object() to also support message_value. */
struct json_object *
filterx_json_object_get_value(FilterXObject *s)
{
s = filterx_ref_unwrap_ro(s);
if (!filterx_object_is_type(s, &FILTERX_TYPE_NAME(json_object)))
return NULL;

FilterXJsonObject *self = (FilterXJsonObject *) s;

return self->jso;
}

Expand Down
Loading

0 comments on commit e5f6b7c

Please sign in to comment.