gstvalue: Do more checks when guessing at flagset strings

If guessing that a string matches a flagset, be more thorough
at checking that the string following a string of hex:hex:
actually looks like a flag set string. Add some unit tests
to catch more cases.

https://bugzilla.gnome.org/show_bug.cgi?id=779755
This commit is contained in:
Jan Schmidt 2017-03-09 12:09:57 +11:00
parent 9b0a6ca7ab
commit d781d09d99
3 changed files with 67 additions and 8 deletions

View file

@ -7054,6 +7054,14 @@ gst_value_serialize_flagset (const GValue * value)
return result;
}
static gboolean
is_valid_flags_string (const gchar * s)
{
/* We're looking to match +this/that+other-thing/not-this-thing type strings */
return g_regex_match_simple ("^([\\+\\/][\\w\\d-]+)+$", s, G_REGEX_CASELESS,
0);
}
static gboolean
gst_value_deserialize_flagset (GValue * dest, const gchar * s)
{
@ -7088,21 +7096,45 @@ gst_value_deserialize_flagset (GValue * dest, const gchar * s)
if (G_UNLIKELY ((mask == 0 && errno == EINVAL) || cur == next))
goto try_as_flags_string;
/* Next char should be NULL terminator, or a ':' */
if (G_UNLIKELY (next[0] != 0 && next[0] != ':'))
goto try_as_flags_string;
/* Next char should be NULL terminator, or a ':'. If ':', we need the flag string after */
if (G_UNLIKELY (next[0] == 0)) {
res = TRUE;
goto done;
}
if (next[0] != ':')
return FALSE;
s = next + 1;
if (g_str_equal (g_type_name (G_VALUE_TYPE (dest)), "GstFlagSet")) {
/* If we're parsing a generic flag set, that can mean we're guessing
* at the type in deserialising a GstStructure so at least check that
* we have a valid-looking string, so we don't cause deserialisation of
* other types of strings like 00:01:00:00 - https://bugzilla.gnome.org/show_bug.cgi?id=779755 */
if (is_valid_flags_string (s)) {
res = TRUE;
goto done;
}
return FALSE;
}
/* Otherwise, we already got a hex string for a valid non-generic flagset type */
res = TRUE;
goto done;
try_as_flags_string:
if (!res) {
{
const gchar *set_class = g_type_name (G_VALUE_TYPE (dest));
GFlagsClass *flags_klass = NULL;
const gchar *end;
if (g_str_equal (set_class, "GstFlagSet"))
goto done; /* There's no hope to parse a generic flag set */
if (g_str_equal (set_class, "GstFlagSet")) {
/* There's no hope to parse the fields of generic flag set if we didn't already
* catch a hex-string above */
return FALSE;
}
/* Flags class is the FlagSet class with 'Set' removed from the end */
end = g_strrstr (set_class, "Set");
@ -7128,9 +7160,9 @@ try_as_flags_string:
}
}
done:
if (res)
gst_value_set_flagset (dest, flags, mask);
done:
return res;
}

View file

@ -984,7 +984,8 @@ GST_START_TEST (test_intersect_flagset)
c2 = gst_caps_from_string (test_string);
g_free (test_string);
fail_unless (gst_caps_is_equal (c1, c2));
fail_unless (gst_caps_is_equal (c1, c2), "Caps %s != %s",
gst_caps_to_string (c1), gst_caps_to_string (c2));
gst_caps_unref (c1);
gst_caps_unref (c2);

View file

@ -159,6 +159,32 @@ GST_START_TEST (test_from_string)
fail_unless_equals_int (g_value_get_boolean (val), TRUE);
gst_structure_free (structure);
/* Tests for flagset deserialisation */
s = "foobar,value=0010:ffff";
structure = gst_structure_from_string (s, NULL);
fail_if (structure == NULL, "Could not get structure from string %s", s);
fail_unless ((val = gst_structure_get_value (structure, "value")) != NULL);
fail_unless (GST_VALUE_HOLDS_FLAG_SET (val));
gst_structure_free (structure);
/* In the presence of the hex values, the strings don't matter as long as they
* have the right form */
s = "foobar,value=0010:ffff:+random+other/not-the-other";
structure = gst_structure_from_string (s, NULL);
fail_if (structure == NULL, "Could not get structure from string %s", s);
fail_unless ((val = gst_structure_get_value (structure, "value")) != NULL);
fail_unless (GST_VALUE_HOLDS_FLAG_SET (val));
gst_structure_free (structure);
/* Test that a timecode string is deserialised as a string, not a flagset:
* https://bugzilla.gnome.org/show_bug.cgi?id=779755 */
s = "foobar,timecode=00:01:00:00";
structure = gst_structure_from_string (s, NULL);
fail_if (structure == NULL, "Could not get structure from string %s", s);
fail_unless ((val = gst_structure_get_value (structure, "timecode")) != NULL);
fail_unless (G_VALUE_HOLDS_STRING (val));
gst_structure_free (structure);
s = "0.10:decoder-video/mpeg, abc=(boolean)false";
ASSERT_CRITICAL (structure = gst_structure_from_string (s, NULL));
fail_unless (structure == NULL, "Could not get structure from string %s", s);