François Cartegnie pushed to branch master at VideoLAN / VLC
Commits:
096eecd2 by François Cartegnie at 2026-01-06T16:17:59+01:00
codec: webvtt: fix leak on failed chained selectors
refs #29451
- - - - -
3270c3cf by François Cartegnie at 2026-01-06T16:17:59+01:00
codec: webvtt: fix bogus check
- - - - -
89e0fe52 by François Cartegnie at 2026-01-06T16:17:59+01:00
codec: webvtt: use NULL instead of 0
- - - - -
96f5580b by François Cartegnie at 2026-01-06T16:17:59+01:00
codec: webvtt: check function strings
- - - - -
43801e41 by François Cartegnie at 2026-01-06T16:17:59+01:00
codec: webvtt: fix potential double free
- - - - -
924b4285 by François Cartegnie at 2026-01-06T16:17:59+01:00
codec: webvtt: fix selector leak on error
refs #29451
- - - - -
3c6279e1 by François Cartegnie at 2026-01-06T16:17:59+01:00
codec: webvtt: add YYNOMEM fallback
- - - - -
a1267c86 by François Cartegnie at 2026-01-06T16:17:59+01:00
codec: webvtt: fix useless check before assignment
- - - - -
842511f0 by François Cartegnie at 2026-01-06T16:17:59+01:00
codec: webvtt: fix grammar error handling and cleanups
- - - - -
61ca5329 by François Cartegnie at 2026-01-06T16:17:59+01:00
test: webvtt: split CSS tests
- - - - -
949502c5 by François Cartegnie at 2026-01-06T16:17:59+01:00
test: webvtt: add ::cue pseudo element test
- - - - -
01f7fc0a by François Cartegnie at 2026-01-06T16:17:59+01:00
test: webvtt: add CSS parser error recovery test
- - - - -
ace499ba by François Cartegnie at 2026-01-06T16:17:59+01:00
codec: webvtt: update CSS parser grammar
Fixes unwanted reduction of IDENT as operator
ex: el3{color:red !important fail;}
due to operator grammar and declaration error propagation.
| /* empty */ { $$ = 0; }
and declaration error propagation
property ':' maybe_space error expr prio
Error handling then leaks the mis-reduced IDENT token.
- - - - -
2 changed files:
- modules/codec/webvtt/CSSGrammar.y
- modules/codec/webvtt/css_test.c
Changes:
=====================================
modules/codec/webvtt/CSSGrammar.y
=====================================
@@ -44,6 +44,10 @@
#define YY_TYPEDEF_YY_SCANNER_T
typedef void* yyscan_t;
#endif
+
+#if YYBISON < 30800
+# define YYNOMEM YYABORT
+#endif
%}
%union {
@@ -74,7 +78,7 @@ static void yyerror(yyscan_t scanner, vlc_css_parser_t *p,
const char *msg)
%}
-%expect 10
+%expect 7
%nonassoc LOWEST_PREC
@@ -189,9 +193,7 @@ maybe_sgml:
maybe_charset:
/* empty */
- | charset {
- vlc_css_rules_Delete($1);
- }
+ | charset
;
closing_brace:
@@ -202,13 +204,13 @@ closing_brace:
charset:
CHARSET_SYM maybe_space STRING maybe_space ';' {
free( $3 );
- $$ = 0;
+ $$ = NULL;
}
| CHARSET_SYM error invalid_block {
- $$ = 0;
+ $$ = NULL;
}
| CHARSET_SYM error ';' {
- $$ = 0;
+ $$ = NULL;
}
;
@@ -216,10 +218,10 @@ ignored_charset:
CHARSET_SYM maybe_space STRING maybe_space ';' {
// Ignore any @charset rule not at the beginning of the style sheet.
free( $3 );
- $$ = 0;
+ $$ = NULL;
}
| CHARSET_SYM maybe_space ';' {
- $$ = 0;
+ $$ = NULL;
}
;
@@ -279,19 +281,16 @@ unary_operator:
ruleset:
selector_list '{' maybe_space declaration_list closing_brace {
$$ = vlc_css_rule_New();
- if($$)
- {
- $$->p_selectors = $1;
- $$->p_declarations = $4;
- }
+ if( !$$ )
+ YYNOMEM;
+ $$->p_selectors = $1;
+ $$->p_declarations = $4;
}
;
selector_list:
selector %prec UNIMPORTANT_TOK {
- if ($1) {
- $$ = $1;
- }
+ $$ = $1;
}
| selector_list ',' maybe_space selector %prec UNIMPORTANT_TOK {
if ($1 && $4 )
@@ -328,22 +327,32 @@ selector:
}
| selector_with_trailing_whitespace simple_selector
{
- $$ = $1;
- if ($$ && $2)
+ if( $1 && $2 )
{
- vlc_css_selector_AddSpecifier( $$, $2 );
+ vlc_css_selector_AddSpecifier( $1, $2 );
$2->combinator = RELATION_DESCENDENT;
+ $$ = $1;
+ }
+ else
+ {
+ vlc_css_selectors_Delete( $1 );
+ vlc_css_selectors_Delete( $2 );
+ $$ = NULL;
}
- else $$ = $2;
}
| selector combinator simple_selector {
- $$ = $1;
- if ($$ && $3)
+ if( $1 && $3 )
{
- vlc_css_selector_AddSpecifier( $$, $3 );
+ vlc_css_selector_AddSpecifier( $1, $3 );
$3->combinator = $2;
+ $$ = $1;
+ }
+ else
+ {
+ vlc_css_selectors_Delete( $1 );
+ vlc_css_selectors_Delete( $3 );
+ $$ = NULL;
}
- else $$ = $3;
}
| selector error {
vlc_css_selectors_Delete( $1 );
@@ -353,19 +362,27 @@ selector:
simple_selector:
element_name {
+ if( !$1 )
+ {
+ $$ = NULL;
+ YYERROR;
+ }
$$ = vlc_css_selector_New( SELECTOR_SIMPLE, $1 );
+ if( !$$ )
+ YYNOMEM; // destructors called
free( $1 );
}
| element_name specifier_list {
- $$ = vlc_css_selector_New( SELECTOR_SIMPLE, $1 );
- if( $$ && $2 )
+ if( !$1 )
{
- vlc_css_selector_AddSpecifier( $$, $2 );
- }
- else
- {
- vlc_css_selectors_Delete( $2 );
+ $$ = NULL;
+ YYERROR;
}
+ $$ = vlc_css_selector_New( SELECTOR_SIMPLE, $1 );
+ if( !$$ )
+ YYNOMEM; // destructors called
+ if( $2 )
+ vlc_css_selector_AddSpecifier( $$, $2 );
free( $1 );
}
| specifier_list {
@@ -388,7 +405,8 @@ specifier_list:
$$ = $1;
while( $1->specifiers.p_first )
$1 = $1->specifiers.p_first;
- vlc_css_selector_AddSpecifier( $1, $2 );
+ if( $2 )
+ vlc_css_selector_AddSpecifier( $1, $2 );
}
else $$ = $2;
}
@@ -400,17 +418,28 @@ specifier_list:
specifier:
IDSEL {
+ if( !$1 )
+ {
+ $$ = NULL;
+ YYERROR;
+ }
$$ = vlc_css_selector_New( SPECIFIER_ID, $1 );
+ if( !$$ )
+ YYNOMEM; // $1 destructor called
free( $1 );
}
/* Case when #fffaaa like token is lexed as HEX instead of IDSEL */
| HASH {
- if ($1[0] >= '0' && $1[0] <= '9') {
+ if ( !$1 || ($1[0] >= '0' && $1[0] <= '9') )
+ {
$$ = NULL;
+ YYERROR; // $1 destructor called
} else {
$$ = vlc_css_selector_New( SPECIFIER_ID, $1 );
+ if( !$$ )
+ YYNOMEM; // $1 destructor called
+ free( $1 );
}
- free( $1 );
}
| class
| attrib
@@ -419,7 +448,14 @@ specifier:
class:
'.' IDENT {
+ if( !$2 )
+ {
+ $$ = NULL;
+ YYERROR;
+ }
$$ = vlc_css_selector_New( SPECIFIER_CLASS, $2 );
+ if( !$$ )
+ YYNOMEM; // $2 destructor called
free( $2 );
}
;
@@ -432,15 +468,29 @@ attr_name:
attrib:
'[' maybe_space attr_name ']' {
+ if( !$3 )
+ {
+ $$ = NULL;
+ YYERROR;
+ }
$$ = vlc_css_selector_New( SPECIFIER_ATTRIB, $3 );
free( $3 );
}
| '[' maybe_space attr_name match maybe_space ident_or_string maybe_space
']' {
+ if( !$6 || !$3 )
+ {
+ $$ = NULL;
+ YYERROR;
+ }
$$ = vlc_css_selector_New( SPECIFIER_ATTRIB, $3 );
- if( $$ && $$ )
+ if( !$$ )
+ YYNOMEM;
+ $$->match = $4;
+ $$->p_matchsel = vlc_css_selector_New( SPECIFIER_ID, $6 );
+ if ( !$$->p_matchsel )
{
- $$->match = $4;
- $$->p_matchsel = vlc_css_selector_New( SPECIFIER_ID, $6 );
+ vlc_css_selectors_Delete( $$ );
+ YYNOMEM;
}
free( $3 );
free( $6 );
@@ -475,41 +525,81 @@ ident_or_string:
pseudo:
':' IDENT {
+ if( !$2 )
+ {
+ $$ = NULL;
+ YYERROR;
+ }
$$ = vlc_css_selector_New( SELECTOR_PSEUDOCLASS, $2 );
+ if( !$$ )
+ YYNOMEM;
free( $2 );
}
| ':' ':' IDENT {
+ if( !$3 )
+ {
+ $$ = NULL;
+ YYERROR;
+ }
$$ = vlc_css_selector_New( SELECTOR_PSEUDOELEMENT, $3 );
+ if( !$$ )
+ YYNOMEM;
free( $3 );
}
// used by :nth-*
| ':' FUNCTION maybe_space maybe_unary_operator NUMBER maybe_space ')' {
+ if( !$2 )
+ {
+ $$ = NULL;
+ YYERROR;
+ }
+
if(*$2 != 0)
$2[strlen($2) - 1] = 0;
$$ = vlc_css_selector_New( SELECTOR_PSEUDOCLASS, $2 );
+ if( !$$ )
+ YYNOMEM;
$5.val *= $4;
+
free( $2 );
vlc_css_term_Clean( $5 );
}
// required for WEBVTT weirdos cue::(::past)
| ':' ':' FUNCTION maybe_space selector maybe_space ')' {
+ if( !$3 )
+ {
+ $$ = NULL;
+ YYERROR;
+ }
+
if(*$3 != 0)
$3[strlen($3) - 1] = 0;
$$ = vlc_css_selector_New( SELECTOR_PSEUDOELEMENT, $3 );
- free( $3 );
- if( $$ && $5 )
+ if( !$$ )
+ YYNOMEM;
+
+ if( $5 )
{
vlc_css_selector_AddSpecifier( $$, $5 );
$5->combinator = RELATION_SELF;
}
- else
- vlc_css_selectors_Delete( $5 );
+
+ free( $3 );
}
// used by :nth-*(odd/even) and :lang
| ':' FUNCTION maybe_space IDENT maybe_space ')' {
+ if( !$2 )
+ {
+ $$ = NULL;
+ YYERROR;
+ }
+
if(*$2 != 0)
$2[strlen($2) - 1] = 0;
$$ = vlc_css_selector_New( SELECTOR_PSEUDOCLASS, $2 );
+ if( !$$ )
+ YYNOMEM;
+
free( $2 );
free( $4 );
}
@@ -577,59 +667,44 @@ decl_list:
declaration:
property ':' maybe_space expr prio {
- if( $4 )
+ if( !$1 || !$4 )
{
- $$ = vlc_css_declaration_New( $1 );
- if( $$ )
- $$->expr = $4;
- else
- vlc_css_expression_Delete( $4 );
+ $$ = NULL;
+ YYERROR;
}
- else $$ = NULL;
+ $$ = vlc_css_declaration_New( $1 );
+ if( !$$ )
+ YYNOMEM;
+ $$->expr = $4;
free( $1 );
}
- |
- property error {
+ | property ':' maybe_space expr error {
+ /* e.g. color: red !important fail; or color: red; garbage */
free( $1 );
+ vlc_css_expression_Delete( $4 );
$$ = NULL;
}
- |
- property ':' maybe_space error expr prio {
+ | property ':' maybe_space error {
+ /* color: garbage */
free( $1 );
- vlc_css_expression_Delete( $5 );
- /* The default movable type template has letter-spacing: .none;
Handle this by looking for
- error tokens at the start of an expr, recover the expr and then treat
as an error, cleaning
- up and deleting the shifted expr. */
$$ = NULL;
}
- |
- property ':' maybe_space expr prio error {
+ | property error {
+ /* color garbage */
free( $1 );
- vlc_css_expression_Delete( $4 );
- /* When we encounter something like p {color: red !important fail;} we
should drop the declaration */
$$ = NULL;
}
- |
- IMPORTANT_SYM maybe_space {
- /* Handle this case: div { text-align: center; !important } Just
reduce away the stray !important. */
- $$ = NULL;
- }
- |
- property ':' maybe_space {
+ | property ':' maybe_space {
+ /* color: ; */
free( $1 );
- /* div { font-family: } Just reduce away this property with no value.
*/
$$ = NULL;
}
- |
- property ':' maybe_space error {
+ | property invalid_block {
free( $1 );
- /* if we come across rules with invalid values like this case: p {
weight: *; }, just discard the rule */
$$ = NULL;
}
- |
- property invalid_block {
- /* if we come across: div { color{;color:maroon} }, ignore everything
within curly brackets */
- free( $1 );
+ | IMPORTANT_SYM maybe_space {
+ /* stray !important */
$$ = NULL;
}
;
@@ -649,38 +724,38 @@ expr:
term {
$$ = vlc_css_expression_New( $1 );
if( !$$ )
- vlc_css_term_Clean( $1 );
+ YYNOMEM;
}
- | expr operator term {
+ | expr term {
+ if( !$1 )
+ {
+ $$ = NULL;
+ YYERROR;
+ }
$$ = $1;
- if( !$1 || !vlc_css_expression_AddTerm($1, $2, $3) )
- vlc_css_term_Clean( $3 );
+ if( !vlc_css_expression_AddTerm( $1, ' ', $2 ) )
+ YYNOMEM;
}
- | expr invalid_block_list {
- vlc_css_expression_Delete( $1 );
- $$ = NULL;
- }
- | expr invalid_block_list error {
- vlc_css_expression_Delete( $1 );
- $$ = NULL;
- }
- | expr error {
- vlc_css_expression_Delete( $1 );
- $$ = NULL;
+ | expr operator maybe_space term {
+ if( !$1 )
+ {
+ $$ = NULL;
+ YYERROR;
+ }
+ $$ = $1;
+ if( !vlc_css_expression_AddTerm( $1, '/', $4 ) )
+ YYNOMEM;
}
;
operator:
- '/' maybe_space {
- $$ = '/';
- }
- | ',' maybe_space {
- $$ = ',';
- }
- | /* empty */ {
- $$ = 0;
- }
- ;
+ '/' maybe_space {
+ $$ = '/';
+ }
+ | ',' maybe_space {
+ $$ = ',';
+ }
+ ;
term:
unary_term { $$ = $1; }
@@ -720,22 +795,22 @@ function:
FUNCTION maybe_space expr ')' maybe_space {
$$.type = TYPE_FUNCTION; $$.function = $3;
$$.psz = $1;
- if(*$$.psz != 0)
+ if($1 && *$$.psz != 0)
$$.psz[strlen($$.psz) - 1] = 0;
} |
FUNCTION maybe_space expr TOKEN_EOF {
$$.type = TYPE_FUNCTION; $$.function = $3; $$.psz = $1;
- if(*$$.psz != 0)
+ if($1 && *$$.psz != 0)
$$.psz[strlen($$.psz) - 1] = 0;
} |
FUNCTION maybe_space ')' maybe_space {
$$.type = TYPE_FUNCTION; $$.function = NULL; $$.psz = $1;
- if(*$$.psz != 0)
+ if($1 && *$$.psz != 0)
$$.psz[strlen($$.psz) - 1] = 0;
} |
FUNCTION maybe_space error {
$$.type = TYPE_FUNCTION; $$.function = NULL; $$.psz = $1;
- if(*$$.psz != 0)
+ if($1 && *$$.psz != 0)
$$.psz[strlen($$.psz) - 1] = 0;
}
;
=====================================
modules/codec/webvtt/css_test.c
=====================================
@@ -33,53 +33,25 @@
#define CHECK(test) run = (test); fprintf(stderr, "* Running test %s\n", run);
#define EXPECT(foo) if(!(foo)) BAILOUT(run)
-const char * css =
+#define PARSE_CSS(r) \
+ const char *run = r;\
+ vlc_css_parser_t p;\
+ vlc_css_parser_Init(&p);\
+ bool b = vlc_css_parser_ParseBytes(&p, (const uint8_t *)css, strlen(css));\
+ EXPECT(b);\
+ vlc_css_parser_Debug(&p);\
+ const vlc_css_rule_t *rule = p.rules.p_first
+
+
+static int test_element_selectors(void)
+{
+ const char * css =
"el1 { float0: 1; }\n"
".class1 { hex1: #F0000f; }\n"
"#id1 { text2: \"foo bar\"; }\n"
- ":pseudo { text2: \"foobar\"; }\n"
- "attrib[foo=\"bar\"] { text2: \"foobar\"; }\n"
- "attrib2[foo] { text2: \"foobar\"; }\n"
- "attribincludes[foo~=\"bar\"] { text2: \"foobar\"; }\n"
- "attribdashmatch[foo|=\"bar\"] { text2: \"foobar\"; }\n"
- "attribstarts[foo^=\"bar\"] { text2: \"foobar\"; }\n"
- "attribends[foo$=\"bar\"] { text2: \"foobar\"; }\n"
- "attribcontains[foo*=\"bar\"] { text2: \"foobar\"; }\n"
- "parent1 child1 { float0: 1; }\n"
- "el2,el3 { float0: 1; }\n"
- "el4+el0 { float0: 1; }\n"
- "el5~el0 { float0: 1; }\n"
- "el6>el0 { float0: 1; }\n"
- "values { "
- " neg: -1;"
- " ems: 100em;"
- " exs: 100ex;"
- " pixels: 100px;"
- " points: 100pt; "
- " mm: 100mm;"
- " percent: 100%;"
- " ms: 100ms;"
- " hz: 100Hz;"
- " degrees: 100deg;"
- " dimension: 100 -200em 300px;"
- " string: \"foobar\";"
- " function: foo(1);"
- " identifier: foobar;"
- " hexcolor: #ff00ff;"
- " unicoderange: U+00-FF;"
- " uri: url(http://crap/);"
- "}\n"
-;
+ ;
-int main(void)
-{
- const char *run ="parsing";
- vlc_css_parser_t p;
- vlc_css_parser_Init(&p);
- bool b = vlc_css_parser_ParseBytes(&p, (const uint8_t *)css, strlen(css));
- EXPECT(b);
- vlc_css_parser_Debug(&p);
- const vlc_css_rule_t *rule = p.rules.p_first;
+ PARSE_CSS("test_element_selectors");
CHECK("element selector");
EXPECT(rule && rule->b_valid);
@@ -113,14 +85,29 @@ int main(void)
EXPECT(decl->expr->seq[0].term.type == TYPE_STRING);
EXPECT(!strcmp(decl->expr->seq[0].term.psz,"foo bar"));
- CHECK("pseudoclass selector");
- rule = rule->p_next;
- EXPECT(rule && rule->b_valid);
- EXPECT(!strcmp(rule->p_selectors->psz_name,"pseudo"));
- EXPECT(rule->p_selectors->type == SELECTOR_PSEUDOCLASS);
+ vlc_css_parser_Clean(&p);
+ return 0;
+
+error:
+ vlc_css_parser_Clean(&p);
+ return 1;
+}
+
+static int test_attributes_selectors(void)
+{
+ const char * css =
+ "attrib[foo=\"bar\"] { text2: \"foobar\"; }\n"
+ "attrib2[foo] { text2: \"foobar\"; }\n"
+ "attribincludes[foo~=\"bar\"] { text2: \"foobar\"; }\n"
+ "attribdashmatch[foo|=\"bar\"] { text2: \"foobar\"; }\n"
+ "attribstarts[foo^=\"bar\"] { text2: \"foobar\"; }\n"
+ "attribends[foo$=\"bar\"] { text2: \"foobar\"; }\n"
+ "attribcontains[foo*=\"bar\"] { text2: \"foobar\"; }\n"
+ ;
+
+ PARSE_CSS("test_attributes_selectors");
CHECK("attribute selector equals");
- rule = rule->p_next;
EXPECT(rule && rule->b_valid);
EXPECT(!strcmp(rule->p_selectors->psz_name,"attrib"));
EXPECT(rule->p_selectors->type == SELECTOR_SIMPLE);
@@ -201,9 +188,72 @@ int main(void)
EXPECT(rule->p_selectors->specifiers.p_first->p_matchsel);
EXPECT(!strcmp(rule->p_selectors->specifiers.p_first->p_matchsel->psz_name,
"bar"));
- CHECK("selectors combination parent child");
+ vlc_css_parser_Clean(&p);
+ return 0;
+
+error:
+ vlc_css_parser_Clean(&p);
+ return 1;
+}
+
+static int test_pseudo_selectors(void)
+{
+ const char * css =
+ ":pseudo { text2: \"foobar\"; }\n"
+ "::cue(b) { color: red; }\n" /* WebVTT special */
+ "::cue(v[voice=\"Tom\"]) { color: blue; }\n"
+ ;
+
+ PARSE_CSS("test_pseudo_selectors");
+
+ CHECK("pseudoclass selector");
+ EXPECT(rule && rule->b_valid);
+ EXPECT(!strcmp(rule->p_selectors->psz_name,"pseudo"));
+ EXPECT(rule->p_selectors->type == SELECTOR_PSEUDOCLASS);
+
+ CHECK("pseudoelement ::cue");
+ rule = rule->p_next;
+ EXPECT(rule && rule->b_valid);
+ EXPECT(!strcmp(rule->p_selectors->psz_name,"cue"));
+ EXPECT(rule->p_selectors->type == SELECTOR_PSEUDOELEMENT);
+
+ CHECK("pseudoelement ::cue(v[voice])");
rule = rule->p_next;
EXPECT(rule && rule->b_valid);
+ EXPECT(!strcmp(rule->p_selectors->psz_name,"cue"));
+ EXPECT(rule->p_selectors->type == SELECTOR_PSEUDOELEMENT);
+ EXPECT(rule->p_selectors->specifiers.p_first);
+ EXPECT(rule->p_selectors->specifiers.p_first->type == SELECTOR_SIMPLE);
+ EXPECT(!strcmp(rule->p_selectors->specifiers.p_first->psz_name, "v"));
+ EXPECT(rule->p_selectors->specifiers.p_first->specifiers.p_first);
+ EXPECT(rule->p_selectors->specifiers.p_first->specifiers.p_first->type ==
SPECIFIER_ATTRIB);
+
EXPECT(!strcmp(rule->p_selectors->specifiers.p_first->specifiers.p_first->psz_name,
"voice"));
+
EXPECT(rule->p_selectors->specifiers.p_first->specifiers.p_first->p_matchsel);
+
EXPECT(rule->p_selectors->specifiers.p_first->specifiers.p_first->p_matchsel->match
== MATCH_EQUALS);
+
EXPECT(!strcmp(rule->p_selectors->specifiers.p_first->specifiers.p_first->p_matchsel->psz_name,
"Tom"));
+
+ vlc_css_parser_Clean(&p);
+ return 0;
+
+error:
+ vlc_css_parser_Clean(&p);
+ return 1;
+}
+
+static int test_combinators(void)
+{
+ const char * css =
+ "parent1 child1 { float0: 1; }\n"
+ "el2,el3 { float0: 1; }\n"
+ "el4+el0 { float0: 1; }\n"
+ "el5~el0 { float0: 1; }\n"
+ "el6>el0 { float0: 1; }\n"
+ ;
+
+ PARSE_CSS("test_combinators");
+
+ CHECK("selectors combination parent child");
+ EXPECT(rule && rule->b_valid);
EXPECT(!strcmp(rule->p_selectors->psz_name,"parent1"));
EXPECT(rule->p_selectors->specifiers.p_first);
EXPECT(rule->p_selectors->specifiers.p_first->combinator ==
RELATION_DESCENDENT);
@@ -240,11 +290,44 @@ int main(void)
EXPECT(rule->p_selectors->specifiers.p_first->combinator ==
RELATION_CHILD);
EXPECT(!strcmp(rule->p_selectors->specifiers.p_first->psz_name, "el0"));
+ vlc_css_parser_Clean(&p);
+ return 0;
+
+error:
+ vlc_css_parser_Clean(&p);
+ return 1;
+}
+
+static int test_values(void)
+{
+ const char * css =
+ "values { "
+ " neg: -1;"
+ " ems: 100em;"
+ " exs: 100ex;"
+ " pixels: 100px;"
+ " points: 100pt; "
+ " mm: 100mm;"
+ " percent: 100%;"
+ " ms: 100ms;"
+ " hz: 100Hz;"
+ " degrees: 100deg;"
+ " dimension: 100 -200em 300px;"
+ " string: \"foobar\";"
+ " function: foo(1);"
+ " identifier: foobar;"
+ " hexcolor: #ff00ff;"
+ " unicoderange: U+00-FF;"
+ " uri: url(http://crap/);"
+ "}\n"
+ ;
+
+ PARSE_CSS("test_values");
+
CHECK("values");
- rule = rule->p_next;
EXPECT(rule && rule->b_valid);
EXPECT(!strcmp(rule->p_selectors->psz_name,"values"));
- decl = rule->p_declarations;
+ const vlc_css_declaration_t *decl = rule->p_declarations;
EXPECT(decl && !strcmp(decl->psz_property, "neg"));
EXPECT(decl->expr && decl->expr->i_count);
EXPECT(decl->expr->seq[0].term.type == TYPE_NONE);
@@ -341,3 +424,57 @@ error:
vlc_css_parser_Clean(&p);
return 1;
}
+
+static int test_error_cases(void)
+{
+ const char *css =
+ /* Invalid charset */
+ "@charset \"UTF-8\" extra;\n"
+ "@charset ;\n"
+ /* Invalid block */
+ "el1 { color { ; color: red } }\n"
+ "el2 { color: red; }\n"
+ "el3 { color: red !important fail; }\n"
+ "el4 { font-family: ; }\n"
+ "el5 { weight: *; }\n"
+ "el6 { color: red; !important }\n"
+ /* Invalid selectors */
+ "#123abc { color: red; }\n" /* HASH starting with digit triggers
YYERROR */
+ "el7 + ;\n" /* combinators without right side */
+ "el8 ~ ;\n"
+ "el9 > ;\n"
+ "el10 , ;\n"
+ /* Invalid declarations */
+ "div { ; }\n"
+ "div { color: ; }\n"
+ "div { color: *; }\n"
+ /* Invalid function / expr */
+ "div { foo(): 1; }\n"
+ "div { bar( ; }\n"
+ ;
+
+ PARSE_CSS("test_error_cases");
+
+ /* We just want to make sure the parser
+ * does not crash on error handling and backtracking
+ * and frees memory */
+
+ VLC_UNUSED(rule);
+
+ vlc_css_parser_Clean(&p);
+ return 0;
+
+error:
+ vlc_css_parser_Clean(&p);
+ return 1;
+}
+
+int main(void)
+{
+ return test_element_selectors() ||
+ test_attributes_selectors() ||
+ test_pseudo_selectors() ||
+ test_combinators() ||
+ test_values() ||
+ test_error_cases();
+}
View it on GitLab:
https://code.videolan.org/videolan/vlc/-/compare/15c9a6e8a3a4ec54ec85d75f415fb521f84867a1...ace499bad067b3aed23dd1a02e3b6c61b929526b
--
View it on GitLab:
https://code.videolan.org/videolan/vlc/-/compare/15c9a6e8a3a4ec54ec85d75f415fb521f84867a1...ace499bad067b3aed23dd1a02e3b6c61b929526b
You're receiving this email because of your account on code.videolan.org.
VideoLAN code repository instance_______________________________________________
vlc-commits mailing list
[email protected]
https://mailman.videolan.org/listinfo/vlc-commits