diff options
author | Benjamin Otte <otte@redhat.com> | 2021-12-05 18:05:14 +0100 |
---|---|---|
committer | Benjamin Otte <otte@redhat.com> | 2023-04-15 06:11:54 +0200 |
commit | a7a3ec8a168832500bd0ec0796fbf23b608b2fc7 (patch) | |
tree | ba652ebbe398ee92a3ffc6e9c21cb3c2f0d8e49c | |
parent | 506b009925ce44b7458b0dad5fb34275ee38e7b6 (diff) | |
download | gtk+-a7a3ec8a168832500bd0ec0796fbf23b608b2fc7.tar.gz |
jsonparser: Don't stack overflow
Handle skipping deep nested object/array trees when skipping them
without causing stack overflow.
The code is somewhat brittle, but it seems to work.
-rw-r--r-- | gtk/json/gtkjsonparser.c | 48 | ||||
-rw-r--r-- | gtk/json/gtkjsonparserprivate.h | 1 |
2 files changed, 36 insertions, 13 deletions
diff --git a/gtk/json/gtkjsonparser.c b/gtk/json/gtkjsonparser.c index 7c112eab42..2c1b94de2c 100644 --- a/gtk/json/gtkjsonparser.c +++ b/gtk/json/gtkjsonparser.c @@ -1012,24 +1012,40 @@ gtk_json_parser_free (GtkJsonParser *self) static gboolean gtk_json_parser_skip_block (GtkJsonParser *self) { + gsize depth; + if (self->reader != self->block->value) return TRUE; - if (*self->reader == '{') - { - return gtk_json_parser_start_object (self) && - gtk_json_parser_end (self); - } - else if (*self->reader == '[') - { - return gtk_json_parser_start_array (self) && - gtk_json_parser_end (self); - } - else + depth = gtk_json_parser_get_depth (self); + while (TRUE) { - g_assert_not_reached (); - return FALSE; + if (*self->reader == '{') + { + if (!gtk_json_parser_start_object (self)) + return FALSE; + } + else if (*self->reader == '[') + { + if (!gtk_json_parser_start_array (self)) + return FALSE; + } + + while (self->reader != self->block->value) + { + /* This should never be reentrant to this function or we might + * loop causing stack overflow */ + if (!gtk_json_parser_next (self)) + { + if (!gtk_json_parser_end (self)) + return FALSE; + if (depth >= gtk_json_parser_get_depth (self)) + return TRUE; + } + } } + + return TRUE; } gboolean @@ -1147,6 +1163,12 @@ gtk_json_parser_next (GtkJsonParser *self) return TRUE; } +gsize +gtk_json_parser_get_depth (GtkJsonParser *self) +{ + return self->block - self->blocks; +} + GtkJsonNode gtk_json_parser_get_node (GtkJsonParser *self) { diff --git a/gtk/json/gtkjsonparserprivate.h b/gtk/json/gtkjsonparserprivate.h index fe737fb719..155a5b7603 100644 --- a/gtk/json/gtkjsonparserprivate.h +++ b/gtk/json/gtkjsonparserprivate.h @@ -55,6 +55,7 @@ GtkJsonParser * gtk_json_parser_new_for_string (const char void gtk_json_parser_free (GtkJsonParser *self); gboolean gtk_json_parser_next (GtkJsonParser *self); +gsize gtk_json_parser_get_depth (GtkJsonParser *self); GtkJsonNode gtk_json_parser_get_node (GtkJsonParser *self); char * gtk_json_parser_get_member_name (GtkJsonParser *self); gssize gtk_json_parser_select_member (GtkJsonParser *self, |