diff --git a/expat/tests/handlers.c b/expat/tests/handlers.c index 0211985f..9199dd5f 100644 --- a/expat/tests/handlers.c +++ b/expat/tests/handlers.c @@ -1842,6 +1842,15 @@ element_decl_suspender(void *userData, const XML_Char *name, XML_FreeContentModel(g_parser, model); } +void XMLCALL +suspend_after_element_declaration(void *userData, const XML_Char *name, + XML_Content *model) { + UNUSED_P(name); + XML_Parser parser = (XML_Parser)userData; + assert_true(XML_StopParser(parser, /*resumable*/ XML_TRUE) == XML_STATUS_OK); + XML_FreeContentModel(parser, model); +} + void XMLCALL accumulate_pi_characters(void *userData, const XML_Char *target, const XML_Char *data) { diff --git a/expat/tests/handlers.h b/expat/tests/handlers.h index 8850bb94..16ab3502 100644 --- a/expat/tests/handlers.h +++ b/expat/tests/handlers.h @@ -557,6 +557,10 @@ extern void XMLCALL suspending_comment_handler(void *userData, extern void XMLCALL element_decl_suspender(void *userData, const XML_Char *name, XML_Content *model); +extern void XMLCALL suspend_after_element_declaration(void *userData, + const XML_Char *name, + XML_Content *model); + extern void XMLCALL accumulate_pi_characters(void *userData, const XML_Char *target, const XML_Char *data); diff --git a/expat/tests/misc_tests.c b/expat/tests/misc_tests.c index 9afe0922..9193aa71 100644 --- a/expat/tests/misc_tests.c +++ b/expat/tests/misc_tests.c @@ -328,64 +328,119 @@ START_TEST(test_misc_stop_during_end_handler_issue_240_2) { END_TEST START_TEST(test_misc_deny_internal_entity_closing_doctype_issue_317) { - const char *const inputOne = "'>\n" - "\n" - "%e;"; + const char *const inputOne + = "'>\n" + "%element_d;\n" + "'>\n" + "\n" + "%e;"; const char *const inputTwo = "'>\n" + "%element_d;\n" "'>\n" "\n" "%e2;"; - const char *const inputThree = "\n" - "\n" - "%e;/>"; - const char *const inputIssue317 = "\n" - "Hell'>\n" - "%foo;\n" - "]>\n" - "Hello, world"; + const char *const inputThree + = "'>\n" + "%element_d;\n" + "\n" + "\n" + "%e;/>"; + const char *const inputIssue317 + = "'>\n" + "%element_doc;\n" + "\n" + "Hell'>\n" + "%foo;\n" + "]>\n" + "Hello, world"; const char *const inputs[] = {inputOne, inputTwo, inputThree, inputIssue317}; + const XML_Bool suspendOrNot[] = {XML_FALSE, XML_TRUE}; size_t inputIndex = 0; for (; inputIndex < sizeof(inputs) / sizeof(inputs[0]); inputIndex++) { - set_subtest("%s", inputs[inputIndex]); - XML_Parser parser; - enum XML_Status parseResult; - int setParamEntityResult; - XML_Size lineNumber; - XML_Size columnNumber; - const char *const input = inputs[inputIndex]; + for (size_t suspendOrNotIndex = 0; + suspendOrNotIndex < sizeof(suspendOrNot) / sizeof(suspendOrNot[0]); + suspendOrNotIndex++) { + const char *const input = inputs[inputIndex]; + const XML_Bool suspend = suspendOrNot[suspendOrNotIndex]; + if (suspend && (g_chunkSize > 0)) { + // We cannot use _XML_Parse_SINGLE_BYTES below due to suspension, and + // so chunk sizes >0 would only repeat the very same test + // due to use of plain XML_Parse; we are saving upon that runtime: + return; + } - parser = XML_ParserCreate(NULL); - setParamEntityResult - = XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS); - if (setParamEntityResult != 1) - fail("Failed to set XML_PARAM_ENTITY_PARSING_ALWAYS."); + set_subtest("[input=%d suspend=%s] %s", (int)inputIndex, + suspend ? "true" : "false", input); + XML_Parser parser; + enum XML_Status parseResult; + int setParamEntityResult; + XML_Size lineNumber; + XML_Size columnNumber; + + parser = XML_ParserCreate(NULL); + setParamEntityResult + = XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS); + if (setParamEntityResult != 1) + fail("Failed to set XML_PARAM_ENTITY_PARSING_ALWAYS."); + + if (suspend) { + XML_SetUserData(parser, parser); + XML_SetElementDeclHandler(parser, suspend_after_element_declaration); + } + + if (suspend) { + // can't use SINGLE_BYTES here, because it'll return early on + // suspension, and we won't know exactly how much input we actually + // managed to give Expat. + parseResult = XML_Parse(parser, input, (int)strlen(input), 0); + + while (parseResult == XML_STATUS_SUSPENDED) { + parseResult = XML_ResumeParser(parser); + } + + if (parseResult != XML_STATUS_ERROR) { + // can't use SINGLE_BYTES here, because it'll return early on + // suspension, and we won't know exactly how much input we actually + // managed to give Expat. + parseResult = XML_Parse(parser, "", 0, 1); + } + + while (parseResult == XML_STATUS_SUSPENDED) { + parseResult = XML_ResumeParser(parser); + } + } else { + parseResult + = _XML_Parse_SINGLE_BYTES(parser, input, (int)strlen(input), 0); + + if (parseResult != XML_STATUS_ERROR) { + parseResult = _XML_Parse_SINGLE_BYTES(parser, "", 0, 1); + } + } - parseResult = _XML_Parse_SINGLE_BYTES(parser, input, (int)strlen(input), 0); - if (parseResult != XML_STATUS_ERROR) { - parseResult = _XML_Parse_SINGLE_BYTES(parser, "", 0, 1); if (parseResult != XML_STATUS_ERROR) { fail("Parsing was expected to fail but succeeded."); } + + if (XML_GetErrorCode(parser) != XML_ERROR_INVALID_TOKEN) + fail("Error code does not match XML_ERROR_INVALID_TOKEN"); + + lineNumber = XML_GetCurrentLineNumber(parser); + if (lineNumber != 6) + fail("XML_GetCurrentLineNumber does not work as expected."); + + columnNumber = XML_GetCurrentColumnNumber(parser); + if (columnNumber != 0) + fail("XML_GetCurrentColumnNumber does not work as expected."); + + XML_ParserFree(parser); } - - if (XML_GetErrorCode(parser) != XML_ERROR_INVALID_TOKEN) - fail("Error code does not match XML_ERROR_INVALID_TOKEN"); - - lineNumber = XML_GetCurrentLineNumber(parser); - if (lineNumber != 4) - fail("XML_GetCurrentLineNumber does not work as expected."); - - columnNumber = XML_GetCurrentColumnNumber(parser); - if (columnNumber != 0) - fail("XML_GetCurrentColumnNumber does not work as expected."); - - XML_ParserFree(parser); } } END_TEST