]> granicus.if.org Git - libass/commitdiff
parse_tags: don't recurse for nested \t()
authorOleg Oshmyan <chortos@inbox.lv>
Thu, 4 Jan 2018 00:42:09 +0000 (02:42 +0200)
committerOleg Oshmyan <chortos@inbox.lv>
Mon, 8 Jan 2018 20:20:13 +0000 (22:20 +0200)
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 https://github.com/libass/libass/pull/296 for more backstory.

Changelog
libass/ass_parse.c

index 22b9b9f3e06d157d6695ccddc85b224889098af8..ba8f6f53248794ab6040be70e1e3bd44f76f8afb 100644 (file)
--- a/Changelog
+++ b/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
index b20ef664206b11492996e6afbff14cce747eb432..652ffa972aa79f015540954553c7292d9fc58c51 100644 (file)
@@ -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;