mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-12-06 00:24:50 +01:00
Merge branch 'backport-4933-variant-parse-string-glib-2-86' into 'glib-2-86'
Backport !4933 “gvariant-parser: Fix potential integer overflow parsing (byte)strings” to glib-2-86 See merge request GNOME/glib!4934
This commit is contained in:
@@ -91,7 +91,9 @@ g_variant_parser_get_error_quark (void)
|
|||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
gint start, end;
|
/* Offsets from the start of the input, in bytes. Can be equal when referring
|
||||||
|
* to a point rather than a range. The invariant `end >= start` always holds. */
|
||||||
|
size_t start, end;
|
||||||
} SourceRef;
|
} SourceRef;
|
||||||
|
|
||||||
G_GNUC_PRINTF(5, 0)
|
G_GNUC_PRINTF(5, 0)
|
||||||
@@ -106,14 +108,16 @@ parser_set_error_va (GError **error,
|
|||||||
GString *msg = g_string_new (NULL);
|
GString *msg = g_string_new (NULL);
|
||||||
|
|
||||||
if (location->start == location->end)
|
if (location->start == location->end)
|
||||||
g_string_append_printf (msg, "%d", location->start);
|
g_string_append_printf (msg, "%" G_GSIZE_FORMAT, location->start);
|
||||||
else
|
else
|
||||||
g_string_append_printf (msg, "%d-%d", location->start, location->end);
|
g_string_append_printf (msg, "%" G_GSIZE_FORMAT "-%" G_GSIZE_FORMAT,
|
||||||
|
location->start, location->end);
|
||||||
|
|
||||||
if (other != NULL)
|
if (other != NULL)
|
||||||
{
|
{
|
||||||
g_assert (other->start != other->end);
|
g_assert (other->start != other->end);
|
||||||
g_string_append_printf (msg, ",%d-%d", other->start, other->end);
|
g_string_append_printf (msg, ",%" G_GSIZE_FORMAT "-%" G_GSIZE_FORMAT,
|
||||||
|
other->start, other->end);
|
||||||
}
|
}
|
||||||
g_string_append_c (msg, ':');
|
g_string_append_c (msg, ':');
|
||||||
|
|
||||||
@@ -140,11 +144,15 @@ parser_set_error (GError **error,
|
|||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
|
/* We should always have the following ordering constraint:
|
||||||
|
* start <= this <= stream <= end
|
||||||
|
* Additionally, unless in an error or EOF state, `this < stream`.
|
||||||
|
*/
|
||||||
const gchar *start;
|
const gchar *start;
|
||||||
const gchar *stream;
|
const gchar *stream;
|
||||||
const gchar *end;
|
const gchar *end;
|
||||||
|
|
||||||
const gchar *this;
|
const gchar *this; /* (nullable) */
|
||||||
} TokenStream;
|
} TokenStream;
|
||||||
|
|
||||||
|
|
||||||
@@ -175,7 +183,7 @@ token_stream_set_error (TokenStream *stream,
|
|||||||
static gboolean
|
static gboolean
|
||||||
token_stream_prepare (TokenStream *stream)
|
token_stream_prepare (TokenStream *stream)
|
||||||
{
|
{
|
||||||
gint brackets = 0;
|
gssize brackets = 0;
|
||||||
const gchar *end;
|
const gchar *end;
|
||||||
|
|
||||||
if (stream->this != NULL)
|
if (stream->this != NULL)
|
||||||
@@ -407,7 +415,7 @@ static void
|
|||||||
pattern_copy (gchar **out,
|
pattern_copy (gchar **out,
|
||||||
const gchar **in)
|
const gchar **in)
|
||||||
{
|
{
|
||||||
gint brackets = 0;
|
gssize brackets = 0;
|
||||||
|
|
||||||
while (**in == 'a' || **in == 'm' || **in == 'M')
|
while (**in == 'a' || **in == 'm' || **in == 'M')
|
||||||
*(*out)++ = *(*in)++;
|
*(*out)++ = *(*in)++;
|
||||||
@@ -609,7 +617,7 @@ ast_resolve (AST *ast,
|
|||||||
{
|
{
|
||||||
GVariant *value;
|
GVariant *value;
|
||||||
gchar *pattern;
|
gchar *pattern;
|
||||||
gint i, j = 0;
|
size_t i, j = 0;
|
||||||
|
|
||||||
pattern = ast_get_pattern (ast, error);
|
pattern = ast_get_pattern (ast, error);
|
||||||
|
|
||||||
@@ -662,9 +670,9 @@ static AST *parse (TokenStream *stream,
|
|||||||
GError **error);
|
GError **error);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ast_array_append (AST ***array,
|
ast_array_append (AST ***array,
|
||||||
gint *n_items,
|
size_t *n_items,
|
||||||
AST *ast)
|
AST *ast)
|
||||||
{
|
{
|
||||||
if ((*n_items & (*n_items - 1)) == 0)
|
if ((*n_items & (*n_items - 1)) == 0)
|
||||||
*array = g_renew (AST *, *array, *n_items ? 2 ** n_items : 1);
|
*array = g_renew (AST *, *array, *n_items ? 2 ** n_items : 1);
|
||||||
@@ -673,10 +681,10 @@ ast_array_append (AST ***array,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ast_array_free (AST **array,
|
ast_array_free (AST **array,
|
||||||
gint n_items)
|
size_t n_items)
|
||||||
{
|
{
|
||||||
gint i;
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < n_items; i++)
|
for (i = 0; i < n_items; i++)
|
||||||
ast_free (array[i]);
|
ast_free (array[i]);
|
||||||
@@ -685,11 +693,11 @@ ast_array_free (AST **array,
|
|||||||
|
|
||||||
static gchar *
|
static gchar *
|
||||||
ast_array_get_pattern (AST **array,
|
ast_array_get_pattern (AST **array,
|
||||||
gint n_items,
|
size_t n_items,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
gchar *pattern;
|
gchar *pattern;
|
||||||
gint i;
|
size_t i;
|
||||||
|
|
||||||
/* Find the pattern which applies to all children in the array, by l-folding a
|
/* Find the pattern which applies to all children in the array, by l-folding a
|
||||||
* coalesce operation.
|
* coalesce operation.
|
||||||
@@ -721,7 +729,7 @@ ast_array_get_pattern (AST **array,
|
|||||||
* pair of values.
|
* pair of values.
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
int j = 0;
|
size_t j = 0;
|
||||||
|
|
||||||
while (TRUE)
|
while (TRUE)
|
||||||
{
|
{
|
||||||
@@ -969,7 +977,7 @@ typedef struct
|
|||||||
AST ast;
|
AST ast;
|
||||||
|
|
||||||
AST **children;
|
AST **children;
|
||||||
gint n_children;
|
size_t n_children;
|
||||||
} Array;
|
} Array;
|
||||||
|
|
||||||
static gchar *
|
static gchar *
|
||||||
@@ -1002,7 +1010,7 @@ array_get_value (AST *ast,
|
|||||||
Array *array = (Array *) ast;
|
Array *array = (Array *) ast;
|
||||||
const GVariantType *childtype;
|
const GVariantType *childtype;
|
||||||
GVariantBuilder builder;
|
GVariantBuilder builder;
|
||||||
gint i;
|
size_t i;
|
||||||
|
|
||||||
if (!g_variant_type_is_array (type))
|
if (!g_variant_type_is_array (type))
|
||||||
return ast_type_error (ast, type, error);
|
return ast_type_error (ast, type, error);
|
||||||
@@ -1088,7 +1096,7 @@ typedef struct
|
|||||||
AST ast;
|
AST ast;
|
||||||
|
|
||||||
AST **children;
|
AST **children;
|
||||||
gint n_children;
|
size_t n_children;
|
||||||
} Tuple;
|
} Tuple;
|
||||||
|
|
||||||
static gchar *
|
static gchar *
|
||||||
@@ -1098,7 +1106,7 @@ tuple_get_pattern (AST *ast,
|
|||||||
Tuple *tuple = (Tuple *) ast;
|
Tuple *tuple = (Tuple *) ast;
|
||||||
gchar *result = NULL;
|
gchar *result = NULL;
|
||||||
gchar **parts;
|
gchar **parts;
|
||||||
gint i;
|
size_t i;
|
||||||
|
|
||||||
parts = g_new (gchar *, tuple->n_children + 4);
|
parts = g_new (gchar *, tuple->n_children + 4);
|
||||||
parts[tuple->n_children + 1] = (gchar *) ")";
|
parts[tuple->n_children + 1] = (gchar *) ")";
|
||||||
@@ -1128,7 +1136,7 @@ tuple_get_value (AST *ast,
|
|||||||
Tuple *tuple = (Tuple *) ast;
|
Tuple *tuple = (Tuple *) ast;
|
||||||
const GVariantType *childtype;
|
const GVariantType *childtype;
|
||||||
GVariantBuilder builder;
|
GVariantBuilder builder;
|
||||||
gint i;
|
size_t i;
|
||||||
|
|
||||||
if (!g_variant_type_is_tuple (type))
|
if (!g_variant_type_is_tuple (type))
|
||||||
return ast_type_error (ast, type, error);
|
return ast_type_error (ast, type, error);
|
||||||
@@ -1320,9 +1328,16 @@ typedef struct
|
|||||||
|
|
||||||
AST **keys;
|
AST **keys;
|
||||||
AST **values;
|
AST **values;
|
||||||
gint n_children;
|
|
||||||
|
/* Iff this is DICTIONARY_N_CHILDREN_FREESTANDING_ENTRY then this struct
|
||||||
|
* represents a single freestanding dict entry (`{1, "one"}`) rather than a
|
||||||
|
* full dict. In the freestanding case, @keys and @values have exactly one
|
||||||
|
* member each. */
|
||||||
|
size_t n_children;
|
||||||
} Dictionary;
|
} Dictionary;
|
||||||
|
|
||||||
|
#define DICTIONARY_N_CHILDREN_FREESTANDING_ENTRY ((size_t) -1)
|
||||||
|
|
||||||
static gchar *
|
static gchar *
|
||||||
dictionary_get_pattern (AST *ast,
|
dictionary_get_pattern (AST *ast,
|
||||||
GError **error)
|
GError **error)
|
||||||
@@ -1337,7 +1352,7 @@ dictionary_get_pattern (AST *ast,
|
|||||||
return g_strdup ("Ma{**}");
|
return g_strdup ("Ma{**}");
|
||||||
|
|
||||||
key_pattern = ast_array_get_pattern (dict->keys,
|
key_pattern = ast_array_get_pattern (dict->keys,
|
||||||
abs (dict->n_children),
|
(dict->n_children == DICTIONARY_N_CHILDREN_FREESTANDING_ENTRY) ? 1 : dict->n_children,
|
||||||
error);
|
error);
|
||||||
|
|
||||||
if (key_pattern == NULL)
|
if (key_pattern == NULL)
|
||||||
@@ -1368,7 +1383,7 @@ dictionary_get_pattern (AST *ast,
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
result = g_strdup_printf ("M%s{%c%s}",
|
result = g_strdup_printf ("M%s{%c%s}",
|
||||||
dict->n_children > 0 ? "a" : "",
|
(dict->n_children > 0 && dict->n_children != DICTIONARY_N_CHILDREN_FREESTANDING_ENTRY) ? "a" : "",
|
||||||
key_char, value_pattern);
|
key_char, value_pattern);
|
||||||
g_free (value_pattern);
|
g_free (value_pattern);
|
||||||
|
|
||||||
@@ -1382,7 +1397,7 @@ dictionary_get_value (AST *ast,
|
|||||||
{
|
{
|
||||||
Dictionary *dict = (Dictionary *) ast;
|
Dictionary *dict = (Dictionary *) ast;
|
||||||
|
|
||||||
if (dict->n_children == -1)
|
if (dict->n_children == DICTIONARY_N_CHILDREN_FREESTANDING_ENTRY)
|
||||||
{
|
{
|
||||||
const GVariantType *subtype;
|
const GVariantType *subtype;
|
||||||
GVariantBuilder builder;
|
GVariantBuilder builder;
|
||||||
@@ -1415,7 +1430,7 @@ dictionary_get_value (AST *ast,
|
|||||||
{
|
{
|
||||||
const GVariantType *entry, *key, *val;
|
const GVariantType *entry, *key, *val;
|
||||||
GVariantBuilder builder;
|
GVariantBuilder builder;
|
||||||
gint i;
|
size_t i;
|
||||||
|
|
||||||
if (!g_variant_type_is_subtype_of (type, G_VARIANT_TYPE_DICTIONARY))
|
if (!g_variant_type_is_subtype_of (type, G_VARIANT_TYPE_DICTIONARY))
|
||||||
return ast_type_error (ast, type, error);
|
return ast_type_error (ast, type, error);
|
||||||
@@ -1456,12 +1471,12 @@ static void
|
|||||||
dictionary_free (AST *ast)
|
dictionary_free (AST *ast)
|
||||||
{
|
{
|
||||||
Dictionary *dict = (Dictionary *) ast;
|
Dictionary *dict = (Dictionary *) ast;
|
||||||
gint n_children;
|
size_t n_children;
|
||||||
|
|
||||||
if (dict->n_children > -1)
|
if (dict->n_children == DICTIONARY_N_CHILDREN_FREESTANDING_ENTRY)
|
||||||
n_children = dict->n_children;
|
|
||||||
else
|
|
||||||
n_children = 1;
|
n_children = 1;
|
||||||
|
else
|
||||||
|
n_children = dict->n_children;
|
||||||
|
|
||||||
ast_array_free (dict->keys, n_children);
|
ast_array_free (dict->keys, n_children);
|
||||||
ast_array_free (dict->values, n_children);
|
ast_array_free (dict->values, n_children);
|
||||||
@@ -1479,7 +1494,7 @@ dictionary_parse (TokenStream *stream,
|
|||||||
maybe_wrapper, dictionary_get_value,
|
maybe_wrapper, dictionary_get_value,
|
||||||
dictionary_free
|
dictionary_free
|
||||||
};
|
};
|
||||||
gint n_keys, n_values;
|
size_t n_keys, n_values;
|
||||||
gboolean only_one;
|
gboolean only_one;
|
||||||
Dictionary *dict;
|
Dictionary *dict;
|
||||||
AST *first;
|
AST *first;
|
||||||
@@ -1522,7 +1537,7 @@ dictionary_parse (TokenStream *stream,
|
|||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
g_assert (n_keys == 1 && n_values == 1);
|
g_assert (n_keys == 1 && n_values == 1);
|
||||||
dict->n_children = -1;
|
dict->n_children = DICTIONARY_N_CHILDREN_FREESTANDING_ENTRY;
|
||||||
|
|
||||||
return (AST *) dict;
|
return (AST *) dict;
|
||||||
}
|
}
|
||||||
@@ -1555,6 +1570,7 @@ dictionary_parse (TokenStream *stream,
|
|||||||
}
|
}
|
||||||
|
|
||||||
g_assert (n_keys == n_values);
|
g_assert (n_keys == n_values);
|
||||||
|
g_assert (n_keys != DICTIONARY_N_CHILDREN_FREESTANDING_ENTRY);
|
||||||
dict->n_children = n_keys;
|
dict->n_children = n_keys;
|
||||||
|
|
||||||
return (AST *) dict;
|
return (AST *) dict;
|
||||||
@@ -1637,9 +1653,9 @@ string_free (AST *ast)
|
|||||||
*/
|
*/
|
||||||
static gboolean
|
static gboolean
|
||||||
unicode_unescape (const gchar *src,
|
unicode_unescape (const gchar *src,
|
||||||
gint *src_ofs,
|
size_t *src_ofs,
|
||||||
gchar *dest,
|
gchar *dest,
|
||||||
gint *dest_ofs,
|
size_t *dest_ofs,
|
||||||
gsize length,
|
gsize length,
|
||||||
SourceRef *ref,
|
SourceRef *ref,
|
||||||
GError **error)
|
GError **error)
|
||||||
@@ -1700,7 +1716,7 @@ string_parse (TokenStream *stream,
|
|||||||
gsize length;
|
gsize length;
|
||||||
gchar quote;
|
gchar quote;
|
||||||
gchar *str;
|
gchar *str;
|
||||||
gint i, j;
|
size_t i, j;
|
||||||
|
|
||||||
token_stream_start_ref (stream, &ref);
|
token_stream_start_ref (stream, &ref);
|
||||||
token = token_stream_get (stream);
|
token = token_stream_get (stream);
|
||||||
@@ -1833,7 +1849,7 @@ bytestring_parse (TokenStream *stream,
|
|||||||
gsize length;
|
gsize length;
|
||||||
gchar quote;
|
gchar quote;
|
||||||
gchar *str;
|
gchar *str;
|
||||||
gint i, j;
|
size_t i, j;
|
||||||
|
|
||||||
token_stream_start_ref (stream, &ref);
|
token_stream_start_ref (stream, &ref);
|
||||||
token = token_stream_get (stream);
|
token = token_stream_get (stream);
|
||||||
@@ -2757,7 +2773,7 @@ g_variant_builder_add_parsed (GVariantBuilder *builder,
|
|||||||
static gboolean
|
static gboolean
|
||||||
parse_num (const gchar *num,
|
parse_num (const gchar *num,
|
||||||
const gchar *limit,
|
const gchar *limit,
|
||||||
guint *result)
|
size_t *result)
|
||||||
{
|
{
|
||||||
gchar *endptr;
|
gchar *endptr;
|
||||||
gint64 bignum;
|
gint64 bignum;
|
||||||
@@ -2767,10 +2783,12 @@ parse_num (const gchar *num,
|
|||||||
if (endptr != limit)
|
if (endptr != limit)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
|
/* The upper bound here is more restrictive than it technically needs to be,
|
||||||
|
* but should be enough for any practical situation: */
|
||||||
if (bignum < 0 || bignum > G_MAXINT)
|
if (bignum < 0 || bignum > G_MAXINT)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
*result = (guint) bignum;
|
*result = (size_t) bignum;
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
@@ -2781,7 +2799,7 @@ add_last_line (GString *err,
|
|||||||
{
|
{
|
||||||
const gchar *last_nl;
|
const gchar *last_nl;
|
||||||
gchar *chomped;
|
gchar *chomped;
|
||||||
gint i;
|
size_t i;
|
||||||
|
|
||||||
/* This is an error at the end of input. If we have a file
|
/* This is an error at the end of input. If we have a file
|
||||||
* with newlines, that's probably the empty string after the
|
* with newlines, that's probably the empty string after the
|
||||||
@@ -2926,7 +2944,7 @@ g_variant_parse_error_print_context (GError *error,
|
|||||||
|
|
||||||
if (dash == NULL || colon < dash)
|
if (dash == NULL || colon < dash)
|
||||||
{
|
{
|
||||||
guint point;
|
size_t point;
|
||||||
|
|
||||||
/* we have a single point */
|
/* we have a single point */
|
||||||
if (!parse_num (error->message, colon, &point))
|
if (!parse_num (error->message, colon, &point))
|
||||||
@@ -2944,7 +2962,7 @@ g_variant_parse_error_print_context (GError *error,
|
|||||||
/* We have one or two ranges... */
|
/* We have one or two ranges... */
|
||||||
if (comma && comma < colon)
|
if (comma && comma < colon)
|
||||||
{
|
{
|
||||||
guint start1, end1, start2, end2;
|
size_t start1, end1, start2, end2;
|
||||||
const gchar *dash2;
|
const gchar *dash2;
|
||||||
|
|
||||||
/* Two ranges */
|
/* Two ranges */
|
||||||
@@ -2960,7 +2978,7 @@ g_variant_parse_error_print_context (GError *error,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
guint start, end;
|
size_t start, end;
|
||||||
|
|
||||||
/* One range */
|
/* One range */
|
||||||
if (!parse_num (error->message, dash, &start) || !parse_num (dash + 1, colon, &end))
|
if (!parse_num (error->message, dash, &start) || !parse_num (dash + 1, colon, &end))
|
||||||
|
|||||||
Reference in New Issue
Block a user