From df2ab607d2e7742edbac0b4b1ea7f0bb4099316c Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Thu, 15 Oct 2009 13:22:41 +0000 Subject: [PATCH] - Fix crasher when parsing multiple XML-ish playlists in Rhythmbox --- reentrant.patch | 626 +++++++++++++++++++++++++++++++++++++++++++ totem-pl-parser.spec | 10 +- 2 files changed, 634 insertions(+), 2 deletions(-) create mode 100644 reentrant.patch diff --git a/reentrant.patch b/reentrant.patch new file mode 100644 index 0000000..8759092 --- /dev/null +++ b/reentrant.patch @@ -0,0 +1,626 @@ +only in patch2: +unchanged: +--- totem-pl-parser-2.28.1.orig/plparse/xmllexer.h ++++ totem-pl-parser-2.28.1/plparse/xmllexer.h +@@ -51,9 +51,26 @@ + #define T_CDATA_STOP 19 /* ]]> */ + + ++/* public structures */ ++struct lexer ++{ ++ const char * lexbuf; ++ int lexbuf_size; ++ int lexbuf_pos; ++ int in_comment; ++ char * lex_malloc; ++ enum { ++ NORMAL, ++ DATA, ++ CDATA, ++ } lex_mode; ++}; ++ ++ + /* public functions */ +-void lexer_init(const char * buf, int size) XINE_PROTECTED; +-int lexer_get_token(char * tok, int tok_size) XINE_PROTECTED; ++struct lexer *lexer_init(const char * buf, int size) XINE_PROTECTED; ++void lexer_finalize(struct lexer * lexer) XINE_PROTECTED; ++int lexer_get_token(struct lexer * lexer, char * tok, int tok_size) XINE_PROTECTED; + char *lexer_decode_entities (const char *tok) XINE_PROTECTED; + + #endif +only in patch2: +unchanged: +--- totem-pl-parser-2.28.1.orig/plparse/xmlparser.c ++++ totem-pl-parser-2.28.1/plparse/xmlparser.c +@@ -51,9 +51,6 @@ + #define DATA_SIZE 64 * 1024 + #define MAX_RECURSION 23 + +-/* private global variables */ +-static int xml_parser_mode; +- + /* private functions */ + + static char * strtoupper(char * str) { +@@ -103,10 +100,17 @@ + free(property); + } + +-void xml_parser_init(const char * buf, int size, int mode) { ++xml_parser_t *xml_parser_init(const char * buf, int size, int mode) { ++ xml_parser_t *xml_parser = malloc(sizeof(xml_parser_t)); ++ xml_parser->lexer = lexer_init(buf, size); ++ xml_parser->mode = mode; ++ return xml_parser; ++} + +- lexer_init(buf, size); +- xml_parser_mode = mode; ++void xml_parser_finalize(xml_parser_t *xml_parser) ++{ ++ lexer_finalize(xml_parser->lexer); ++ free(xml_parser); + } + + static void xml_parser_free_props(xml_property_t *current_property) { +@@ -220,7 +224,7 @@ + + #define Q_STATE(CURRENT,NEW) (STATE_##NEW + state - STATE_##CURRENT) + +-static int xml_parser_get_node_internal (xml_node_t *current_node, char *root_names[], int rec, int flags) ++static int xml_parser_get_node_internal (xml_parser_t *xml_parser, xml_node_t *current_node, char *root_names[], int rec, int flags) + { + char tok[TOKEN_SIZE]; + char property_name[TOKEN_SIZE]; +@@ -239,7 +243,7 @@ + + memset (tok, 0, TOKEN_SIZE); + +- while ((bypass_get_token) || (res = lexer_get_token(tok, TOKEN_SIZE)) != T_ERROR) { ++ while ((bypass_get_token) || (res = lexer_get_token(xml_parser->lexer, tok, TOKEN_SIZE)) != T_ERROR) { + bypass_get_token = 0; + lprintf("info: %d - %d : '%s'\n", state, res, tok); + +@@ -295,7 +299,7 @@ + current_property = NULL; + + /* save node name */ +- if (xml_parser_mode == XML_PARSER_CASE_INSENSITIVE) { ++ if (xml_parser->mode == XML_PARSER_CASE_INSENSITIVE) { + strtoupper(tok); + } + if (state == STATE_Q_NODE) { +@@ -331,7 +335,7 @@ + subtree->props = properties; + lprintf("info: rec %d new subtree %s\n", rec, node_name); + root_names[rec + 1] = node_name; +- parse_res = xml_parser_get_node_internal(subtree, root_names, rec + 1, flags); ++ parse_res = xml_parser_get_node_internal(xml_parser, subtree, root_names, rec + 1, flags); + if (parse_res == -1 || parse_res > 0) { + return parse_res; + } +@@ -374,7 +378,7 @@ + case (T_IDENT): + /* save property name */ + new_prop: +- if (xml_parser_mode == XML_PARSER_CASE_INSENSITIVE) { ++ if (xml_parser->mode == XML_PARSER_CASE_INSENSITIVE) { + strtoupper(tok); + } + strcpy(property_name, tok); +@@ -409,7 +413,7 @@ + switch (res) { + case (T_IDENT): + /* must be equal to root_name */ +- if (xml_parser_mode == XML_PARSER_CASE_INSENSITIVE) { ++ if (xml_parser->mode == XML_PARSER_CASE_INSENSITIVE) { + strtoupper(tok); + } + if (strcmp(tok, root_names[rec]) == 0) { +@@ -621,19 +625,19 @@ + } + } + +-static int xml_parser_get_node (xml_node_t *current_node, int flags) ++static int xml_parser_get_node (xml_parser_t *xml_parser, xml_node_t *current_node, int flags) + { + char *root_names[MAX_RECURSION + 1]; + root_names[0] = ""; +- return xml_parser_get_node_internal (current_node, root_names, 0, flags); ++ return xml_parser_get_node_internal (xml_parser, current_node, root_names, 0, flags); + } + +-int xml_parser_build_tree_with_options(xml_node_t **root_node, int flags) { ++int xml_parser_build_tree_with_options(xml_parser_t *xml_parser, xml_node_t **root_node, int flags) { + xml_node_t *tmp_node, *pri_node, *q_node; + int res; + + tmp_node = new_xml_node(); +- res = xml_parser_get_node(tmp_node, flags); ++ res = xml_parser_get_node(xml_parser, tmp_node, flags); + + /* delete any top-level [CDATA] nodes */; + pri_node = tmp_node->child; +@@ -676,8 +680,8 @@ + return res; + } + +-int xml_parser_build_tree(xml_node_t **root_node) { +- return xml_parser_build_tree_with_options (root_node, 0); ++int xml_parser_build_tree(xml_parser_t *xml_parser, xml_node_t **root_node) { ++ return xml_parser_build_tree_with_options (xml_parser, root_node, 0); + } + + const char *xml_parser_get_property (const xml_node_t *node, const char *name) { +only in patch2: +unchanged: +--- totem-pl-parser-2.28.1.orig/plparse/totem-pl-parser.c ++++ totem-pl-parser-2.28.1/plparse/totem-pl-parser.c +@@ -1676,11 +1676,16 @@ + xml_node_t* doc, *node; + char *encoding, *new_contents; + gsize new_size; ++ xml_parser_t *xml_parser; + + totem_pl_parser_cleanup_xml (contents); +- xml_parser_init (contents, size, XML_PARSER_CASE_INSENSITIVE); +- if (xml_parser_build_tree_with_options (&doc, XML_PARSER_RELAXED | XML_PARSER_MULTI_TEXT) < 0) ++ xml_parser = xml_parser_init (contents, size, XML_PARSER_CASE_INSENSITIVE); ++ if (xml_parser_build_tree_with_options (xml_parser, &doc, XML_PARSER_RELAXED | XML_PARSER_MULTI_TEXT) < 0) { ++ xml_parser_finalize (xml_parser); + return NULL; ++ } ++ ++ xml_parser_finalize (xml_parser); + + encoding = NULL; + for (node = doc; node != NULL; node = node->next) { +@@ -1705,12 +1710,14 @@ + } + g_free (encoding); + +- xml_parser_init (new_contents, new_size, XML_PARSER_CASE_INSENSITIVE); +- if (xml_parser_build_tree_with_options (&doc, XML_PARSER_RELAXED | XML_PARSER_MULTI_TEXT) < 0) { ++ xml_parser = xml_parser_init (new_contents, new_size, XML_PARSER_CASE_INSENSITIVE); ++ if (xml_parser_build_tree_with_options (xml_parser, &doc, XML_PARSER_RELAXED | XML_PARSER_MULTI_TEXT) < 0) { ++ xml_parser_finalize (xml_parser); + g_free (new_contents); + return NULL; + } + ++ xml_parser_finalize (xml_parser); + g_free (new_contents); + + return doc; +only in patch2: +unchanged: +--- totem-pl-parser-2.28.1.orig/plparse/xmlparser.h ++++ totem-pl-parser-2.28.1/plparse/xmlparser.h +@@ -65,10 +65,16 @@ + struct xml_node_s *next; + } xml_node_t; + +-void xml_parser_init(const char * buf, int size, int mode) XINE_PROTECTED; ++typedef struct xml_parser_s { ++ struct lexer *lexer; ++ int mode; ++} xml_parser_t; + +-int xml_parser_build_tree(xml_node_t **root_node) XINE_PROTECTED; +-int xml_parser_build_tree_with_options(xml_node_t **root_node, int flags) XINE_PROTECTED; ++xml_parser_t *xml_parser_init(const char * buf, int size, int mode) XINE_PROTECTED; ++void xml_parser_finalize(xml_parser_t *xml_parser) XINE_PROTECTED; ++ ++int xml_parser_build_tree(xml_parser_t *xml_parser, xml_node_t **root_node) XINE_PROTECTED; ++int xml_parser_build_tree_with_options(xml_parser_t *xml_parser, xml_node_t **root_node, int flags) XINE_PROTECTED; + + void xml_parser_free_tree(xml_node_t *root_node) XINE_PROTECTED; + +only in patch2: +unchanged: +--- totem-pl-parser-2.28.1.orig/plparse/xmllexer.c ++++ totem-pl-parser-2.28.1/plparse/xmllexer.c +@@ -44,16 +44,9 @@ + + /* private constants*/ + +-/* private global variables */ +-static const char * lexbuf; +-static int lexbuf_size = 0; +-static int lexbuf_pos = 0; +-static int in_comment = 0; +-static char *lex_malloc = NULL; +- + enum utf { UTF32BE, UTF32LE, UTF16BE, UTF16LE }; + +-static void lex_convert (const char * buf, int size, enum utf utf) ++static void lex_convert (struct lexer * lexer, const char * buf, int size, enum utf utf) + { + char *utf8 = malloc (size * (utf >= UTF16BE ? 3 : 6) + 1); + char *bp = utf8; +@@ -85,45 +78,44 @@ + } + } + *bp = 0; +- lexbuf_size = bp - utf8; +- lexbuf = lex_malloc = realloc (utf8, lexbuf_size + 1); ++ lexer->lexbuf_size = bp - utf8; ++ lexer->lexbuf = lexer->lex_malloc = realloc (utf8, lexer->lexbuf_size + 1); + } + +-static enum { +- NORMAL, +- DATA, +- CDATA, +-} lex_mode = NORMAL; +- +-void lexer_init(const char * buf, int size) { ++struct lexer *lexer_init(const char * buf, int size) { + static const char boms[] = { 0xFF, 0xFE, 0, 0, 0xFE, 0xFF }, + bom_utf8[] = { 0xEF, 0xBB, 0xBF }; ++ struct lexer * lexer = calloc (1, sizeof (*lexer)); + +- free (lex_malloc); +- lex_malloc = NULL; +- +- lexbuf = buf; +- lexbuf_size = size; ++ lexer->lexbuf = buf; ++ lexer->lexbuf_size = size; + + if (size >= 4 && !memcmp (buf, boms + 2, 4)) +- lex_convert (buf + 4, size - 4, UTF32BE); ++ lex_convert (lexer, buf + 4, size - 4, UTF32BE); + else if (size >= 4 && !memcmp (buf, boms, 4)) +- lex_convert (buf + 4, size - 4, UTF32LE); ++ lex_convert (lexer, buf + 4, size - 4, UTF32LE); + else if (size >= 3 && !memcmp (buf, bom_utf8, 3)) + { +- lexbuf += 3; +- lexbuf_size -= 3; ++ lexer->lexbuf += 3; ++ lexer->lexbuf_size -= 3; + } + else if (size >= 2 && !memcmp (buf, boms + 4, 2)) +- lex_convert (buf + 2, size - 2, UTF16BE); ++ lex_convert (lexer, buf + 2, size - 2, UTF16BE); + else if (size >= 2 && !memcmp (buf, boms, 2)) +- lex_convert (buf + 2, size - 2, UTF16LE); ++ lex_convert (lexer, buf + 2, size - 2, UTF16LE); + +- lexbuf_pos = 0; +- lex_mode = NORMAL; +- in_comment = 0; ++ lexer->lexbuf_pos = 0; ++ lexer->lex_mode = NORMAL; ++ lexer->in_comment = 0; + + lprintf("buffer length %d\n", size); ++ return lexer; ++} ++ ++void lexer_finalize(struct lexer * lexer) ++{ ++ free (lexer->lex_malloc); ++ free (lexer); + } + + typedef enum { +@@ -144,17 +136,17 @@ + STATE_IDENT /* must be last */ + } lexer_state_t; + +-int lexer_get_token(char * tok, int tok_size) { ++int lexer_get_token(struct lexer * lexer, char * tok, int tok_size) { + int tok_pos = 0; + lexer_state_t state = STATE_IDLE; + char c; + + if (tok) { +- while ((tok_pos < tok_size) && (lexbuf_pos < lexbuf_size)) { +- c = lexbuf[lexbuf_pos]; +- lprintf("c=%c, state=%d, lex_mode=%d, in_comment=%d\n", c, state, lex_mode, in_comment); ++ while ((tok_pos < tok_size) && (lexer->lexbuf_pos < lexer->lexbuf_size)) { ++ c = lexer->lexbuf[lexer->lexbuf_pos]; ++ lprintf("c=%c, state=%d, lex_mode=%d, lexer->in_comment=%d\n", c, state, lexer->lex_mode, lexer->in_comment); + +- switch (lex_mode) { ++ switch (lexer->lex_mode) { + case NORMAL: + switch (state) { + /* init state */ +@@ -187,7 +179,7 @@ + break; + + case '/': +- if (!in_comment) ++ if (!lexer->in_comment) + state = STATE_T_M_STOP_2; + tok[tok_pos] = c; + tok_pos++; +@@ -214,7 +206,7 @@ + break; + + case '?': +- if (!in_comment) ++ if (!lexer->in_comment) + state = STATE_T_TI_STOP; + tok[tok_pos] = c; + tok_pos++; +@@ -226,14 +218,14 @@ + tok_pos++; + break; + } +- lexbuf_pos++; ++ lexer->lexbuf_pos++; + break; + + /* end of line */ + case STATE_EOL: + if (c == '\n' || (c == '\r')) { + tok[tok_pos] = c; +- lexbuf_pos++; ++ lexer->lexbuf_pos++; + tok_pos++; + } else { + tok[tok_pos] = '\0'; +@@ -245,7 +237,7 @@ + case STATE_SEPAR: + if (c == ' ' || (c == '\t')) { + tok[tok_pos] = c; +- lexbuf_pos++; ++ lexer->lexbuf_pos++; + tok_pos++; + } else { + tok[tok_pos] = '\0'; +@@ -258,20 +250,20 @@ + switch (c) { + case '/': + tok[tok_pos] = c; +- lexbuf_pos++; ++ lexer->lexbuf_pos++; + tok_pos++; /* FIXME */ + tok[tok_pos] = '\0'; + return T_M_START_2; + break; + case '!': + tok[tok_pos] = c; +- lexbuf_pos++; ++ lexer->lexbuf_pos++; + tok_pos++; + state = STATE_T_COMMENT; + break; + case '?': + tok[tok_pos] = c; +- lexbuf_pos++; ++ lexer->lexbuf_pos++; + tok_pos++; /* FIXME */ + tok[tok_pos] = '\0'; + return T_TI_START; +@@ -285,8 +277,8 @@ + /* T_M_STOP_1 */ + case STATE_T_M_STOP_1: + tok[tok_pos] = '\0'; +- if (!in_comment) +- lex_mode = DATA; ++ if (!lexer->in_comment) ++ lexer->lex_mode = DATA; + return T_M_STOP_1; + break; + +@@ -294,11 +286,11 @@ + case STATE_T_M_STOP_2: + if (c == '>') { + tok[tok_pos] = c; +- lexbuf_pos++; ++ lexer->lexbuf_pos++; + tok_pos++; /* FIXME */ + tok[tok_pos] = '\0'; +- if (!in_comment) +- lex_mode = DATA; ++ if (!lexer->in_comment) ++ lexer->lex_mode = DATA; + return T_M_STOP_2; + } else { + tok[tok_pos] = '\0'; +@@ -315,7 +307,7 @@ + /* T_STRING */ + case STATE_T_STRING_DOUBLE: + tok[tok_pos] = c; +- lexbuf_pos++; ++ lexer->lexbuf_pos++; + if (c == '\"') { /* " */ + tok[tok_pos] = '\0'; /* FIXME */ + return T_STRING; +@@ -327,33 +319,33 @@ + case STATE_T_COMMENT: + switch (c) { + case '-': +- lexbuf_pos++; +- if (lexbuf[lexbuf_pos] == '-') ++ lexer->lexbuf_pos++; ++ if (lexer->lexbuf[lexer->lexbuf_pos] == '-') + { +- lexbuf_pos++; ++ lexer->lexbuf_pos++; + tok[tok_pos++] = '-'; /* FIXME */ + tok[tok_pos++] = '-'; + tok[tok_pos] = '\0'; +- in_comment = 1; ++ lexer->in_comment = 1; + return T_C_START; + } + break; + case 'D': +- lexbuf_pos++; +- if (strncmp(lexbuf + lexbuf_pos, "OCTYPE", 6) == 0) { ++ lexer->lexbuf_pos++; ++ if (strncmp(lexer->lexbuf + lexer->lexbuf_pos, "OCTYPE", 6) == 0) { + strncpy(tok + tok_pos, "DOCTYPE", 7); /* FIXME */ +- lexbuf_pos += 6; ++ lexer->lexbuf_pos += 6; + return T_DOCTYPE_START; + } else { + return T_ERROR; + } + break; + case '[': +- lexbuf_pos++; +- if (strncmp(lexbuf + lexbuf_pos, "CDATA[", 6) == 0) { ++ lexer->lexbuf_pos++; ++ if (strncmp(lexer->lexbuf + lexer->lexbuf_pos, "CDATA[", 6) == 0) { + strncpy (tok + tok_pos, "[CDATA[", 7); /* FIXME */ +- lexbuf_pos += 6; +- lex_mode = CDATA; ++ lexer->lexbuf_pos += 6; ++ lexer->lex_mode = CDATA; + return T_CDATA_START; + } else{ + return T_ERROR; +@@ -369,11 +361,11 @@ + case STATE_T_TI_STOP: + if (c == '>') { + tok[tok_pos] = c; +- lexbuf_pos++; ++ lexer->lexbuf_pos++; + tok_pos++; /* FIXME */ + tok[tok_pos] = '\0'; +- if (!in_comment) +- lex_mode = DATA; ++ if (!lexer->in_comment) ++ lexer->lex_mode = DATA; + return T_TI_STOP; + } else { + tok[tok_pos] = '\0'; +@@ -387,13 +379,13 @@ + case '-': + tok[tok_pos] = c; + tok_pos++; +- lexbuf_pos++; ++ lexer->lexbuf_pos++; + state = STATE_T_C_STOP; + break; + default: + tok[tok_pos] = c; + tok_pos++; +- lexbuf_pos++; ++ lexer->lexbuf_pos++; + state = STATE_IDENT; + } + break; +@@ -404,21 +396,21 @@ + case '>': + tok[tok_pos] = c; + tok_pos++; +- lexbuf_pos++; ++ lexer->lexbuf_pos++; + tok[tok_pos] = '\0'; /* FIX ME */ + if (strlen(tok) != 3) { + tok[tok_pos - 3] = '\0'; +- lexbuf_pos -= 3; ++ lexer->lexbuf_pos -= 3; + return T_IDENT; + } else { +- in_comment = 0; ++ lexer->in_comment = 0; + return T_C_STOP; + } + break; + default: + tok[tok_pos] = c; + tok_pos++; +- lexbuf_pos++; ++ lexer->lexbuf_pos++; + state = STATE_IDENT; + } + break; +@@ -426,7 +418,7 @@ + /* T_STRING (single quotes) */ + case STATE_T_STRING_SINGLE: + tok[tok_pos] = c; +- lexbuf_pos++; ++ lexer->lexbuf_pos++; + if (c == '\'') { /* " */ + tok[tok_pos] = '\0'; /* FIXME */ + return T_STRING; +@@ -453,19 +445,19 @@ + case '?': + tok[tok_pos] = c; + tok_pos++; +- lexbuf_pos++; ++ lexer->lexbuf_pos++; + state = STATE_T_TI_STOP; + break; + case '-': + tok[tok_pos] = c; + tok_pos++; +- lexbuf_pos++; ++ lexer->lexbuf_pos++; + state = STATE_T_DASHDASH; + break; + default: + tok[tok_pos] = c; + tok_pos++; +- lexbuf_pos++; ++ lexer->lexbuf_pos++; + } + break; + default: +@@ -479,12 +471,12 @@ + { + case '<': + tok[tok_pos] = '\0'; +- lex_mode = NORMAL; ++ lexer->lex_mode = NORMAL; + return T_DATA; + default: + tok[tok_pos] = c; + tok_pos++; +- lexbuf_pos++; ++ lexer->lexbuf_pos++; + } + break; + +@@ -492,32 +484,32 @@ + switch (c) + { + case ']': +- if (strncmp(lexbuf + lexbuf_pos, "]]>", 3) == 0) { +- lexbuf_pos += 3; +- lex_mode = DATA; ++ if (strncmp(lexer->lexbuf + lexer->lexbuf_pos, "]]>", 3) == 0) { ++ lexer->lexbuf_pos += 3; ++ lexer->lex_mode = DATA; + return T_CDATA_STOP; + } else { + tok[tok_pos] = c; + tok_pos++; +- lexbuf_pos++; ++ lexer->lexbuf_pos++; + } + break; + default: + tok[tok_pos] = c; + tok_pos++; +- lexbuf_pos++; ++ lexer->lexbuf_pos++; + } + break; + } + } + lprintf ("loop done tok_pos = %d, tok_size=%d, lexbuf_pos=%d, lexbuf_size=%d\n", +- tok_pos, tok_size, lexbuf_pos, lexbuf_size); ++ tok_pos, tok_size, lexer->lexbuf_pos, lexer->lexbuf_size); + + /* pb */ + if (tok_pos >= tok_size) { + lprintf("token buffer is too little\n"); + } else { +- if (lexbuf_pos >= lexbuf_size) { ++ if (lexer->lexbuf_pos >= lexer->lexbuf_size) { + /* Terminate the current token */ + tok[tok_pos] = '\0'; + switch (state) { diff --git a/totem-pl-parser.spec b/totem-pl-parser.spec index 8be5e45..494e45b 100644 --- a/totem-pl-parser.spec +++ b/totem-pl-parser.spec @@ -1,6 +1,6 @@ Name: totem-pl-parser Version: 2.28.1 -Release: 1%{?dist} +Release: 2%{?dist} Summary: Totem Playlist Parser library Group: System Environment/Libraries @@ -16,6 +16,9 @@ BuildRequires: libxml2-devel BuildRequires: gettext BuildRequires: perl(XML::Parser) intltool +# https://bugzilla.gnome.org/show_bug.cgi?id=572705 +Patch0: reentrant.patch + %description A library to parse and save playlists, as used in music and movie players. @@ -34,7 +37,7 @@ developing applications that use %{name}. %prep %setup -q - +%patch0 -p1 -b .reentrant %build %configure --enable-static=no @@ -67,6 +70,9 @@ rm -rf $RPM_BUILD_ROOT %{_datadir}/gtk-doc/html/totem-pl-parser %changelog +* Thu Oct 15 2009 Bastien Nocera 2.28.1-2 +- Fix crasher when parsing multiple XML-ish playlists in Rhythmbox + * Tue Sep 29 2009 Bastien Nocera 2.28.1-1 - Update to 2.28.1