Skip to content
Permalink
Browse files Browse the repository at this point in the history
parse_tags: don't recurse for nested \t()
This fixes https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=4892
(stack overflow on deeply nested \t()).

This is possible because parentheses do not nest and the first ')'
terminates the whole tag. Thus something like \t(\t(\t(\t(\t() can be
read in a simple loop with no recursion required. Recursion is also
not required if the ')' is missing entirely and the outermost \t(...
never ends.

See #296 for more backstory.
  • Loading branch information
astiob committed Jan 8, 2018
1 parent 691b422 commit 6835731
Show file tree
Hide file tree
Showing 2 changed files with 14 additions and 1 deletion.
3 changes: 3 additions & 0 deletions Changelog
@@ -1,3 +1,6 @@
libass (unreleased)
* Fix stack overflow on deeply nested \t tags

libass (0.14.0)
* Brand new, faster and better outline stroker (replaces FreeType stroker)
* Remove option to use the FreeType rasterizer
Expand Down
12 changes: 11 additions & 1 deletion libass/ass_parse.c
Expand Up @@ -650,7 +650,17 @@ char *parse_tags(ASS_Renderer *render_priv, char *p, char *end, double pwr)
k = pow(((double) (t - t1)) / delta_t, accel);
}
p = args[cnt].start;
p = parse_tags(render_priv, p, args[cnt].end, k); // maybe k*pwr ? no, specs forbid nested \t's
if (args[cnt].end < end) {
p = parse_tags(render_priv, p, args[cnt].end, k);
} else {
assert(q == end);
// No other tags can possibly follow this \t tag,
// so we don't need to restore pwr after parsing \t.
// The recursive call is now essentially a tail call,
// so optimize it away.
pwr = k;
q = p;
}
} else if (complex_tag("clip")) {
if (nargs == 4) {
int x0, y0, x1, y1;
Expand Down

0 comments on commit 6835731

Please sign in to comment.