From 69c379990d83d83682b23eac3ddf390c0d85e976 Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Wed, 12 Oct 2016 14:45:23 +0200 Subject: Use pool allocator when parsing CSS. Fixes memory leaks when parsing throws exceptions and saves a lot of tiny mallocs for objects that have common life times. --- source/fitz/pool.c | 8 ++ source/html/css-apply.c | 18 ++--- source/html/css-parse.c | 182 +++++++++++++++++++--------------------------- source/html/html-layout.c | 111 ++++++++++++++++------------ 4 files changed, 153 insertions(+), 166 deletions(-) (limited to 'source') diff --git a/source/fitz/pool.c b/source/fitz/pool.c index e676947f..2591c563 100644 --- a/source/fitz/pool.c +++ b/source/fitz/pool.c @@ -31,6 +31,14 @@ void *fz_pool_alloc(fz_context *ctx, fz_pool *pool, size_t size) return ptr; } +char *fz_pool_strdup(fz_context *ctx, fz_pool *pool, const char *s) +{ + size_t n = strlen(s) + 1; + char *p = fz_pool_alloc(ctx, pool, n); + memcpy(p, s, n); + return p; +} + void fz_drop_pool(fz_context *ctx, fz_pool *pool) { fz_pool_node *node = pool->head; diff --git a/source/html/css-apply.c b/source/html/css-apply.c index d7375752..03e61a87 100644 --- a/source/html/css-apply.c +++ b/source/html/css-apply.c @@ -622,14 +622,14 @@ sort_properties(fz_css_match *match) } void -fz_match_css(fz_context *ctx, fz_css_match *match, fz_css_rule *css, fz_xml *node) +fz_match_css(fz_context *ctx, fz_css_match *match, fz_css *css, fz_xml *node) { fz_css_rule *rule; fz_css_selector *sel; fz_css_property *prop, *head, *tail; const char *s; - for (rule = css; rule; rule = rule->next) + for (rule = css->rule; rule; rule = rule->next) { sel = rule->selector; while (sel) @@ -649,16 +649,14 @@ fz_match_css(fz_context *ctx, fz_css_match *match, fz_css_rule *css, fz_xml *nod { fz_try(ctx) { - head = tail = prop = fz_parse_css_properties(ctx, s); + head = tail = prop = fz_parse_css_properties(ctx, css->pool, s); while (prop) { add_property(match, prop->name, prop->value, INLINE_SPECIFICITY); tail = prop; prop = prop->next; } - if (tail) - tail->next = css->garbage; - css->garbage = head; + /* We can "leak" the property here, since it is freed along with the pool allocator. */ } fz_catch(ctx) { @@ -670,13 +668,13 @@ fz_match_css(fz_context *ctx, fz_css_match *match, fz_css_rule *css, fz_xml *nod } void -fz_match_css_at_page(fz_context *ctx, fz_css_match *match, fz_css_rule *css) +fz_match_css_at_page(fz_context *ctx, fz_css_match *match, fz_css *css) { fz_css_rule *rule; fz_css_selector *sel; fz_css_property *prop; - for (rule = css; rule; rule = rule->next) + for (rule = css->rule; rule; rule = rule->next) { sel = rule->selector; while (sel) @@ -761,12 +759,12 @@ fz_add_css_font_face(fz_context *ctx, fz_html_font_set *set, fz_archive *zip, co } void -fz_add_css_font_faces(fz_context *ctx, fz_html_font_set *set, fz_archive *zip, const char *base_uri, fz_css_rule *css) +fz_add_css_font_faces(fz_context *ctx, fz_html_font_set *set, fz_archive *zip, const char *base_uri, fz_css *css) { fz_css_rule *rule; fz_css_selector *sel; - for (rule = css; rule; rule = rule->next) + for (rule = css->rule; rule; rule = rule->next) { sel = rule->selector; while (sel) diff --git a/source/html/css-parse.c b/source/html/css-parse.c index 7fd8571a..b5d436e8 100644 --- a/source/html/css-parse.c +++ b/source/html/css-parse.c @@ -3,6 +3,7 @@ struct lexbuf { fz_context *ctx; + fz_pool *pool; const unsigned char *s; const char *file; int line; @@ -20,20 +21,45 @@ FZ_NORETURN static void fz_css_error(struct lexbuf *buf, const char *msg) fz_throw(buf->ctx, FZ_ERROR_SYNTAX, "css syntax error: %s (%s:%d)", msg, buf->file, buf->line); } -static fz_css_rule *fz_new_css_rule(fz_context *ctx, fz_css_selector *selector, fz_css_property *declaration) +fz_css *fz_new_css(fz_context *ctx) { - fz_css_rule *rule = fz_malloc_struct(ctx, fz_css_rule); + fz_pool *pool = fz_new_pool(ctx); + fz_css *css; + + fz_try(ctx) + { + css = fz_pool_alloc(ctx, pool, sizeof *css); + css->pool = pool; + css->rule = NULL; + } + fz_catch(ctx) + { + fz_drop_pool(ctx, pool); + fz_rethrow(ctx); + } + + return css; +} + +void fz_drop_css(fz_context *ctx, fz_css *css) +{ + if (css) + fz_drop_pool(ctx, css->pool); +} + +static fz_css_rule *fz_new_css_rule(fz_context *ctx, fz_pool *pool, fz_css_selector *selector, fz_css_property *declaration) +{ + fz_css_rule *rule = fz_pool_alloc(ctx, pool, sizeof *rule); rule->selector = selector; rule->declaration = declaration; - rule->garbage = NULL; rule->next = NULL; return rule; } -static fz_css_selector *fz_new_css_selector(fz_context *ctx, const char *name) +static fz_css_selector *fz_new_css_selector(fz_context *ctx, fz_pool *pool, const char *name) { - fz_css_selector *sel = fz_malloc_struct(ctx, fz_css_selector); - sel->name = name ? fz_strdup(ctx, name) : NULL; + fz_css_selector *sel = fz_pool_alloc(ctx, pool, sizeof *sel); + sel->name = name ? fz_pool_strdup(ctx, pool, name) : NULL; sel->combine = 0; sel->cond = NULL; sel->left = NULL; @@ -42,20 +68,20 @@ static fz_css_selector *fz_new_css_selector(fz_context *ctx, const char *name) return sel; } -static fz_css_condition *fz_new_css_condition(fz_context *ctx, int type, const char *key, const char *val) +static fz_css_condition *fz_new_css_condition(fz_context *ctx, fz_pool *pool, int type, const char *key, const char *val) { - fz_css_condition *cond = fz_malloc_struct(ctx, fz_css_condition); + fz_css_condition *cond = fz_pool_alloc(ctx, pool, sizeof *cond); cond->type = type; - cond->key = key ? fz_strdup(ctx, key) : NULL; - cond->val = val ? fz_strdup(ctx, val) : NULL; + cond->key = key ? fz_pool_strdup(ctx, pool, key) : NULL; + cond->val = val ? fz_pool_strdup(ctx, pool, val) : NULL; cond->next = NULL; return cond; } -static fz_css_property *fz_new_css_property(fz_context *ctx, const char *name, fz_css_value *value, int spec) +static fz_css_property *fz_new_css_property(fz_context *ctx, fz_pool *pool, const char *name, fz_css_value *value, int spec) { - fz_css_property *prop = fz_malloc_struct(ctx, fz_css_property); - prop->name = fz_strdup(ctx, name); + fz_css_property *prop = fz_pool_alloc(ctx, pool, sizeof *prop); + prop->name = fz_pool_strdup(ctx, pool, name); prop->value = value; prop->spec = spec; prop->important = 0; @@ -63,9 +89,9 @@ static fz_css_property *fz_new_css_property(fz_context *ctx, const char *name, f return prop; } -static fz_css_value *fz_new_css_value_x(fz_context *ctx, int type) +static fz_css_value *fz_new_css_value_x(fz_context *ctx, fz_pool *pool, int type) { - fz_css_value *val = fz_malloc_struct(ctx, fz_css_value); + fz_css_value *val = fz_pool_alloc(ctx, pool, sizeof *val); val->type = type; val->data = NULL; val->args = NULL; @@ -73,79 +99,16 @@ static fz_css_value *fz_new_css_value_x(fz_context *ctx, int type) return val; } -static fz_css_value *fz_new_css_value(fz_context *ctx, int type, const char *data) +static fz_css_value *fz_new_css_value(fz_context *ctx, fz_pool *pool, int type, const char *data) { - fz_css_value *val = fz_malloc_struct(ctx, fz_css_value); + fz_css_value *val = fz_pool_alloc(ctx, pool, sizeof *val); val->type = type; - val->data = fz_strdup(ctx, data); + val->data = fz_pool_strdup(ctx, pool, data); val->args = NULL; val->next = NULL; return val; } -static void fz_drop_css_value(fz_context *ctx, fz_css_value *val) -{ - while (val) - { - fz_css_value *next = val->next; - fz_drop_css_value(ctx, val->args); - fz_free(ctx, val->data); - fz_free(ctx, val); - val = next; - } -} - -static void fz_drop_css_condition(fz_context *ctx, fz_css_condition *cond) -{ - while (cond) - { - fz_css_condition *next = cond->next; - fz_free(ctx, cond->key); - fz_free(ctx, cond->val); - fz_free(ctx, cond); - cond = next; - } -} - -static void fz_drop_css_selector(fz_context *ctx, fz_css_selector *sel) -{ - while (sel) - { - fz_css_selector *next = sel->next; - fz_free(ctx, sel->name); - fz_drop_css_condition(ctx, sel->cond); - fz_drop_css_selector(ctx, sel->left); - fz_drop_css_selector(ctx, sel->right); - fz_free(ctx, sel); - sel = next; - } -} - -static void fz_drop_css_property(fz_context *ctx, fz_css_property *prop) -{ - while (prop) - { - fz_css_property *next = prop->next; - fz_free(ctx, prop->name); - fz_drop_css_value(ctx, prop->value); - fz_free(ctx, prop); - prop = next; - } -} - -void fz_drop_css(fz_context *ctx, fz_css_rule *rule) -{ - while (rule) - { - fz_css_rule *next = rule->next; - fz_drop_css_selector(ctx, rule->selector); - fz_drop_css_property(ctx, rule->declaration); - fz_drop_css_property(ctx, rule->garbage); - fz_free(ctx, rule); - rule = next; - } -} - static void css_lex_next(struct lexbuf *buf) { buf->c = *(buf->s++); @@ -153,9 +116,10 @@ static void css_lex_next(struct lexbuf *buf) ++buf->line; } -static void css_lex_init(fz_context *ctx, struct lexbuf *buf, const char *s, const char *file) +static void css_lex_init(fz_context *ctx, struct lexbuf *buf, fz_pool *pool, const char *s, const char *file) { buf->ctx = ctx; + buf->pool = pool; buf->s = (const unsigned char *)s; buf->c = 0; buf->file = file; @@ -517,14 +481,14 @@ static fz_css_value *parse_term(struct lexbuf *buf) fz_css_error(buf, "expected number"); if (sign < 0) { - v = fz_new_css_value_x(buf->ctx, buf->lookahead); - v->data = fz_malloc(buf->ctx, strlen(buf->string) + 2); + v = fz_new_css_value_x(buf->ctx, buf->pool, buf->lookahead); + v->data = fz_pool_alloc(buf->ctx, buf->pool, strlen(buf->string) + 2); v->data[0] = '-'; strcpy(v->data + 1, buf->string); } else { - v = fz_new_css_value(buf->ctx, buf->lookahead, buf->string); + v = fz_new_css_value(buf->ctx, buf->pool, buf->lookahead, buf->string); } next(buf); white(buf); @@ -533,7 +497,7 @@ static fz_css_value *parse_term(struct lexbuf *buf) if (buf->lookahead == CSS_KEYWORD) { - v = fz_new_css_value(buf->ctx, CSS_KEYWORD, buf->string); + v = fz_new_css_value(buf->ctx, buf->pool, CSS_KEYWORD, buf->string); next(buf); if (accept(buf, '(')) { @@ -554,7 +518,7 @@ static fz_css_value *parse_term(struct lexbuf *buf) case CSS_NUMBER: case CSS_LENGTH: case CSS_PERCENT: - v = fz_new_css_value(buf->ctx, buf->lookahead, buf->string); + v = fz_new_css_value(buf->ctx, buf->pool, buf->lookahead, buf->string); next(buf); white(buf); return v; @@ -575,13 +539,13 @@ static fz_css_value *parse_expr(struct lexbuf *buf) if (accept(buf, ',')) { white(buf); - tail = tail->next = fz_new_css_value(buf->ctx, ',', ","); + tail = tail->next = fz_new_css_value(buf->ctx, buf->pool, ',', ","); tail = tail->next = parse_term(buf); } else if (accept(buf, '/')) { white(buf); - tail = tail->next = fz_new_css_value(buf->ctx, '/', "/"); + tail = tail->next = fz_new_css_value(buf->ctx, buf->pool, '/', "/"); tail = tail->next = parse_term(buf); } else @@ -599,7 +563,7 @@ static fz_css_property *parse_declaration(struct lexbuf *buf) if (buf->lookahead != CSS_KEYWORD) fz_css_error(buf, "expected keyword in property"); - p = fz_new_css_property(buf->ctx, buf->string, NULL, 0); + p = fz_new_css_property(buf->ctx, buf->pool, buf->string, NULL, 0); next(buf); white(buf); @@ -652,7 +616,7 @@ static char *parse_attrib_value(struct lexbuf *buf) if (buf->lookahead == CSS_KEYWORD || buf->lookahead == CSS_STRING) { - s = fz_strdup(buf->ctx, buf->string); + s = fz_pool_strdup(buf->ctx, buf->pool, buf->string); next(buf); white(buf); return s; @@ -670,7 +634,7 @@ static fz_css_condition *parse_condition(struct lexbuf *buf) accept(buf, ':'); /* swallow css3 :: syntax and pretend it's a normal pseudo-class */ if (buf->lookahead != CSS_KEYWORD) fz_css_error(buf, "expected keyword after ':'"); - c = fz_new_css_condition(buf->ctx, ':', "pseudo", buf->string); + c = fz_new_css_condition(buf->ctx, buf->pool, ':', "pseudo", buf->string); next(buf); if (accept(buf, '(')) { @@ -686,7 +650,7 @@ static fz_css_condition *parse_condition(struct lexbuf *buf) { if (buf->lookahead != CSS_KEYWORD) fz_css_error(buf, "expected keyword after '.'"); - c = fz_new_css_condition(buf->ctx, '.', "class", buf->string); + c = fz_new_css_condition(buf->ctx, buf->pool, '.', "class", buf->string); next(buf); return c; } @@ -697,7 +661,7 @@ static fz_css_condition *parse_condition(struct lexbuf *buf) if (buf->lookahead != CSS_KEYWORD) fz_css_error(buf, "expected keyword after '['"); - c = fz_new_css_condition(buf->ctx, '[', buf->string, NULL); + c = fz_new_css_condition(buf->ctx, buf->pool, '[', buf->string, NULL); next(buf); white(buf); @@ -727,7 +691,7 @@ static fz_css_condition *parse_condition(struct lexbuf *buf) if (buf->lookahead == CSS_HASH) { - c = fz_new_css_condition(buf->ctx, '#', "id", buf->string); + c = fz_new_css_condition(buf->ctx, buf->pool, '#', "id", buf->string); next(buf); return c; } @@ -753,14 +717,14 @@ static fz_css_selector *parse_simple_selector(struct lexbuf *buf) if (accept(buf, '*')) { - s = fz_new_css_selector(buf->ctx, NULL); + s = fz_new_css_selector(buf->ctx, buf->pool, NULL); if (iscond(buf->lookahead)) s->cond = parse_condition_list(buf); return s; } else if (buf->lookahead == CSS_KEYWORD) { - s = fz_new_css_selector(buf->ctx, buf->string); + s = fz_new_css_selector(buf->ctx, buf->pool, buf->string); next(buf); if (iscond(buf->lookahead)) s->cond = parse_condition_list(buf); @@ -768,7 +732,7 @@ static fz_css_selector *parse_simple_selector(struct lexbuf *buf) } else if (iscond(buf->lookahead)) { - s = fz_new_css_selector(buf->ctx, NULL); + s = fz_new_css_selector(buf->ctx, buf->pool, NULL); s->cond = parse_condition_list(buf); return s; } @@ -781,7 +745,7 @@ static fz_css_selector *parse_combinator(struct lexbuf *buf, int c, fz_css_selec fz_css_selector *sel, *b; white(buf); b = parse_simple_selector(buf); - sel = fz_new_css_selector(buf->ctx, NULL); + sel = fz_new_css_selector(buf->ctx, buf->pool, NULL); sel->combine = c; sel->left = a; sel->right = b; @@ -856,7 +820,7 @@ static fz_css_rule *parse_ruleset(struct lexbuf *buf) return NULL; } - return fz_new_css_rule(buf->ctx, s, p); + return fz_new_css_rule(buf->ctx, buf->pool, s, p); } static fz_css_rule *parse_at_page(struct lexbuf *buf) @@ -875,8 +839,8 @@ static fz_css_rule *parse_at_page(struct lexbuf *buf) expect(buf, '}'); white(buf); - s = fz_new_css_selector(buf->ctx, "@page"); - return fz_new_css_rule(buf->ctx, s, p); + s = fz_new_css_selector(buf->ctx, buf->pool, "@page"); + return fz_new_css_rule(buf->ctx, buf->pool, s, p); } static fz_css_rule *parse_at_font_face(struct lexbuf *buf) @@ -890,8 +854,8 @@ static fz_css_rule *parse_at_font_face(struct lexbuf *buf) expect(buf, '}'); white(buf); - s = fz_new_css_selector(buf->ctx, "@font-face"); - return fz_new_css_rule(buf->ctx, s, p); + s = fz_new_css_selector(buf->ctx, buf->pool, "@font-face"); + return fz_new_css_rule(buf->ctx, buf->pool, s, p); } static void parse_at_rule(struct lexbuf *buf) @@ -979,18 +943,18 @@ static fz_css_rule *parse_stylesheet(struct lexbuf *buf, fz_css_rule *chain) return chain ? chain : tail; } -fz_css_property *fz_parse_css_properties(fz_context *ctx, const char *source) +fz_css_property *fz_parse_css_properties(fz_context *ctx, fz_pool *pool, const char *source) { struct lexbuf buf; - css_lex_init(ctx, &buf, source, ""); + css_lex_init(ctx, &buf, pool, source, ""); next(&buf); return parse_declaration_list(&buf); } -fz_css_rule *fz_parse_css(fz_context *ctx, fz_css_rule *chain, const char *source, const char *file) +void fz_parse_css(fz_context *ctx, fz_css *css, const char *source, const char *file) { struct lexbuf buf; - css_lex_init(ctx, &buf, source, file); + css_lex_init(ctx, &buf, css->pool, source, file); next(&buf); - return parse_stylesheet(&buf, chain); + css->rule = parse_stylesheet(&buf, css->rule); } diff --git a/source/html/html-layout.c b/source/html/html-layout.c index 34d6f8ac..fb039061 100644 --- a/source/html/html-layout.c +++ b/source/html/html-layout.c @@ -112,7 +112,7 @@ struct genstate fz_tree *images; int is_fb2; const char *base_uri; - fz_css_rule *css; + fz_css *css; int at_bol; int emit_white; int last_brk_cls; @@ -498,8 +498,11 @@ static void fz_drop_html_box(fz_context *ctx, fz_html_box *box) void fz_drop_html(fz_context *ctx, fz_html *html) { - fz_drop_html_box(ctx, html->root); - fz_drop_pool(ctx, html->pool); + if (html) + { + fz_drop_html_box(ctx, html->root); + fz_drop_pool(ctx, html->pool); + } } static fz_html_box *new_box(fz_context *ctx, fz_pool *pool, fz_bidi_direction markup_dir) @@ -1907,8 +1910,8 @@ static char *concat_text(fz_context *ctx, fz_xml *root) return s; } -static fz_css_rule * -html_load_css(fz_context *ctx, fz_archive *zip, const char *base_uri, fz_css_rule *css, fz_xml *root) +static void +html_load_css(fz_context *ctx, fz_archive *zip, const char *base_uri, fz_css *css, fz_xml *root) { fz_xml *html, *head, *node; fz_buffer *buf; @@ -1942,7 +1945,7 @@ html_load_css(fz_context *ctx, fz_archive *zip, const char *base_uri, fz_css_rul { buf = fz_read_archive_entry(ctx, zip, path); fz_write_buffer_byte(ctx, buf, 0); - css = fz_parse_css(ctx, css, (char*)buf->data, path); + fz_parse_css(ctx, css, (char*)buf->data, path); } fz_always(ctx) fz_drop_buffer(ctx, buf); @@ -1956,17 +1959,16 @@ html_load_css(fz_context *ctx, fz_archive *zip, const char *base_uri, fz_css_rul { char *s = concat_text(ctx, node); fz_try(ctx) - css = fz_parse_css(ctx, css, s, "