From 15ef260f6b7b8a620322567d8cc1606923946006 Mon Sep 17 00:00:00 2001 From: Rhodri James Date: Fri, 10 Feb 2017 18:17:01 +0000 Subject: [PATCH 01/54] Test handling of trailing CR (rather than newline) --- expat/tests/runtests.c | 43 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/expat/tests/runtests.c b/expat/tests/runtests.c index 5c9857c9..700ff86c 100644 --- a/expat/tests/runtests.c +++ b/expat/tests/runtests.c @@ -2308,6 +2308,48 @@ START_TEST(test_explicit_encoding) } END_TEST +/* Test handling of trailing CR (rather than newline) */ +static void XMLCALL +cr_cdata_handler(void *userData, const XML_Char *s, int len) +{ + int *pfound = (int *)userData; + + /* Internal processing turns the CR into a newline for the + * character data handler, but not for the default handler + */ + if (len == 1 && (*s == '\n' || *s == '\r')) + *pfound = 1; +} + +START_TEST(test_trailing_cr) +{ + const char *text = "\r"; + int found_cr; + + /* Try with a character handler, for code coverage */ + XML_SetCharacterDataHandler(parser, cr_cdata_handler); + XML_SetUserData(parser, &found_cr); + found_cr = 0; + if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), + XML_TRUE) == XML_STATUS_OK) + fail("Failed to fault unclosed doc"); + if (found_cr == 0) + fail("Did not catch the carriage return"); + XML_ParserReset(parser, NULL); + + /* Now with a default handler instead */ + XML_SetDefaultHandler(parser, cr_cdata_handler); + XML_SetUserData(parser, &found_cr); + found_cr = 0; + if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), + XML_TRUE) == XML_STATUS_OK) + fail("Failed to fault unclosed doc"); + if (found_cr == 0) + fail("Did not catch default carriage return"); +} +END_TEST + + /* Test user parameter settings */ /* Variable holding the expected handler userData */ static void *handler_data = NULL; @@ -3929,6 +3971,7 @@ make_suite(void) tcase_add_test(tc_basic, test_subordinate_xdecl_suspend); tcase_add_test(tc_basic, test_subordinate_xdecl_abort); tcase_add_test(tc_basic, test_explicit_encoding); + tcase_add_test(tc_basic, test_trailing_cr); tcase_add_test(tc_basic, test_user_parameters); tcase_add_test(tc_basic, test_ext_entity_ref_parameter); tcase_add_test(tc_basic, test_empty_parse); From 6cfef697051117be8dbeeeaa959afdd3fcbd7c7f Mon Sep 17 00:00:00 2001 From: Rhodri James Date: Mon, 13 Feb 2017 17:59:47 +0000 Subject: [PATCH 02/54] Test trailing CR in external entity parse --- expat/tests/runtests.c | 79 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/expat/tests/runtests.c b/expat/tests/runtests.c index 700ff86c..5609cfc3 100644 --- a/expat/tests/runtests.c +++ b/expat/tests/runtests.c @@ -2349,6 +2349,84 @@ START_TEST(test_trailing_cr) } END_TEST +/* Test trailing CR in an external entity parse */ +static int XMLCALL +external_entity_cr_catcher(XML_Parser parser, + const XML_Char *context, + const XML_Char *UNUSED_P(base), + const XML_Char *UNUSED_P(systemId), + const XML_Char *UNUSED_P(publicId)) +{ + const char *text = "\r"; + XML_Parser ext_parser; + + ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL); + if (ext_parser == NULL) + fail("Could not create external entity parser"); + XML_SetCharacterDataHandler(ext_parser, cr_cdata_handler); + if (_XML_Parse_SINGLE_BYTES(ext_parser, text, strlen(text), + XML_TRUE) == XML_STATUS_ERROR) + xml_failure(ext_parser); + XML_ParserFree(ext_parser); + return XML_STATUS_OK; +} + +static int XMLCALL +external_entity_bad_cr_catcher(XML_Parser parser, + const XML_Char *context, + const XML_Char *UNUSED_P(base), + const XML_Char *UNUSED_P(systemId), + const XML_Char *UNUSED_P(publicId)) +{ + const char *text = "\r"; + XML_Parser ext_parser; + + ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL); + if (ext_parser == NULL) + fail("Could not create external entity parser"); + XML_SetCharacterDataHandler(ext_parser, cr_cdata_handler); + if (_XML_Parse_SINGLE_BYTES(ext_parser, text, strlen(text), + XML_TRUE) == XML_STATUS_OK) + fail("Async entity error not caught"); + if (XML_GetErrorCode(ext_parser) != XML_ERROR_ASYNC_ENTITY) + xml_failure(ext_parser); + XML_ParserFree(ext_parser); + return XML_STATUS_OK; +} + +START_TEST(test_ext_entity_trailing_cr) +{ + const char *text = + "\n" + "]>\n" + "&en;"; + int found_cr; + + XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS); + XML_SetExternalEntityRefHandler(parser, external_entity_cr_catcher); + XML_SetUserData(parser, &found_cr); + found_cr = 0; + if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), + XML_TRUE) != XML_STATUS_OK) + xml_failure(parser); + if (found_cr == 0) + fail("No carriage return found"); + XML_ParserReset(parser, NULL); + + /* Try again with a different trailing CR */ + XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS); + XML_SetExternalEntityRefHandler(parser, external_entity_bad_cr_catcher); + XML_SetUserData(parser, &found_cr); + found_cr = 0; + if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), + XML_TRUE) != XML_STATUS_OK) + xml_failure(parser); + if (found_cr == 0) + fail("No carriage return found"); +} +END_TEST + /* Test user parameter settings */ /* Variable holding the expected handler userData */ @@ -3972,6 +4050,7 @@ make_suite(void) tcase_add_test(tc_basic, test_subordinate_xdecl_abort); tcase_add_test(tc_basic, test_explicit_encoding); tcase_add_test(tc_basic, test_trailing_cr); + tcase_add_test(tc_basic, test_ext_entity_trailing_cr); tcase_add_test(tc_basic, test_user_parameters); tcase_add_test(tc_basic, test_ext_entity_ref_parameter); tcase_add_test(tc_basic, test_empty_parse); From f71790ccf990846acdf66b5b0fc7300a9ff0d3fa Mon Sep 17 00:00:00 2001 From: Rhodri James Date: Mon, 13 Feb 2017 18:05:54 +0000 Subject: [PATCH 03/54] Extend coverage of partial character parsing --- expat/tests/runtests.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/expat/tests/runtests.c b/expat/tests/runtests.c index 5609cfc3..b89aafaa 100644 --- a/expat/tests/runtests.c +++ b/expat/tests/runtests.c @@ -1327,6 +1327,11 @@ START_TEST(test_ext_entity_invalid_parse) "Incomplete character not faulted", XML_ERROR_PARTIAL_CHAR }, + { + "\xe2\x82", + "Incomplete character in CDATA not faulted", + XML_ERROR_PARTIAL_CHAR + }, { NULL, NULL, XML_ERROR_NONE } }; const ExtFaults *fault = faults; From 7653beecee83bc3da986e511f9e1fbe254789c58 Mon Sep 17 00:00:00 2001 From: Rhodri James Date: Tue, 14 Feb 2017 15:31:31 +0000 Subject: [PATCH 04/54] More external entity allocation failure coverage --- expat/tests/runtests.c | 58 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/expat/tests/runtests.c b/expat/tests/runtests.c index b89aafaa..9bf84fda 100644 --- a/expat/tests/runtests.c +++ b/expat/tests/runtests.c @@ -3824,6 +3824,63 @@ START_TEST(test_alloc_external_entity) } END_TEST +/* Test more allocation failure paths */ +static int XMLCALL +external_entity_alloc_set_encoding(XML_Parser parser, + const XML_Char *context, + const XML_Char *UNUSED_P(base), + const XML_Char *UNUSED_P(systemId), + const XML_Char *UNUSED_P(publicId)) +{ + /* As for external_entity_loader_set_encoding() */ + const char *text = + "" + "\xC3\xA9"; + XML_Parser ext_parser; + enum XML_Status status; + + ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL); + if (ext_parser == NULL) + return 0; + if (!XML_SetEncoding(ext_parser, "utf-8")) { + XML_ParserFree(ext_parser); + return 0; + } + status = _XML_Parse_SINGLE_BYTES(ext_parser, text, strlen(text), + XML_TRUE); + XML_ParserFree(ext_parser); + if (status == XML_STATUS_ERROR) + return 0; + return 1; +} + +START_TEST(test_alloc_ext_entity_set_encoding) +{ + const char *text = + "\n" + "]>\n" + "&en;"; + int i; +#define MAX_ALLOCATION_COUNT 20 + + for (i = 0; i < MAX_ALLOCATION_COUNT; i++) { + XML_SetExternalEntityRefHandler(parser, + external_entity_alloc_set_encoding); + allocation_count = i; + if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), + XML_TRUE) == XML_STATUS_OK) + break; + allocation_count = -1; + XML_ParserReset(parser, NULL); + } + if (i == 0) + fail("Encoding check succeeded despite failing allocator"); + if (i == MAX_ALLOCATION_COUNT) + fail("Encoding failed at max allocation count"); +#undef MAX_ALLOCATION_COUNT +} +END_TEST static int XMLCALL unknown_released_encoding_handler(void *UNUSED_P(data), @@ -4102,6 +4159,7 @@ make_suite(void) tcase_add_test(tc_alloc, test_alloc_run_external_parser); tcase_add_test(tc_alloc, test_alloc_dtd_copy_default_atts); tcase_add_test(tc_alloc, test_alloc_external_entity); + tcase_add_test(tc_alloc, test_alloc_ext_entity_set_encoding); tcase_add_test(tc_alloc, test_alloc_internal_entity); tcase_add_test(tc_alloc, test_alloc_dtd_default_handling); tcase_add_test(tc_alloc, test_alloc_explicit_encoding); From 9a7d8d2c3f890ee1cad5de82f758ae76fc7b2c61 Mon Sep 17 00:00:00 2001 From: Rhodri James Date: Tue, 14 Feb 2017 16:04:56 +0000 Subject: [PATCH 05/54] Tweak tests for greater allocation failure coverage --- expat/tests/runtests.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/expat/tests/runtests.c b/expat/tests/runtests.c index 9bf84fda..530cef73 100644 --- a/expat/tests/runtests.c +++ b/expat/tests/runtests.c @@ -3862,9 +3862,17 @@ START_TEST(test_alloc_ext_entity_set_encoding) "]>\n" "&en;"; int i; + int repeat = 0; #define MAX_ALLOCATION_COUNT 20 for (i = 0; i < MAX_ALLOCATION_COUNT; i++) { + /* Repeat some counts to get round caching */ + if ((i == 2 && repeat < 3) || + (i == 3 && repeat < 6) || + (i == 4 && repeat == 6)) { + i--; + repeat++; + } XML_SetExternalEntityRefHandler(parser, external_entity_alloc_set_encoding); allocation_count = i; From 41524fed8589f47d4f5f72dd18fafa76d0c59ecd Mon Sep 17 00:00:00 2001 From: Rhodri James Date: Tue, 14 Feb 2017 16:13:06 +0000 Subject: [PATCH 06/54] Test external entity with no handler --- expat/tests/runtests.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/expat/tests/runtests.c b/expat/tests/runtests.c index 530cef73..a083e777 100644 --- a/expat/tests/runtests.c +++ b/expat/tests/runtests.c @@ -1022,6 +1022,20 @@ START_TEST(test_ext_entity_set_encoding) } END_TEST +/* Test external entities with no handler */ +START_TEST(test_ext_entity_no_handler) +{ + const char *text = + "\n" + "]>\n" + "&en;"; + + XML_SetDefaultHandler(parser, dummy_default_handler); + run_character_check(text, ""); +} +END_TEST + /* Test UTF-8 BOM is accepted */ static int XMLCALL external_entity_loader_set_bom(XML_Parser parser, @@ -4092,6 +4106,7 @@ make_suite(void) test_wfc_undeclared_entity_with_external_subset_standalone); tcase_add_test(tc_basic, test_wfc_no_recursive_entity_refs); tcase_add_test(tc_basic, test_ext_entity_set_encoding); + tcase_add_test(tc_basic, test_ext_entity_no_handler); tcase_add_test(tc_basic, test_ext_entity_set_bom); tcase_add_test(tc_basic, test_ext_entity_bad_encoding); tcase_add_test(tc_basic, test_ext_entity_invalid_parse); From dabb530d17bde94a65df68d8775482cb3c4a7dcc Mon Sep 17 00:00:00 2001 From: Rhodri James Date: Tue, 14 Feb 2017 16:26:27 +0000 Subject: [PATCH 07/54] Extend coverage of namespace start and end handlers --- expat/tests/runtests.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/expat/tests/runtests.c b/expat/tests/runtests.c index a083e777..2470bf66 100644 --- a/expat/tests/runtests.c +++ b/expat/tests/runtests.c @@ -3210,6 +3210,11 @@ START_TEST(test_ns_default_with_empty_uri) "\n" " \n" ""; + /* Add some handlers to exercise extra code paths */ + XML_SetStartNamespaceDeclHandler(parser, + dummy_start_namespace_decl_handler); + XML_SetEndNamespaceDeclHandler(parser, + dummy_end_namespace_decl_handler); if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR) xml_failure(parser); } From e92f989efe3a7cd4eb6d54d1e54390ece9a68c2c Mon Sep 17 00:00:00 2001 From: Rhodri James Date: Tue, 14 Feb 2017 16:40:55 +0000 Subject: [PATCH 08/54] Add default handlers to character entity tests to extend coverage --- expat/tests/runtests.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/expat/tests/runtests.c b/expat/tests/runtests.c index 2470bf66..cf20b91e 100644 --- a/expat/tests/runtests.c +++ b/expat/tests/runtests.c @@ -580,6 +580,13 @@ START_TEST(test_latin1_umlauts) run_character_check(text, utf8); XML_ParserReset(parser, NULL); run_attribute_check(text, utf8); + /* Repeat with a default handler */ + XML_ParserReset(parser, NULL); + XML_SetDefaultHandler(parser, dummy_default_handler); + run_character_check(text, utf8); + XML_ParserReset(parser, NULL); + XML_SetDefaultHandler(parser, dummy_default_handler); + run_attribute_check(text, utf8); } END_TEST From 05fe0bd6c94bd763b481c15f7669c0d8c1ca1018 Mon Sep 17 00:00:00 2001 From: Rhodri James Date: Tue, 14 Feb 2017 17:36:38 +0000 Subject: [PATCH 09/54] Add default handler to namespace failing allocation test Increases code coverage. Also tweaked allocation counts for better coverage --- expat/tests/runtests.c | 50 +++++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/expat/tests/runtests.c b/expat/tests/runtests.c index cf20b91e..f40d3b25 100644 --- a/expat/tests/runtests.c +++ b/expat/tests/runtests.c @@ -3392,31 +3392,37 @@ START_TEST(test_misc_alloc_ns) allocation_count = ALLOC_ALWAYS_SUCCEED; parser = XML_ParserCreate_MM(NULL, &memsuite, ns_sep); - if (parser == NULL) { + if (parser == NULL) fail("Parser not created"); - } else { - for (i = 0; i < 10; i++) { - /* Repeat some tests with the same allocation count to - * catch cached allocations not freed by XML_ParserReset() - */ - if (repeated < 2 && i == 3) { - i--; - repeated++; - } - if (repeated == 2 && i == 5) { - i = 3; - repeated++; - } - allocation_count = i; - if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_TRUE) != XML_STATUS_ERROR) - break; - XML_ParserReset(parser, NULL); + + for (i = 0; i < 10; i++) { + /* Repeat some tests with the same allocation count to + * catch cached allocations not freed by XML_ParserReset() + */ + if ((i == 4 && repeated == 3) || + (i == 7 && repeated == 8)) { + i -= 2; + repeated++; } - if (i == 0) - fail("Parsing worked despite failing allocations"); - else if (i == 10) - fail("Parsing failed even at allocation count 10"); + else if ((i == 2 && repeated < 2) || + (i == 3 && repeated < 3) || + (i == 3 && repeated > 3 && repeated < 7) || + (i == 5 && repeated < 8)) { + i--; + repeated++; + } + allocation_count = i; + /* Exercise more code paths with a default handler */ + XML_SetDefaultHandler(parser, dummy_default_handler); + if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), + XML_TRUE) != XML_STATUS_ERROR) + break; + XML_ParserReset(parser, NULL); } + if (i == 0) + fail("Parsing worked despite failing allocations"); + else if (i == 10) + fail("Parsing failed even at allocation count 10"); } END_TEST From 213c8523a3b9c69d66d08b2e25f6de986ae61c60 Mon Sep 17 00:00:00 2001 From: Rhodri James Date: Tue, 14 Feb 2017 17:57:58 +0000 Subject: [PATCH 10/54] Add CDATA section handlers for increased test coverage --- expat/tests/runtests.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/expat/tests/runtests.c b/expat/tests/runtests.c index f40d3b25..726c2a5f 100644 --- a/expat/tests/runtests.c +++ b/expat/tests/runtests.c @@ -1584,6 +1584,9 @@ START_TEST(test_good_cdata_ascii) CharData_Init(&storage); XML_SetUserData(parser, &storage); XML_SetCharacterDataHandler(parser, accumulate_characters); + /* Add start and end handlers for coverage */ + XML_SetStartCdataSectionHandler(parser, dummy_start_cdata_handler); + XML_SetEndCdataSectionHandler(parser, dummy_end_cdata_handler); if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR) xml_failure(parser); From fe2e255025df92838d3d1ae3d611e11f035a951e Mon Sep 17 00:00:00 2001 From: Rhodri James Date: Tue, 14 Feb 2017 18:22:53 +0000 Subject: [PATCH 11/54] Extend ASCII CDATA test to cover a default handler --- expat/tests/runtests.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/expat/tests/runtests.c b/expat/tests/runtests.c index 726c2a5f..6200b244 100644 --- a/expat/tests/runtests.c +++ b/expat/tests/runtests.c @@ -1591,6 +1591,17 @@ START_TEST(test_good_cdata_ascii) if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR) xml_failure(parser); CharData_CheckXMLChars(&storage, expected); + + /* Try again, this time with a default handler */ + XML_ParserReset(parser, NULL); + CharData_Init(&storage); + XML_SetUserData(parser, &storage); + XML_SetCharacterDataHandler(parser, accumulate_characters); + XML_SetDefaultHandler(parser, dummy_default_handler); + + if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR) + xml_failure(parser); + CharData_CheckXMLChars(&storage, expected); } END_TEST From 8bdf2bc10246a7b5f738f115c2c6f1c4944a2c84 Mon Sep 17 00:00:00 2001 From: Rhodri James Date: Wed, 15 Feb 2017 13:50:04 +0000 Subject: [PATCH 12/54] Test handling of right square bracket at end of content data --- expat/tests/runtests.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/expat/tests/runtests.c b/expat/tests/runtests.c index 6200b244..61e6f987 100644 --- a/expat/tests/runtests.c +++ b/expat/tests/runtests.c @@ -1747,7 +1747,7 @@ record_cdata_nodefault_handler(void *userData, /* Test XML_DefaultCurrent() passes handling on correctly */ START_TEST(test_default_current) { - const char *text = "hello"; + const char *text = "hell]"; const char *entity_text = "\n" From a3a68a412daa57b5edd02a1a86eab1f7d3d9045d Mon Sep 17 00:00:00 2001 From: Rhodri James Date: Wed, 15 Feb 2017 15:02:45 +0000 Subject: [PATCH 13/54] More tests for the right square bracket control paths --- expat/tests/runtests.c | 50 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/expat/tests/runtests.c b/expat/tests/runtests.c index 61e6f987..5eb64358 100644 --- a/expat/tests/runtests.c +++ b/expat/tests/runtests.c @@ -2467,6 +2467,55 @@ START_TEST(test_ext_entity_trailing_cr) } END_TEST +/* Test handling of trailing square bracket */ +static void XMLCALL +rsqb_handler(void *userData, const XML_Char *s, int len) +{ + int *pfound = (int *)userData; + + if (len == 1 && *s == ']') + *pfound = 1; +} + +START_TEST(test_trailing_rsqb) +{ + const char *text8 = "]"; + const char text16[] = "\xFF\xFE<\000d\000o\000c\000>\000]\000"; + int found_rsqb; + + XML_SetCharacterDataHandler(parser, rsqb_handler); + XML_SetUserData(parser, &found_rsqb); + found_rsqb = 0; + if (_XML_Parse_SINGLE_BYTES(parser, text8, strlen(text8), + XML_TRUE) == XML_STATUS_OK) + fail("Failed to fault unclosed doc"); + if (found_rsqb == 0) + fail("Did not catch the right square bracket"); + + /* Try again with a different encoding */ + XML_ParserReset(parser, NULL); + XML_SetCharacterDataHandler(parser, rsqb_handler); + XML_SetUserData(parser, &found_rsqb); + found_rsqb = 0; + if (_XML_Parse_SINGLE_BYTES(parser, text16, sizeof(text16)-1, + XML_TRUE) == XML_STATUS_OK) + fail("Failed to fault unclosed doc"); + if (found_rsqb == 0) + fail("Did not catch the right square bracket"); + + /* And finally with a default handler */ + XML_ParserReset(parser, NULL); + XML_SetDefaultHandler(parser, rsqb_handler); + XML_SetUserData(parser, &found_rsqb); + found_rsqb = 0; + if (_XML_Parse_SINGLE_BYTES(parser, text16, sizeof(text16)-1, + XML_TRUE) == XML_STATUS_OK) + fail("Failed to fault unclosed doc"); + if (found_rsqb == 0) + fail("Did not catch the right square bracket"); +} +END_TEST + /* Test user parameter settings */ /* Variable holding the expected handler userData */ @@ -4168,6 +4217,7 @@ make_suite(void) tcase_add_test(tc_basic, test_explicit_encoding); tcase_add_test(tc_basic, test_trailing_cr); tcase_add_test(tc_basic, test_ext_entity_trailing_cr); + tcase_add_test(tc_basic, test_trailing_rsqb); tcase_add_test(tc_basic, test_user_parameters); tcase_add_test(tc_basic, test_ext_entity_ref_parameter); tcase_add_test(tc_basic, test_empty_parse); From ef26a78837b193adaf18254de8d3cf5c92d5dd77 Mon Sep 17 00:00:00 2001 From: Rhodri James Date: Wed, 15 Feb 2017 15:48:00 +0000 Subject: [PATCH 14/54] Test right square bracket handling in external entity parses --- expat/tests/runtests.c | 48 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/expat/tests/runtests.c b/expat/tests/runtests.c index 5eb64358..e0f48d8f 100644 --- a/expat/tests/runtests.c +++ b/expat/tests/runtests.c @@ -2482,11 +2482,12 @@ START_TEST(test_trailing_rsqb) const char *text8 = "]"; const char text16[] = "\xFF\xFE<\000d\000o\000c\000>\000]\000"; int found_rsqb; + int text8_len = strlen(text8); XML_SetCharacterDataHandler(parser, rsqb_handler); XML_SetUserData(parser, &found_rsqb); found_rsqb = 0; - if (_XML_Parse_SINGLE_BYTES(parser, text8, strlen(text8), + if (_XML_Parse_SINGLE_BYTES(parser, text8, text8_len, XML_TRUE) == XML_STATUS_OK) fail("Failed to fault unclosed doc"); if (found_rsqb == 0) @@ -2516,6 +2517,50 @@ START_TEST(test_trailing_rsqb) } END_TEST +/* Test trailing right square bracket in an external entity parse */ +static int XMLCALL +external_entity_rsqb_catcher(XML_Parser parser, + const XML_Char *context, + const XML_Char *UNUSED_P(base), + const XML_Char *UNUSED_P(systemId), + const XML_Char *UNUSED_P(publicId)) +{ + const char *text = "]"; + XML_Parser ext_parser; + + ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL); + if (ext_parser == NULL) + fail("Could not create external entity parser"); + XML_SetCharacterDataHandler(ext_parser, rsqb_handler); + if (_XML_Parse_SINGLE_BYTES(ext_parser, text, strlen(text), + XML_TRUE) != XML_STATUS_ERROR) + fail("Async entity error not caught"); + if (XML_GetErrorCode(ext_parser) != XML_ERROR_ASYNC_ENTITY) + xml_failure(ext_parser); + XML_ParserFree(ext_parser); + return XML_STATUS_OK; +} + +START_TEST(test_ext_entity_trailing_rsqb) +{ + const char *text = + "\n" + "]>\n" + "&en;"; + int found_rsqb; + + XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS); + XML_SetExternalEntityRefHandler(parser, external_entity_rsqb_catcher); + XML_SetUserData(parser, &found_rsqb); + found_rsqb = 0; + if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), + XML_TRUE) != XML_STATUS_OK) + xml_failure(parser); + if (found_rsqb == 0) + fail("No right square bracket found"); +} +END_TEST /* Test user parameter settings */ /* Variable holding the expected handler userData */ @@ -4218,6 +4263,7 @@ make_suite(void) tcase_add_test(tc_basic, test_trailing_cr); tcase_add_test(tc_basic, test_ext_entity_trailing_cr); tcase_add_test(tc_basic, test_trailing_rsqb); + tcase_add_test(tc_basic, test_ext_entity_trailing_rsqb); tcase_add_test(tc_basic, test_user_parameters); tcase_add_test(tc_basic, test_ext_entity_ref_parameter); tcase_add_test(tc_basic, test_empty_parse); From 97ad97e9e9f0ba7a55d5a78e823b3cabc59b8377 Mon Sep 17 00:00:00 2001 From: Rhodri James Date: Wed, 15 Feb 2017 17:24:06 +0000 Subject: [PATCH 15/54] Expand really long line test for encoded CDATA handling --- expat/tests/runtests.c | 51 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/expat/tests/runtests.c b/expat/tests/runtests.c index e0f48d8f..839526d5 100644 --- a/expat/tests/runtests.c +++ b/expat/tests/runtests.c @@ -202,6 +202,12 @@ static void XMLCALL dummy_end_cdata_handler(void *UNUSED_P(userData)) {} +static void XMLCALL +dummy_cdata_handler(void *UNUSED_P(userData), + const XML_Char *UNUSED_P(s), + int UNUSED_P(len)) +{} + static void XMLCALL dummy_start_namespace_decl_handler(void *UNUSED_P(userData), const XML_Char *UNUSED_P(prefix), @@ -770,6 +776,50 @@ START_TEST(test_really_long_lines) } END_TEST +/* Test cdata processing across a buffer boundary */ +START_TEST(test_really_long_encoded_lines) +{ + /* As above, except that we want to provoke an output buffer + * overflow with a non-trivial encoding. For this we need to pass + * the whole cdata in one go, not byte-by-byte. + */ + void *buffer; + const char *text = + "" + "" + /* 64 chars */ + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" + /* until we have at least 1024 characters on the line: */ + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" + ""; + int parse_len = strlen(text); + + /* Need a cdata handler to provoke the code path we want to test */ + XML_SetCharacterDataHandler(parser, dummy_cdata_handler); + buffer = XML_GetBuffer(parser, parse_len); + if (buffer == NULL) + fail("Could not allocate parse buffer"); + memcpy(buffer, text, parse_len); + if (XML_ParseBuffer(parser, parse_len, XML_TRUE) == XML_STATUS_ERROR) + xml_failure(parser); +} +END_TEST + /* * Element event tests. @@ -4216,6 +4266,7 @@ make_suite(void) tcase_add_test(tc_basic, test_line_number_after_error); tcase_add_test(tc_basic, test_column_number_after_error); tcase_add_test(tc_basic, test_really_long_lines); + tcase_add_test(tc_basic, test_really_long_encoded_lines); tcase_add_test(tc_basic, test_end_element_events); tcase_add_test(tc_basic, test_attr_whitespace_normalization); tcase_add_test(tc_basic, test_xmldecl_misplaced); From a1cffcb4eae798e6ae05f261233b0fbc77f6c4be Mon Sep 17 00:00:00 2001 From: Rhodri James Date: Wed, 15 Feb 2017 18:17:25 +0000 Subject: [PATCH 16/54] Test parsing a PI with a failing allocator --- expat/tests/runtests.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/expat/tests/runtests.c b/expat/tests/runtests.c index 839526d5..f57dc2da 100644 --- a/expat/tests/runtests.c +++ b/expat/tests/runtests.c @@ -3752,6 +3752,44 @@ alloc_teardown(void) basic_teardown(); } + +/* Test the effects of allocation failures on a straightforward parse */ +START_TEST(test_alloc_parse) +{ + const char *text = + "\n" + "\n" + "Hello, world"; + int i; + int repeat = 0; +#define MAX_ALLOC_COUNT 10 + + for (i = 0; i < MAX_ALLOC_COUNT; i++) { + allocation_count = i; + /* Repeat some counts because of cached memory */ + if (i == 2 && repeat == 2) { + i -= 2; + repeat++; + } else if ((i == 1 && repeat < 2) || + (i == 1 && repeat > 2 && repeat < 5)) { + i--; + repeat++; + } + XML_SetProcessingInstructionHandler(parser, dummy_pi_handler); + if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), + XML_TRUE) != XML_STATUS_ERROR) + break; + XML_ParserReset(parser, NULL); + } + if (i == 0) + fail("Parse succeeded despite failing allocator"); + if (i == MAX_ALLOC_COUNT) + fail("Parse failed with max allocations"); +#undef MAX_ALLOC_COUNT +} +END_TEST + + static int XMLCALL external_entity_duff_loader(XML_Parser parser, const XML_Char *context, @@ -4357,6 +4395,7 @@ make_suite(void) suite_add_tcase(s, tc_alloc); tcase_add_checked_fixture(tc_alloc, alloc_setup, alloc_teardown); + tcase_add_test(tc_alloc, test_alloc_parse); tcase_add_test(tc_alloc, test_alloc_create_external_parser); tcase_add_test(tc_alloc, test_alloc_run_external_parser); tcase_add_test(tc_alloc, test_alloc_dtd_copy_default_atts); From 8f3d13188b60bc685b94d0805517b4c3f16b8888 Mon Sep 17 00:00:00 2001 From: Rhodri James Date: Wed, 15 Feb 2017 18:49:24 +0000 Subject: [PATCH 17/54] More coverage of PIs with failing allocator --- expat/tests/runtests.c | 45 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 42 insertions(+), 3 deletions(-) diff --git a/expat/tests/runtests.c b/expat/tests/runtests.c index f57dc2da..2fb6ee70 100644 --- a/expat/tests/runtests.c +++ b/expat/tests/runtests.c @@ -3754,12 +3754,14 @@ alloc_teardown(void) /* Test the effects of allocation failures on a straightforward parse */ -START_TEST(test_alloc_parse) +START_TEST(test_alloc_parse_pi) { const char *text = "\n" "\n" - "Hello, world"; + "" + "Hello, world" + ""; int i; int repeat = 0; #define MAX_ALLOC_COUNT 10 @@ -3789,6 +3791,42 @@ START_TEST(test_alloc_parse) } END_TEST +START_TEST(test_alloc_parse_pi_2) +{ + const char *text = + "\n" + "" + "Hello, world" + "\n" + ""; + int i; + int repeat = 0; +#define MAX_ALLOC_COUNT 10 + + for (i = 0; i < MAX_ALLOC_COUNT; i++) { + allocation_count = i; + /* Repeat some counts because of cached memory */ + if (i == 2 && repeat == 1) { + i -= 2; + repeat++; + } else if ((i == 1 && repeat < 1) || + (i == 1 && repeat > 1 && repeat < 4)) { + i--; + repeat++; + } + XML_SetProcessingInstructionHandler(parser, dummy_pi_handler); + if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), + XML_TRUE) != XML_STATUS_ERROR) + break; + XML_ParserReset(parser, NULL); + } + if (i == 0) + fail("Parse succeeded despite failing allocator"); + if (i == MAX_ALLOC_COUNT) + fail("Parse failed with max allocations"); +#undef MAX_ALLOC_COUNT +} +END_TEST static int XMLCALL external_entity_duff_loader(XML_Parser parser, @@ -4395,7 +4433,8 @@ make_suite(void) suite_add_tcase(s, tc_alloc); tcase_add_checked_fixture(tc_alloc, alloc_setup, alloc_teardown); - tcase_add_test(tc_alloc, test_alloc_parse); + tcase_add_test(tc_alloc, test_alloc_parse_pi); + tcase_add_test(tc_alloc, test_alloc_parse_pi_2); tcase_add_test(tc_alloc, test_alloc_create_external_parser); tcase_add_test(tc_alloc, test_alloc_run_external_parser); tcase_add_test(tc_alloc, test_alloc_dtd_copy_default_atts); From f591474e623ed144e7e95e2df51fde521598e3b1 Mon Sep 17 00:00:00 2001 From: Rhodri James Date: Wed, 15 Feb 2017 19:11:19 +0000 Subject: [PATCH 18/54] Add test coverage for comments with a failing allocator --- expat/tests/runtests.c | 74 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/expat/tests/runtests.c b/expat/tests/runtests.c index 2fb6ee70..fe5486cb 100644 --- a/expat/tests/runtests.c +++ b/expat/tests/runtests.c @@ -3828,6 +3828,78 @@ START_TEST(test_alloc_parse_pi_2) } END_TEST +START_TEST(test_alloc_parse_comment) +{ + const char *text = + "\n" + "" + "Hi"; + int i; + int repeat = 0; +#define MAX_ALLOC_COUNT 10 + + for (i = 0; i < MAX_ALLOC_COUNT; i++) { + /* Repeat some counts because of cached memory */ + if (i == 2 && repeat == 2) { + i -= 2; + repeat++; + } else if ((i == 1 && repeat < 2) || + (i == 1 && repeat > 2 && repeat < 5)) { + i--; + repeat++; + } + allocation_count = i; + XML_SetCommentHandler(parser, dummy_comment_handler); + if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), + XML_TRUE) != XML_STATUS_ERROR) + break; + XML_ParserReset(parser, NULL); + } + if (i == 0) + fail("Parse succeeded despite failing allocator"); + if (i == MAX_ALLOC_COUNT) + fail("Parse failed with max allocations"); +#undef MAX_ALLOC_COUNT +} +END_TEST + +START_TEST(test_alloc_parse_comment_2) +{ + const char *text = + "\n" + "" + "Hello, world" + "" + ""; + int i; + int repeat = 0; +#define MAX_ALLOC_COUNT 10 + + for (i = 0; i < MAX_ALLOC_COUNT; i++) { + allocation_count = i; + /* Repeat some counts because of cached memory */ + if (i == 2 && repeat == 1) { + i -= 2; + repeat++; + } else if ((i == 1 && repeat < 1) || + (i == 1 && repeat > 1 && repeat < 4)) { + i--; + repeat++; + } + XML_SetCommentHandler(parser, dummy_comment_handler); + if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), + XML_TRUE) != XML_STATUS_ERROR) + break; + XML_ParserReset(parser, NULL); + } + if (i == 0) + fail("Parse succeeded despite failing allocator"); + if (i == MAX_ALLOC_COUNT) + fail("Parse failed with max allocations"); +#undef MAX_ALLOC_COUNT +} +END_TEST + static int XMLCALL external_entity_duff_loader(XML_Parser parser, const XML_Char *context, @@ -4435,6 +4507,8 @@ make_suite(void) tcase_add_checked_fixture(tc_alloc, alloc_setup, alloc_teardown); tcase_add_test(tc_alloc, test_alloc_parse_pi); tcase_add_test(tc_alloc, test_alloc_parse_pi_2); + tcase_add_test(tc_alloc, test_alloc_parse_comment); + tcase_add_test(tc_alloc, test_alloc_parse_comment_2); tcase_add_test(tc_alloc, test_alloc_create_external_parser); tcase_add_test(tc_alloc, test_alloc_run_external_parser); tcase_add_test(tc_alloc, test_alloc_dtd_copy_default_atts); From 20c12da662a9c992194cbdb71cc5bf9929ff2e3a Mon Sep 17 00:00:00 2001 From: Rhodri James Date: Tue, 14 Feb 2017 11:50:40 +0000 Subject: [PATCH 19/54] Extend code path coverage of entity handling --- expat/tests/runtests.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/expat/tests/runtests.c b/expat/tests/runtests.c index fe5486cb..6519fec4 100644 --- a/expat/tests/runtests.c +++ b/expat/tests/runtests.c @@ -231,6 +231,11 @@ dummy_unparsed_entity_decl_handler(void *UNUSED_P(userData), const XML_Char *UNUSED_P(notationName)) {} +static void XMLCALL +dummy_default_handler(void *UNUSED_P(userData), + const XML_Char *UNUSED_P(s), + int UNUSED_P(len)) +{} /* * Character & encoding tests. @@ -1892,6 +1897,8 @@ START_TEST(test_set_foreign_dtd) XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS); XML_SetUserData(parser, dtd_text); XML_SetExternalEntityRefHandler(parser, external_entity_loader); + /* Add a default handler to exercise more code paths */ + XML_SetDefaultHandler(parser, dummy_default_handler); if (XML_UseForeignDTD(parser, XML_TRUE) != XML_ERROR_NONE) fail("Could not set foreign DTD"); if (_XML_Parse_SINGLE_BYTES(parser, text1, strlen(text1), From 8dabab1576c27e46a61ea880705c90c201b022bc Mon Sep 17 00:00:00 2001 From: Rhodri James Date: Thu, 16 Feb 2017 16:09:28 +0000 Subject: [PATCH 20/54] Refactor namespace allocation tests --- expat/tests/runtests.c | 249 ++++++++++++++++++++++------------------- 1 file changed, 132 insertions(+), 117 deletions(-) diff --git a/expat/tests/runtests.c b/expat/tests/runtests.c index 6519fec4..68621e5c 100644 --- a/expat/tests/runtests.c +++ b/expat/tests/runtests.c @@ -3541,121 +3541,6 @@ START_TEST(test_misc_alloc_create_parser_with_encoding) } END_TEST -/* Test the effects of allocation failure in simple namespace parsing. - * Based on test_ns_default_with_empty_uri() - */ -START_TEST(test_misc_alloc_ns) -{ - XML_Memory_Handling_Suite memsuite = { duff_allocator, realloc, free }; - const char *text = - "\n" - " \n" - ""; - unsigned int i; - int repeated = 0; - XML_Char ns_sep[2] = { ' ', '\0' }; - - allocation_count = ALLOC_ALWAYS_SUCCEED; - parser = XML_ParserCreate_MM(NULL, &memsuite, ns_sep); - if (parser == NULL) - fail("Parser not created"); - - for (i = 0; i < 10; i++) { - /* Repeat some tests with the same allocation count to - * catch cached allocations not freed by XML_ParserReset() - */ - if ((i == 4 && repeated == 3) || - (i == 7 && repeated == 8)) { - i -= 2; - repeated++; - } - else if ((i == 2 && repeated < 2) || - (i == 3 && repeated < 3) || - (i == 3 && repeated > 3 && repeated < 7) || - (i == 5 && repeated < 8)) { - i--; - repeated++; - } - allocation_count = i; - /* Exercise more code paths with a default handler */ - XML_SetDefaultHandler(parser, dummy_default_handler); - if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), - XML_TRUE) != XML_STATUS_ERROR) - break; - XML_ParserReset(parser, NULL); - } - if (i == 0) - fail("Parsing worked despite failing allocations"); - else if (i == 10) - fail("Parsing failed even at allocation count 10"); -} -END_TEST - -/* Test XML_ParseBuffer interface with namespace and a dicky allocator */ -START_TEST(test_misc_alloc_ns_parse_buffer) -{ - XML_Memory_Handling_Suite memsuite = { duff_allocator, realloc, free }; - XML_Char ns_sep[2] = { ' ', '\0' }; - const char *text = "Hello"; - void *buffer; - - /* Make sure the basic parser is allocated */ - allocation_count = ALLOC_ALWAYS_SUCCEED; - parser = XML_ParserCreate_MM(NULL, &memsuite, ns_sep); - if (parser == NULL) - fail("Parser not created"); - - /* Try a parse before the start of the world */ - /* (Exercises new code path) */ - allocation_count = 0; - if (XML_ParseBuffer(parser, 0, XML_FALSE) != XML_STATUS_ERROR) - fail("Pre-init XML_ParseBuffer not faulted"); - if (XML_GetErrorCode(parser) != XML_ERROR_NO_MEMORY) - fail("Pre-init XML_ParseBuffer faulted for wrong reason"); - - /* Now with actual memory allocation */ - allocation_count = ALLOC_ALWAYS_SUCCEED; - if (XML_ParseBuffer(parser, 0, XML_FALSE) != XML_STATUS_OK) - xml_failure(parser); - - /* Check that resuming an unsuspended parser is faulted */ - if (XML_ResumeParser(parser) != XML_STATUS_ERROR) - fail("Resuming unsuspended parser not faulted"); - if (XML_GetErrorCode(parser) != XML_ERROR_NOT_SUSPENDED) - xml_failure(parser); - - /* Get the parser into suspended state */ - XML_SetCharacterDataHandler(parser, clearing_aborting_character_handler); - resumable = XML_TRUE; - buffer = XML_GetBuffer(parser, strlen(text)); - if (buffer == NULL) - fail("Could not acquire parse buffer"); - memcpy(buffer, text, strlen(text)); - if (XML_ParseBuffer(parser, strlen(text), - XML_TRUE) != XML_STATUS_SUSPENDED) - xml_failure(parser); - if (XML_GetErrorCode(parser) != XML_ERROR_NONE) - xml_failure(parser); - if (XML_ParseBuffer(parser, strlen(text), XML_TRUE) != XML_STATUS_ERROR) - fail("Suspended XML_ParseBuffer not faulted"); - if (XML_GetErrorCode(parser) != XML_ERROR_SUSPENDED) - xml_failure(parser); - if (XML_GetBuffer(parser, strlen(text)) != NULL) - fail("Suspended XML_GetBuffer not faulted"); - - /* Get it going again and complete the world */ - XML_SetCharacterDataHandler(parser, NULL); - if (XML_ResumeParser(parser) != XML_STATUS_OK) - xml_failure(parser); - if (XML_ParseBuffer(parser, strlen(text), XML_TRUE) != XML_STATUS_ERROR) - fail("Post-finishing XML_ParseBuffer not faulted"); - if (XML_GetErrorCode(parser) != XML_ERROR_FINISHED) - xml_failure(parser); - if (XML_GetBuffer(parser, strlen(text)) != NULL) - fail("Post-finishing XML_GetBuffer not faulted"); -} -END_TEST - /* Test that freeing a NULL parser doesn't cause an explosion. * (Not actually tested anywhere else) */ @@ -4384,6 +4269,132 @@ START_TEST(test_alloc_set_base) END_TEST +static void +nsalloc_setup(void) +{ + XML_Memory_Handling_Suite memsuite = { + duff_allocator, + duff_reallocator, + free + }; + XML_Char ns_sep[2] = { ' ', '\0' }; + + /* Ensure the parser creation will go through */ + allocation_count = ALLOC_ALWAYS_SUCCEED; + reallocation_count = REALLOC_ALWAYS_SUCCEED; + parser = XML_ParserCreate_MM(NULL, &memsuite, ns_sep); + if (parser == NULL) + fail("Parser not created"); +} + +static void +nsalloc_teardown(void) +{ + basic_teardown(); +} + + +/* Test the effects of allocation failure in simple namespace parsing. + * Based on test_ns_default_with_empty_uri() + */ +START_TEST(test_nsalloc_xmlns) +{ + const char *text = + "\n" + " \n" + ""; + unsigned int i; + int repeated = 0; + + for (i = 0; i < 10; i++) { + /* Repeat some tests with the same allocation count to + * catch cached allocations not freed by XML_ParserReset() + */ + if ((i == 4 && repeated == 3) || + (i == 7 && repeated == 8)) { + i -= 2; + repeated++; + } + else if ((i == 2 && repeated < 2) || + (i == 3 && repeated < 3) || + (i == 3 && repeated > 3 && repeated < 7) || + (i == 5 && repeated < 8)) { + i--; + repeated++; + } + allocation_count = i; + /* Exercise more code paths with a default handler */ + XML_SetDefaultHandler(parser, dummy_default_handler); + if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), + XML_TRUE) != XML_STATUS_ERROR) + break; + XML_ParserReset(parser, NULL); + } + if (i == 0) + fail("Parsing worked despite failing allocations"); + else if (i == 10) + fail("Parsing failed even at allocation count 10"); +} +END_TEST + +/* Test XML_ParseBuffer interface with namespace and a dicky allocator */ +START_TEST(test_nsalloc_parse_buffer) +{ + const char *text = "Hello"; + void *buffer; + + /* Try a parse before the start of the world */ + /* (Exercises new code path) */ + allocation_count = 0; + if (XML_ParseBuffer(parser, 0, XML_FALSE) != XML_STATUS_ERROR) + fail("Pre-init XML_ParseBuffer not faulted"); + if (XML_GetErrorCode(parser) != XML_ERROR_NO_MEMORY) + fail("Pre-init XML_ParseBuffer faulted for wrong reason"); + + /* Now with actual memory allocation */ + allocation_count = ALLOC_ALWAYS_SUCCEED; + if (XML_ParseBuffer(parser, 0, XML_FALSE) != XML_STATUS_OK) + xml_failure(parser); + + /* Check that resuming an unsuspended parser is faulted */ + if (XML_ResumeParser(parser) != XML_STATUS_ERROR) + fail("Resuming unsuspended parser not faulted"); + if (XML_GetErrorCode(parser) != XML_ERROR_NOT_SUSPENDED) + xml_failure(parser); + + /* Get the parser into suspended state */ + XML_SetCharacterDataHandler(parser, clearing_aborting_character_handler); + resumable = XML_TRUE; + buffer = XML_GetBuffer(parser, strlen(text)); + if (buffer == NULL) + fail("Could not acquire parse buffer"); + memcpy(buffer, text, strlen(text)); + if (XML_ParseBuffer(parser, strlen(text), + XML_TRUE) != XML_STATUS_SUSPENDED) + xml_failure(parser); + if (XML_GetErrorCode(parser) != XML_ERROR_NONE) + xml_failure(parser); + if (XML_ParseBuffer(parser, strlen(text), XML_TRUE) != XML_STATUS_ERROR) + fail("Suspended XML_ParseBuffer not faulted"); + if (XML_GetErrorCode(parser) != XML_ERROR_SUSPENDED) + xml_failure(parser); + if (XML_GetBuffer(parser, strlen(text)) != NULL) + fail("Suspended XML_GetBuffer not faulted"); + + /* Get it going again and complete the world */ + XML_SetCharacterDataHandler(parser, NULL); + if (XML_ResumeParser(parser) != XML_STATUS_OK) + xml_failure(parser); + if (XML_ParseBuffer(parser, strlen(text), XML_TRUE) != XML_STATUS_ERROR) + fail("Post-finishing XML_ParseBuffer not faulted"); + if (XML_GetErrorCode(parser) != XML_ERROR_FINISHED) + xml_failure(parser); + if (XML_GetBuffer(parser, strlen(text)) != NULL) + fail("Post-finishing XML_GetBuffer not faulted"); +} +END_TEST + + static Suite * make_suite(void) { @@ -4392,6 +4403,7 @@ make_suite(void) TCase *tc_namespace = tcase_create("XML namespaces"); TCase *tc_misc = tcase_create("miscellaneous tests"); TCase *tc_alloc = tcase_create("allocation tests"); + TCase *tc_nsalloc = tcase_create("namespace allocattion tests"); suite_add_tcase(s, tc_basic); tcase_add_checked_fixture(tc_basic, basic_setup, basic_teardown); @@ -4503,9 +4515,7 @@ make_suite(void) tcase_add_checked_fixture(tc_misc, NULL, basic_teardown); tcase_add_test(tc_misc, test_misc_alloc_create_parser); tcase_add_test(tc_misc, test_misc_alloc_create_parser_with_encoding); - tcase_add_test(tc_misc, test_misc_alloc_ns); tcase_add_test(tc_misc, test_misc_null_parser); - tcase_add_test(tc_misc, test_misc_alloc_ns_parse_buffer); tcase_add_test(tc_misc, test_misc_error_string); tcase_add_test(tc_misc, test_misc_version); tcase_add_test(tc_misc, test_misc_attribute_leak); @@ -4526,6 +4536,11 @@ make_suite(void) tcase_add_test(tc_alloc, test_alloc_explicit_encoding); tcase_add_test(tc_alloc, test_alloc_set_base); + suite_add_tcase(s, tc_nsalloc); + tcase_add_checked_fixture(tc_nsalloc, nsalloc_setup, nsalloc_teardown); + tcase_add_test(tc_nsalloc, test_nsalloc_xmlns); + tcase_add_test(tc_nsalloc, test_nsalloc_parse_buffer); + return s; } From edfcd16b98ca4f3c33f01e459421052a37d15433 Mon Sep 17 00:00:00 2001 From: Rhodri James Date: Thu, 16 Feb 2017 17:44:53 +0000 Subject: [PATCH 21/54] Test long namespace names (1024 characters) --- expat/tests/runtests.c | 92 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/expat/tests/runtests.c b/expat/tests/runtests.c index 68621e5c..f351d2bf 100644 --- a/expat/tests/runtests.c +++ b/expat/tests/runtests.c @@ -4394,6 +4394,97 @@ START_TEST(test_nsalloc_parse_buffer) } END_TEST +/* Check handling of long prefix names (pool growth) */ +START_TEST(test_nsalloc_long_prefix) +{ + const char *text = + "<" + /* 64 characters per line */ + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ" + ":foo xmlns:" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ" + "='http://example.com/'>" + ""; + int i; +#define MAX_ALLOC_COUNT 10 + int repeated = 0; + + for (i = 0; i < MAX_ALLOC_COUNT; i++) { + /* Repeat some tests with the same allocation count to + * catch cached allocations not freed by XML_ParserReset() + */ + if ((i == 4 && repeated == 3) || + (i == 4 && repeated == 6)) { + i -= 2; + repeated++; + } + else if ((i == 2 && repeated < 2) || + (i == 3 && repeated < 3) || + (i == 3 && repeated > 3 && repeated < 6) || + (i == 3 && repeated > 6 && repeated < 9)) { + i--; + repeated++; + } + allocation_count = i; + if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), + XML_TRUE) != XML_STATUS_ERROR) + break; + XML_ParserReset(parser, NULL); + } + if (i == 0) + fail("Parsing worked despite failing allocations"); + else if (i == MAX_ALLOC_COUNT) + fail("Parsing failed even at max allocation count"); +} +#undef MAX_ALLOC_COUNT +END_TEST static Suite * make_suite(void) @@ -4540,6 +4631,7 @@ make_suite(void) tcase_add_checked_fixture(tc_nsalloc, nsalloc_setup, nsalloc_teardown); tcase_add_test(tc_nsalloc, test_nsalloc_xmlns); tcase_add_test(tc_nsalloc, test_nsalloc_parse_buffer); + tcase_add_test(tc_nsalloc, test_nsalloc_long_prefix); return s; } From 9f844cac4a24abe1765323aaf5c2f8aafd141474 Mon Sep 17 00:00:00 2001 From: Rhodri James Date: Fri, 17 Feb 2017 12:01:30 +0000 Subject: [PATCH 22/54] Revert recorded size of attribute memory when reallocation fails --- expat/lib/xmlparse.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/expat/lib/xmlparse.c b/expat/lib/xmlparse.c index c430541f..00f4b7bd 100644 --- a/expat/lib/xmlparse.c +++ b/expat/lib/xmlparse.c @@ -3117,13 +3117,17 @@ storeAtts(XML_Parser parser, const ENCODING *enc, #endif attsSize = n + nDefaultAtts + INIT_ATTS_SIZE; temp = (ATTRIBUTE *)REALLOC((void *)atts, attsSize * sizeof(ATTRIBUTE)); - if (temp == NULL) + if (temp == NULL) { + attsSize = oldAttsSize; return XML_ERROR_NO_MEMORY; + } atts = temp; #ifdef XML_ATTR_INFO temp2 = (XML_AttrInfo *)REALLOC((void *)attInfo, attsSize * sizeof(XML_AttrInfo)); - if (temp2 == NULL) + if (temp2 == NULL) { + attsSize = oldAttsSize; return XML_ERROR_NO_MEMORY; + } attInfo = temp2; #endif if (n > oldAttsSize) From f748d87811b77afa5cd856bde5e60a26682b0c57 Mon Sep 17 00:00:00 2001 From: Rhodri James Date: Fri, 17 Feb 2017 15:18:34 +0000 Subject: [PATCH 23/54] Test rejection of unbound prefix, improve coverage of attribute handling --- expat/tests/runtests.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/expat/tests/runtests.c b/expat/tests/runtests.c index f351d2bf..e007bdae 100644 --- a/expat/tests/runtests.c +++ b/expat/tests/runtests.c @@ -3376,6 +3376,25 @@ START_TEST(test_ns_prefix_with_empty_uri_4) } END_TEST +/* Test with non-xmlns prefix */ +START_TEST(test_ns_unbound_prefix) +{ + const char *text = + "\n" + " \n" + "]>\n" + ""; + + if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), + XML_TRUE) != XML_STATUS_ERROR) + fail("Unbound prefix incorrectly passed"); + if (XML_GetErrorCode(parser) != XML_ERROR_UNBOUND_PREFIX) + xml_failure(parser); +} +END_TEST + START_TEST(test_ns_default_with_empty_uri) { const char *text = @@ -4595,6 +4614,7 @@ make_suite(void) tcase_add_test(tc_namespace, test_ns_prefix_with_empty_uri_2); tcase_add_test(tc_namespace, test_ns_prefix_with_empty_uri_3); tcase_add_test(tc_namespace, test_ns_prefix_with_empty_uri_4); + tcase_add_test(tc_namespace, test_ns_unbound_prefix); tcase_add_test(tc_namespace, test_ns_default_with_empty_uri); tcase_add_test(tc_namespace, test_ns_duplicate_attrs_diff_prefixes); tcase_add_test(tc_namespace, test_ns_unbound_prefix_on_attribute); From 41ab4fd94ad1ef48f0fb5272f5ee0eb5b4ec24f2 Mon Sep 17 00:00:00 2001 From: Rhodri James Date: Fri, 17 Feb 2017 16:21:17 +0000 Subject: [PATCH 24/54] Test reallocation failure in xmlns attribute handling Note that this commit provokes a segfault due to a bug in storeAtts() --- expat/tests/runtests.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/expat/tests/runtests.c b/expat/tests/runtests.c index e007bdae..1011510e 100644 --- a/expat/tests/runtests.c +++ b/expat/tests/runtests.c @@ -4505,6 +4505,32 @@ START_TEST(test_nsalloc_long_prefix) #undef MAX_ALLOC_COUNT END_TEST +/* Test attribute handling in the face of a dodgy reallocator */ +START_TEST(test_nsalloc_realloc_attributes) +{ + const char *text = + "" + ""; + int i; +#define MAX_REALLOC_COUNT 10 + + for (i = 0; i < MAX_REALLOC_COUNT; i++) { + reallocation_count = i; + if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), + XML_TRUE) != XML_STATUS_ERROR) + break; + XML_ParserReset(parser, NULL); + } + if (i == 0) + fail("Parsing worked despite failing reallocations"); + else if (i == MAX_REALLOC_COUNT) + fail("Parsing failed at max reallocation count"); +} +#undef MAX_REALLOC_COUNT +END_TEST + + static Suite * make_suite(void) { @@ -4652,6 +4678,7 @@ make_suite(void) tcase_add_test(tc_nsalloc, test_nsalloc_xmlns); tcase_add_test(tc_nsalloc, test_nsalloc_parse_buffer); tcase_add_test(tc_nsalloc, test_nsalloc_long_prefix); + tcase_add_test(tc_nsalloc, test_nsalloc_realloc_attributes); return s; } From c90f4bc24cdc3b698d2147d851513bcfc98c31cd Mon Sep 17 00:00:00 2001 From: Rhodri James Date: Fri, 17 Feb 2017 16:32:21 +0000 Subject: [PATCH 25/54] Restore original nsAttsSize if reallocation fails --- expat/lib/xmlparse.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/expat/lib/xmlparse.c b/expat/lib/xmlparse.c index 00f4b7bd..fd08b4ec 100644 --- a/expat/lib/xmlparse.c +++ b/expat/lib/xmlparse.c @@ -3264,6 +3264,7 @@ storeAtts(XML_Parser parser, const ENCODING *enc, int j; /* hash table index */ unsigned long version = nsAttsVersion; int nsAttsSize = (int)1 << nsAttsPower; + unsigned char oldNsAttsPower = nsAttsPower; /* size of hash table must be at least 2 * (# of prefixed attributes) */ if ((nPrefixes << 1) >> nsAttsPower) { /* true for nsAttsPower = 0 */ NS_ATT *temp; @@ -3273,8 +3274,11 @@ storeAtts(XML_Parser parser, const ENCODING *enc, nsAttsPower = 3; nsAttsSize = (int)1 << nsAttsPower; temp = (NS_ATT *)REALLOC(nsAtts, nsAttsSize * sizeof(NS_ATT)); - if (!temp) + if (!temp) { + /* Restore actual size of memory in nsAtts */ + nsAttsPower = oldNsAttsPower; return XML_ERROR_NO_MEMORY; + } nsAtts = temp; version = 0; /* force re-initialization of nsAtts hash table */ } From 53e1698aa3d23c6de39ea7a3f30ca417c6d343e8 Mon Sep 17 00:00:00 2001 From: Rhodri James Date: Fri, 17 Feb 2017 18:58:08 +0000 Subject: [PATCH 26/54] Add test case for long URIs in attributes with failing allocator --- expat/tests/runtests.c | 76 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/expat/tests/runtests.c b/expat/tests/runtests.c index 1011510e..d971cbe6 100644 --- a/expat/tests/runtests.c +++ b/expat/tests/runtests.c @@ -4505,6 +4505,81 @@ START_TEST(test_nsalloc_long_prefix) #undef MAX_ALLOC_COUNT END_TEST +/* Check handling of long uri names (pool growth) */ +START_TEST(test_nsalloc_long_uri) +{ + const char *text = + "" + ""; + int i; +#define MAX_ALLOC_COUNT 15 + int repeated = 0; + + for (i = 0; i < MAX_ALLOC_COUNT; i++) { + /* Repeat some tests with the same allocation count to + * catch cached allocations not freed by XML_ParserReset() + */ + if ((i == 3 && repeated == 1) || + (i == 6 && repeated == 4)) { + i -= 2; + repeated++; + } + else if ((i == 2 && (repeated == 0 || repeated == 2)) || + (i == 4 && repeated == 3) || + (i == 8 && repeated == 5)) { + i--; + repeated++; + } + allocation_count = i; + if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), + XML_TRUE) != XML_STATUS_ERROR) + break; + XML_ParserReset(parser, NULL); + } + if (i == 0) + fail("Parsing worked despite failing allocations"); + else if (i == MAX_ALLOC_COUNT) + fail("Parsing failed even at max allocation count"); +} +#undef MAX_ALLOC_COUNT +END_TEST + /* Test attribute handling in the face of a dodgy reallocator */ START_TEST(test_nsalloc_realloc_attributes) { @@ -4678,6 +4753,7 @@ make_suite(void) tcase_add_test(tc_nsalloc, test_nsalloc_xmlns); tcase_add_test(tc_nsalloc, test_nsalloc_parse_buffer); tcase_add_test(tc_nsalloc, test_nsalloc_long_prefix); + tcase_add_test(tc_nsalloc, test_nsalloc_long_uri); tcase_add_test(tc_nsalloc, test_nsalloc_realloc_attributes); return s; From 894033fab8487164d7e2f20141bca8ad75d28311 Mon Sep 17 00:00:00 2001 From: Rhodri James Date: Tue, 21 Feb 2017 15:29:31 +0000 Subject: [PATCH 27/54] Fix structure initialisation not to cause warnings --- expat/tests/runtests.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/expat/tests/runtests.c b/expat/tests/runtests.c index d971cbe6..c4b461e8 100644 --- a/expat/tests/runtests.c +++ b/expat/tests/runtests.c @@ -2031,6 +2031,12 @@ START_TEST(test_attributes) info[0].attributes = doc_info; info[1].attributes = tag_info; + /* Silence some warnings: doc_info and tag_info are not computable + * at load time, making the variable initialisation harder. + */ + info[0].attributes = doc_info; + info[1].attributes = tag_info; + XML_SetStartElementHandler(parser, counting_start_element_handler); XML_SetUserData(parser, info); if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR) From 1056c797dd795b8d82838f6112be77849da46aa1 Mon Sep 17 00:00:00 2001 From: Rhodri James Date: Tue, 21 Feb 2017 16:26:58 +0000 Subject: [PATCH 28/54] Test for specific error from XML_UseForeignDTD() --- expat/tests/runtests.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/expat/tests/runtests.c b/expat/tests/runtests.c index c4b461e8..bda2e6b3 100644 --- a/expat/tests/runtests.c +++ b/expat/tests/runtests.c @@ -1908,7 +1908,8 @@ START_TEST(test_set_foreign_dtd) /* Ensure that trying to set the DTD after parsing has started * is faulted, even if it's the same setting. */ - if (XML_UseForeignDTD(parser, XML_TRUE) == XML_ERROR_NONE) + if (XML_UseForeignDTD(parser, XML_TRUE) != + XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING) fail("Failed to reject late foreign DTD setting"); /* Ditto for the hash salt */ if (XML_SetHashSalt(parser, 0x23456789)) From b1bea335822c02c12b410fd57c51b9160ac8ff94 Mon Sep 17 00:00:00 2001 From: Rhodri James Date: Tue, 21 Feb 2017 16:33:01 +0000 Subject: [PATCH 29/54] Check NULLing the encoding works before the parse is started --- expat/tests/runtests.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/expat/tests/runtests.c b/expat/tests/runtests.c index bda2e6b3..a3befc85 100644 --- a/expat/tests/runtests.c +++ b/expat/tests/runtests.c @@ -2394,7 +2394,10 @@ START_TEST(test_explicit_encoding) const char *text1 = "Hello "; const char *text2 = " World"; - /* First say we are UTF-8 */ + /* Just check that we can set the encoding to NULL before starting */ + if (XML_SetEncoding(parser, NULL) != XML_STATUS_OK) + fail("Failed to initialise encoding to NULL"); + /* Say we are UTF-8 */ if (XML_SetEncoding(parser, "utf-8") != XML_STATUS_OK) fail("Failed to set explicit encoding"); if (_XML_Parse_SINGLE_BYTES(parser, text1, strlen(text1), From d69a504a5a4f4a11cde04d63243ad30a75de33e4 Mon Sep 17 00:00:00 2001 From: Rhodri James Date: Tue, 21 Feb 2017 17:24:39 +0000 Subject: [PATCH 30/54] Comment change: explain why attribute count is twice what you expect --- expat/tests/runtests.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/expat/tests/runtests.c b/expat/tests/runtests.c index a3befc85..0542f9ad 100644 --- a/expat/tests/runtests.c +++ b/expat/tests/runtests.c @@ -1970,7 +1970,12 @@ counting_start_element_handler(void *userData, } if (info->name == NULL) fail("Element not recognised"); - /* Note attribute count is doubled */ + /* The attribute count is twice what you might expect. It is a + * count of items in atts, an array which contains alternating + * attribute names and attribute values. For the naive user this + * is possibly a little unexpected, but it is what the + * documentation in expat.h tells us to expect. + */ count = XML_GetSpecifiedAttributeCount(parser); if (info->attr_count * 2 != count) { fail("Not got expected attribute count"); @@ -2000,6 +2005,7 @@ counting_start_element_handler(void *userData, fail("Attribute has wrong value"); return; } + /* Remember, two entries in atts per attribute (see above) */ atts += 2; } } From ade4c402af1d282edb819fbc956ff0bb32ac2c33 Mon Sep 17 00:00:00 2001 From: Rhodri James Date: Tue, 21 Feb 2017 18:25:41 +0000 Subject: [PATCH 31/54] Extend test coverage of external entity handler parameters --- expat/tests/runtests.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/expat/tests/runtests.c b/expat/tests/runtests.c index 0542f9ad..d6a004b6 100644 --- a/expat/tests/runtests.c +++ b/expat/tests/runtests.c @@ -2750,16 +2750,34 @@ END_TEST /* Test that an explicit external entity handler argument replaces * the parser as the first argument. + * + * We do not call the first parameter to the external entity handler + * 'parser' for once, since the first time the handler is called it + * will actually be a text string. We need to be able to access the + * global 'parser' variable to create our external entity parser from, + * since there are code paths we need to ensure get executed. */ static int XMLCALL -external_entity_ref_param_checker(XML_Parser parser, - const XML_Char *UNUSED_P(context), +external_entity_ref_param_checker(XML_Parser parameter, + const XML_Char *context, const XML_Char *UNUSED_P(base), const XML_Char *UNUSED_P(systemId), const XML_Char *UNUSED_P(publicId)) { - if ((void *)parser != handler_data) + const char *text = ""; + XML_Parser ext_parser; + + if ((void *)parameter != handler_data) fail("External entity ref handler parameter not correct"); + + /* Here we use the global 'parser' variable */ + ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL); + if (ext_parser == NULL) + fail("Could not create external entity parser"); + if (_XML_Parse_SINGLE_BYTES(ext_parser, text, strlen(text), + XML_TRUE) == XML_STATUS_ERROR) + xml_failure(ext_parser); + return XML_STATUS_OK; } From d526cd09f78eda8d1f4c28225bdd6d86a6fbfc3c Mon Sep 17 00:00:00 2001 From: Rhodri James Date: Tue, 21 Feb 2017 19:36:07 +0000 Subject: [PATCH 32/54] Test long attribute names in a namespace with failing allocator --- expat/tests/runtests.c | 62 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/expat/tests/runtests.c b/expat/tests/runtests.c index d6a004b6..4ab5eaae 100644 --- a/expat/tests/runtests.c +++ b/expat/tests/runtests.c @@ -4614,6 +4614,67 @@ START_TEST(test_nsalloc_long_uri) #undef MAX_ALLOC_COUNT END_TEST +/* Test handling of long attribute names with prefixes */ +START_TEST(test_nsalloc_long_attr) +{ + const char *text = + "" + ""; + int i; +#define MAX_ALLOC_COUNT 20 + int repeated = 0; + + for (i = 0; i < MAX_ALLOC_COUNT; i++) { + /* Repeat some tests with the same allocation count to + * catch cached allocation not freed by XML_ParserReset() + */ + if ((i == 4 && repeated < 6) || + (i == 7 && repeated == 8) || + (i == 10 && repeated == 10)) { + i -= 2; + repeated++; + } + else if ((i == 2 && repeated < 2) || + (i == 3 && + (repeated == 2 || repeated == 4 || repeated == 6)) || + (i == 5 && repeated == 7) || + (i == 6 && repeated == 9)) { + i--; + repeated++; + } + allocation_count = i; + if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), + XML_TRUE) != XML_STATUS_ERROR) + break; + XML_ParserReset(parser, NULL); + } + if (i == 0) + fail("Parsing worked despite failing allocations"); + else if (i == MAX_ALLOC_COUNT) + fail("Parsing failed even at max allocation count"); +} +#undef MAX_ALLOC_COUNT +END_TEST + /* Test attribute handling in the face of a dodgy reallocator */ START_TEST(test_nsalloc_realloc_attributes) { @@ -4788,6 +4849,7 @@ make_suite(void) tcase_add_test(tc_nsalloc, test_nsalloc_parse_buffer); tcase_add_test(tc_nsalloc, test_nsalloc_long_prefix); tcase_add_test(tc_nsalloc, test_nsalloc_long_uri); + tcase_add_test(tc_nsalloc, test_nsalloc_long_attr); tcase_add_test(tc_nsalloc, test_nsalloc_realloc_attributes); return s; From 1c0ecf1b95022a19ff11fc9342b7503709c8b6fe Mon Sep 17 00:00:00 2001 From: Rhodri James Date: Wed, 22 Feb 2017 15:14:50 +0000 Subject: [PATCH 33/54] Test attribute table hash collision handling --- expat/tests/runtests.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/expat/tests/runtests.c b/expat/tests/runtests.c index 4ab5eaae..45d22c23 100644 --- a/expat/tests/runtests.c +++ b/expat/tests/runtests.c @@ -3458,6 +3458,33 @@ START_TEST(test_ns_duplicate_attrs_diff_prefixes) } END_TEST +START_TEST(test_ns_duplicate_hashes) +{ + /* The hash of an attribute is calculated as the hash of its URI + * concatenated with a space followed by its name (after the + * colon). We wish to generate attributes with the same hash + * value modulo the attribute table size so that we can check that + * the attribute hash table works correctly. The attribute hash + * table size will be the smallest power of two greater than the + * number of attributes, but at least eight. There is + * unfortunately no programmatic way of getting the hash or the + * table size at user level, but the test code coverage percentage + * will drop if the hashes cease to point to the same row. + * + * The cunning plan is to have few enough attributes to have a + * reliable table size of 8, and have the single letter attribute + * names be 8 characters apart, producing a hash which will be the + * same modulo 8. + */ + const char *text = + ""; + if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), + XML_TRUE) == XML_STATUS_ERROR) + xml_failure(parser); +} +END_TEST + /* Regression test for SF bug #695401: unbound prefix. */ START_TEST(test_ns_unbound_prefix_on_attribute) { @@ -4813,6 +4840,7 @@ make_suite(void) tcase_add_test(tc_namespace, test_ns_unbound_prefix); tcase_add_test(tc_namespace, test_ns_default_with_empty_uri); tcase_add_test(tc_namespace, test_ns_duplicate_attrs_diff_prefixes); + tcase_add_test(tc_namespace, test_ns_duplicate_hashes); tcase_add_test(tc_namespace, test_ns_unbound_prefix_on_attribute); tcase_add_test(tc_namespace, test_ns_unbound_prefix_on_element); tcase_add_test(tc_namespace, test_ns_parser_reset); From 8eda8b3c9e23afa45ef92db0405994a083ed461d Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Sun, 16 Jul 2017 18:58:21 +0200 Subject: [PATCH 34/54] runtests.c: Fix memleaks --- expat/tests/runtests.c | 1 + 1 file changed, 1 insertion(+) diff --git a/expat/tests/runtests.c b/expat/tests/runtests.c index 45d22c23..7fa3e798 100644 --- a/expat/tests/runtests.c +++ b/expat/tests/runtests.c @@ -2778,6 +2778,7 @@ external_entity_ref_param_checker(XML_Parser parameter, XML_TRUE) == XML_STATUS_ERROR) xml_failure(ext_parser); + XML_ParserFree(ext_parser); return XML_STATUS_OK; } From cbfc54ee2f539abc96c28392e7c0de1c73586b55 Mon Sep 17 00:00:00 2001 From: Rhodri James Date: Wed, 22 Feb 2017 16:24:18 +0000 Subject: [PATCH 35/54] Test allocator handling of attribute with long namespace --- expat/tests/runtests.c | 107 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) diff --git a/expat/tests/runtests.c b/expat/tests/runtests.c index 7fa3e798..600f60b9 100644 --- a/expat/tests/runtests.c +++ b/expat/tests/runtests.c @@ -4703,6 +4703,112 @@ START_TEST(test_nsalloc_long_attr) #undef MAX_ALLOC_COUNT END_TEST +/* Test handling of an attribute name with a long namespace prefix */ +START_TEST(test_nsalloc_long_attr_prefix) +{ + const char *text = + "" + ""; + const char *elemstr[] = { + "http://example.org/ e foo", + "http://example.org/ a " + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ" + }; + int i; +#define MAX_ALLOC_COUNT 15 + int repeated = 0; + + for (i = 0; i < MAX_ALLOC_COUNT; i++) { + /* Repeat some counts to flush out cached allocations */ + if ((i == 4 && (repeated == 3 || repeated == 6)) || + (i == 7 && repeated == 9) || + (i == 10 && repeated == 12)) { + i -= 2; + repeated++; + } + else if ((i == 2 && repeated < 2) || + (i == 3 && + (repeated == 2 || + repeated == 4 || + repeated == 5 || + repeated == 7)) || + (i == 5 && repeated == 8) || + (i == 6 && repeated == 10) || + (i == 8 && repeated == 11)) { + i--; + repeated++; + } + allocation_count = i; + XML_SetReturnNSTriplet(parser, XML_TRUE); + XML_SetUserData(parser, elemstr); + XML_SetElementHandler(parser, + triplet_start_checker, + triplet_end_checker); + if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), + XML_TRUE) != XML_STATUS_ERROR) + break; + XML_ParserReset(parser, NULL); + } + if (i == 0) + fail("Parsing worked despite failing allocations"); + else if (i == MAX_ALLOC_COUNT) + fail("Parsing failed even at max allocation count"); +} +#undef MAX_ALLOC_COUNT +END_TEST + /* Test attribute handling in the face of a dodgy reallocator */ START_TEST(test_nsalloc_realloc_attributes) { @@ -4879,6 +4985,7 @@ make_suite(void) tcase_add_test(tc_nsalloc, test_nsalloc_long_prefix); tcase_add_test(tc_nsalloc, test_nsalloc_long_uri); tcase_add_test(tc_nsalloc, test_nsalloc_long_attr); + tcase_add_test(tc_nsalloc, test_nsalloc_long_attr_prefix); tcase_add_test(tc_nsalloc, test_nsalloc_realloc_attributes); return s; From ea6ab8be03dd1c12fdd4a6b59fcc3c389e466730 Mon Sep 17 00:00:00 2001 From: Rhodri James Date: Wed, 22 Feb 2017 16:54:35 +0000 Subject: [PATCH 36/54] Test mixed prefixed and unprefixed attributes in a namespace --- expat/tests/runtests.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/expat/tests/runtests.c b/expat/tests/runtests.c index 600f60b9..a5f8a180 100644 --- a/expat/tests/runtests.c +++ b/expat/tests/runtests.c @@ -3553,6 +3553,20 @@ START_TEST(test_ns_long_element) } END_TEST +/* Test mixed population of prefixed and unprefixed attributes */ +START_TEST(test_ns_mixed_prefix_atts) +{ + const char *text = + "" + ""; + + if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), + XML_TRUE) == XML_STATUS_ERROR) + xml_failure(parser); +} +END_TEST + /* Control variable; the number of times duff_allocator() will successfully allocate */ #define ALLOC_ALWAYS_SUCCEED (-1) @@ -4952,6 +4966,7 @@ make_suite(void) tcase_add_test(tc_namespace, test_ns_unbound_prefix_on_element); tcase_add_test(tc_namespace, test_ns_parser_reset); tcase_add_test(tc_namespace, test_ns_long_element); + tcase_add_test(tc_namespace, test_ns_mixed_prefix_atts); suite_add_tcase(s, tc_misc); tcase_add_checked_fixture(tc_misc, NULL, basic_teardown); From d8651ffbe85f7ae5c02197ddd7feeae13fd27883 Mon Sep 17 00:00:00 2001 From: Rhodri James Date: Wed, 22 Feb 2017 17:49:11 +0000 Subject: [PATCH 37/54] Test medium-length element name with namespaces and a failing allocator --- expat/tests/runtests.c | 54 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/expat/tests/runtests.c b/expat/tests/runtests.c index a5f8a180..7e06284f 100644 --- a/expat/tests/runtests.c +++ b/expat/tests/runtests.c @@ -4848,6 +4848,59 @@ START_TEST(test_nsalloc_realloc_attributes) #undef MAX_REALLOC_COUNT END_TEST +/* Test long element names with namespaces under a failing allocator */ +START_TEST(test_nsalloc_long_element) +{ + const char *text = + "" + ""; + const char *elemstr[] = { + "http://example.org/" + " thisisalongenoughelementnametotriggerareallocation foo", + "http://example.org/ a bar" + }; + int i; +#define MAX_ALLOC_COUNT 15 + int repeated = 0; + + for (i = 0; i < MAX_ALLOC_COUNT; i++) { + /* Repeat some allocation counts because some allocations + * get cached across XML_ParserReset() called. + */ + if ((i == 4 && (repeated == 3 || repeated == 5)) || + (i == 7 && repeated == 8) || + (i == 10 && repeated == 9)) { + i -= 2; + repeated++; + } + else if ((i == 2 && repeated < 2) || + (i == 3 && + (repeated == 2 || repeated == 4 || repeated == 6)) || + (i == 5 && repeated == 7)) { + i--; + repeated++; + } + allocation_count = i; + XML_SetReturnNSTriplet(parser, XML_TRUE); + XML_SetUserData(parser, elemstr); + XML_SetElementHandler(parser, + triplet_start_checker, + triplet_end_checker); + if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), + XML_TRUE) != XML_STATUS_ERROR) + break; + XML_ParserReset(parser, NULL); + } + if (i == 0) + fail("Parsing worked despite failing reallocations"); + else if (i == MAX_ALLOC_COUNT) + fail("Parsing failed at max reallocation count"); +} +#undef MAX_ALLOC_COUNT +END_TEST + static Suite * make_suite(void) @@ -5002,6 +5055,7 @@ make_suite(void) tcase_add_test(tc_nsalloc, test_nsalloc_long_attr); tcase_add_test(tc_nsalloc, test_nsalloc_long_attr_prefix); tcase_add_test(tc_nsalloc, test_nsalloc_realloc_attributes); + tcase_add_test(tc_nsalloc, test_nsalloc_long_element); return s; } From 1ead467e3c51da1ffa225502b39be58a3371aaf4 Mon Sep 17 00:00:00 2001 From: Rhodri James Date: Wed, 22 Feb 2017 18:41:31 +0000 Subject: [PATCH 38/54] Test extension of URI buffer shared between element tags --- expat/tests/runtests.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/expat/tests/runtests.c b/expat/tests/runtests.c index 7e06284f..dd6cd68f 100644 --- a/expat/tests/runtests.c +++ b/expat/tests/runtests.c @@ -3567,6 +3567,23 @@ START_TEST(test_ns_mixed_prefix_atts) } END_TEST +/* Test having a long namespaced element name inside a short one. + * This exercises some internal buffer reallocation that is shared + * across elements with the same namespace URI. + */ +START_TEST(test_ns_extend_uri_buffer) +{ + const char *text = + "" + " " + ""; + if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), + XML_TRUE) == XML_STATUS_ERROR) + xml_failure(parser); +} +END_TEST + /* Control variable; the number of times duff_allocator() will successfully allocate */ #define ALLOC_ALWAYS_SUCCEED (-1) @@ -5020,6 +5037,7 @@ make_suite(void) tcase_add_test(tc_namespace, test_ns_parser_reset); tcase_add_test(tc_namespace, test_ns_long_element); tcase_add_test(tc_namespace, test_ns_mixed_prefix_atts); + tcase_add_test(tc_namespace, test_ns_extend_uri_buffer); suite_add_tcase(s, tc_misc); tcase_add_checked_fixture(tc_misc, NULL, basic_teardown); From a2302df9b6917620128fb7fdaf6db51720e136c2 Mon Sep 17 00:00:00 2001 From: Rhodri James Date: Thu, 23 Feb 2017 13:31:59 +0000 Subject: [PATCH 39/54] Test for correct rejection of 'xmlns' as an attribute --- expat/tests/runtests.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/expat/tests/runtests.c b/expat/tests/runtests.c index dd6cd68f..eb7b1f85 100644 --- a/expat/tests/runtests.c +++ b/expat/tests/runtests.c @@ -3584,6 +3584,23 @@ START_TEST(test_ns_extend_uri_buffer) } END_TEST +/* Test that xmlns is correctly rejected as an attribute in the xmlns + * namespace, but not in other namespaces + */ +START_TEST(test_ns_reserved_attributes) +{ + const char *text1 = + ""; + const char *text2 = + ""; + expect_failure(text1, XML_ERROR_RESERVED_PREFIX_XMLNS, + "xmlns not rejected as an attribute"); + XML_ParserReset(parser, NULL); + if (_XML_Parse_SINGLE_BYTES(parser, text2, strlen(text2), + XML_TRUE) == XML_STATUS_ERROR) + xml_failure(parser); +} +END_TEST /* Control variable; the number of times duff_allocator() will successfully allocate */ #define ALLOC_ALWAYS_SUCCEED (-1) @@ -5038,6 +5055,7 @@ make_suite(void) tcase_add_test(tc_namespace, test_ns_long_element); tcase_add_test(tc_namespace, test_ns_mixed_prefix_atts); tcase_add_test(tc_namespace, test_ns_extend_uri_buffer); + tcase_add_test(tc_namespace, test_ns_reserved_attributes); suite_add_tcase(s, tc_misc); tcase_add_checked_fixture(tc_misc, NULL, basic_teardown); From c7d2fc3020fef0d61962ff1c51fbc65ff09996a7 Mon Sep 17 00:00:00 2001 From: Rhodri James Date: Thu, 23 Feb 2017 15:13:12 +0000 Subject: [PATCH 40/54] Test rejection of invalid attribute 'xml' and use of w3.org --- expat/tests/runtests.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/expat/tests/runtests.c b/expat/tests/runtests.c index eb7b1f85..0ecc3f0b 100644 --- a/expat/tests/runtests.c +++ b/expat/tests/runtests.c @@ -3602,6 +3602,23 @@ START_TEST(test_ns_reserved_attributes) } END_TEST +/* Test more reserved attributes */ +START_TEST(test_ns_reserved_attributes_2) +{ + const char *text1 = + ""; + const char *text2 = + ""; + + expect_failure(text1, XML_ERROR_RESERVED_PREFIX_XML, + "xml not rejected as an attribute"); + XML_ParserReset(parser, NULL); + expect_failure(text2, XML_ERROR_RESERVED_NAMESPACE_URI, + "Use of w3.org URL not faulted"); +} +END_TEST + /* Control variable; the number of times duff_allocator() will successfully allocate */ #define ALLOC_ALWAYS_SUCCEED (-1) #define REALLOC_ALWAYS_SUCCEED (-1) @@ -5056,6 +5073,7 @@ make_suite(void) tcase_add_test(tc_namespace, test_ns_mixed_prefix_atts); tcase_add_test(tc_namespace, test_ns_extend_uri_buffer); tcase_add_test(tc_namespace, test_ns_reserved_attributes); + tcase_add_test(tc_namespace, test_ns_reserved_attributes_2); suite_add_tcase(s, tc_misc); tcase_add_checked_fixture(tc_misc, NULL, basic_teardown); From 757ac4cb0e2b2a0c4729ef86ae1c6f1c6f9544d5 Mon Sep 17 00:00:00 2001 From: Rhodri James Date: Thu, 23 Feb 2017 15:22:40 +0000 Subject: [PATCH 41/54] Test w3.org xmlns URL is correctly rejected --- expat/tests/runtests.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/expat/tests/runtests.c b/expat/tests/runtests.c index 0ecc3f0b..856b275a 100644 --- a/expat/tests/runtests.c +++ b/expat/tests/runtests.c @@ -3610,12 +3610,17 @@ START_TEST(test_ns_reserved_attributes_2) " xmlns:xml='http://example.org/' />"; const char *text2 = ""; + const char *text3 = + ""; expect_failure(text1, XML_ERROR_RESERVED_PREFIX_XML, "xml not rejected as an attribute"); XML_ParserReset(parser, NULL); expect_failure(text2, XML_ERROR_RESERVED_NAMESPACE_URI, "Use of w3.org URL not faulted"); + XML_ParserReset(parser, NULL); + expect_failure(text3, XML_ERROR_RESERVED_NAMESPACE_URI, + "Use of w3.org xmlns URL not faulted"); } END_TEST From 47003df13df4f75922e57e4666f03ec43baae0b3 Mon Sep 17 00:00:00 2001 From: Rhodri James Date: Thu, 23 Feb 2017 16:04:12 +0000 Subject: [PATCH 42/54] Test reallocation of URI in re-used binding with dodgy reallocator --- expat/tests/runtests.c | 45 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/expat/tests/runtests.c b/expat/tests/runtests.c index 856b275a..75591357 100644 --- a/expat/tests/runtests.c +++ b/expat/tests/runtests.c @@ -4957,6 +4957,50 @@ START_TEST(test_nsalloc_long_element) #undef MAX_ALLOC_COUNT END_TEST +/* Test the effects of reallocation failure when reassigning a + * binding. + * + * XML_ParserReset does not free the BINDING structures used by a + * parser, but instead adds them to an internal free list to be reused + * as necessary. Likewise the URI buffers allocated for the binding + * aren't freed, but kept attached to their existing binding. If the + * new binding has a longer URI, it will need reallocation. This test + * provokes that reallocation, and tests the control path if it fails. + */ +START_TEST(test_nsalloc_realloc_binding_uri) +{ + const char *first = + "\n" + " \n" + ""; + const char *second = + "\n" + " \n" + ""; + unsigned i; +#define MAX_REALLOC_COUNT 10 + + /* First, do a full parse that will leave bindings around */ + if (_XML_Parse_SINGLE_BYTES(parser, first, strlen(first), + XML_TRUE) == XML_STATUS_ERROR) + xml_failure(parser); + + /* Now repeat with a longer URI and a duff reallocator */ + for (i = 0; i < MAX_REALLOC_COUNT; i++) { + XML_ParserReset(parser, NULL); + reallocation_count = i; + if (_XML_Parse_SINGLE_BYTES(parser, second, strlen(second), + XML_TRUE) != XML_STATUS_ERROR) + break; + } + if (i == 0) + fail("Parsing worked despite failing reallocation"); + else if (i == MAX_REALLOC_COUNT) + fail("Parsing failed at max reallocation count"); +} +#undef MAX_REALLOC_COUNT +END_TEST + static Suite * make_suite(void) @@ -5115,6 +5159,7 @@ make_suite(void) tcase_add_test(tc_nsalloc, test_nsalloc_long_attr_prefix); tcase_add_test(tc_nsalloc, test_nsalloc_realloc_attributes); tcase_add_test(tc_nsalloc, test_nsalloc_long_element); + tcase_add_test(tc_nsalloc, test_nsalloc_realloc_binding_uri); return s; } From b86bec407b95f1f594cac0150cd82aae032be7a6 Mon Sep 17 00:00:00 2001 From: Rhodri James Date: Thu, 23 Feb 2017 16:57:12 +0000 Subject: [PATCH 43/54] Test handling of CDATA in an external entity parser --- expat/tests/runtests.c | 47 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/expat/tests/runtests.c b/expat/tests/runtests.c index 75591357..407c65d3 100644 --- a/expat/tests/runtests.c +++ b/expat/tests/runtests.c @@ -2635,6 +2635,52 @@ START_TEST(test_ext_entity_trailing_rsqb) } END_TEST +/* Test CDATA handling in an external entity */ +static int XMLCALL +external_entity_good_cdata_ascii(XML_Parser parser, + const XML_Char *context, + const XML_Char *UNUSED_P(base), + const XML_Char *UNUSED_P(systemId), + const XML_Char *UNUSED_P(publicId)) +{ + const char *text = + "Hello, world!]]>"; + const char *expected = "Hello, world!"; + CharData storage; + XML_Parser ext_parser; + + CharData_Init(&storage); + ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL); + if (ext_parser == NULL) + fail("Could not create external entity parser"); + XML_SetUserData(ext_parser, &storage); + XML_SetCharacterDataHandler(ext_parser, accumulate_characters); + + if (_XML_Parse_SINGLE_BYTES(ext_parser, text, strlen(text), + XML_TRUE) == XML_STATUS_ERROR) + xml_failure(ext_parser); + CharData_CheckXMLChars(&storage, expected); + + return XML_STATUS_OK; +} + +START_TEST(test_ext_entity_good_cdata) +{ + const char *text = + "\n" + "]>\n" + "&en;"; + + XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS); + XML_SetExternalEntityRefHandler(parser, + external_entity_good_cdata_ascii); + if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), + XML_TRUE) != XML_STATUS_OK) + xml_failure(parser); +} +END_TEST + /* Test user parameter settings */ /* Variable holding the expected handler userData */ static void *handler_data = NULL; @@ -5089,6 +5135,7 @@ make_suite(void) tcase_add_test(tc_basic, test_ext_entity_trailing_cr); tcase_add_test(tc_basic, test_trailing_rsqb); tcase_add_test(tc_basic, test_ext_entity_trailing_rsqb); + tcase_add_test(tc_basic, test_ext_entity_good_cdata); tcase_add_test(tc_basic, test_user_parameters); tcase_add_test(tc_basic, test_ext_entity_ref_parameter); tcase_add_test(tc_basic, test_empty_parse); From fa37a8069a27fb674584b8b2bca8fbc3aadbdf08 Mon Sep 17 00:00:00 2001 From: Rhodri James Date: Thu, 23 Feb 2017 17:48:39 +0000 Subject: [PATCH 44/54] Test CDATA correctly runs through a default handler In particular exercises a code path dealing with newlines --- expat/tests/runtests.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/expat/tests/runtests.c b/expat/tests/runtests.c index 407c65d3..53466cc3 100644 --- a/expat/tests/runtests.c +++ b/expat/tests/runtests.c @@ -2116,6 +2116,23 @@ START_TEST(test_resume_resuspended) } END_TEST +/* Test that CDATA shows up correctly through a default handler */ +START_TEST(test_cdata_default) +{ + const char *text = ""; + CharData storage; + + CharData_Init(&storage); + XML_SetUserData(parser, &storage); + XML_SetDefaultHandler(parser, accumulate_characters); + + if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), + XML_TRUE) == XML_STATUS_ERROR) + xml_failure(parser); + CharData_CheckXMLChars(&storage, text); +} +END_TEST + /* Test resetting a subordinate parser does exactly nothing */ static int XMLCALL external_entity_resetter(XML_Parser parser, @@ -5126,6 +5143,7 @@ make_suite(void) tcase_add_test(tc_basic, test_reset_in_entity); tcase_add_test(tc_basic, test_resume_invalid_parse); tcase_add_test(tc_basic, test_resume_resuspended); + tcase_add_test(tc_basic, test_cdata_default); tcase_add_test(tc_basic, test_subordinate_reset); tcase_add_test(tc_basic, test_subordinate_suspend); tcase_add_test(tc_basic, test_subordinate_xdecl_suspend); From e932825e22507085a6e424d4b0dcd0f44b5a015d Mon Sep 17 00:00:00 2001 From: Rhodri James Date: Fri, 24 Feb 2017 13:12:41 +0000 Subject: [PATCH 45/54] Test long UTF-16 CDATA (more than internal buffer size) --- expat/tests/chardata.h | 2 +- expat/tests/runtests.c | 74 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 1 deletion(-) diff --git a/expat/tests/chardata.h b/expat/tests/chardata.h index e8dc4ce2..0db4b999 100644 --- a/expat/tests/chardata.h +++ b/expat/tests/chardata.h @@ -18,7 +18,7 @@ extern "C" { typedef struct { int count; /* # of chars, < 0 if not set */ - XML_Char data[1024]; + XML_Char data[2048]; } CharData; diff --git a/expat/tests/runtests.c b/expat/tests/runtests.c index 53466cc3..22a51ad2 100644 --- a/expat/tests/runtests.c +++ b/expat/tests/runtests.c @@ -1685,6 +1685,79 @@ START_TEST(test_good_cdata_utf16) } END_TEST +/* Test UTF16 conversion of a long cdata string */ + +/* 16 characters: handy macro to reduce visual clutter */ +#define A_TO_P_IN_UTF16 "\0A\0B\0C\0D\0E\0F\0G\0H\0I\0J\0K\0L\0M\0N\0O\0P" + +START_TEST(test_long_cdata_utf16) +{ + /* Test data is: + * + * + */ + const char text[] = + "\0<\0?\0x\0m\0l\0 " + "\0v\0e\0r\0s\0i\0o\0n\0=\0'\0\x31\0.\0\x30\0'\0 " + "\0e\0n\0c\0o\0d\0i\0n\0g\0=\0'\0u\0t\0f\0-\0\x31\0\x36\0'\0?\0>" + "\0<\0a\0>\0<\0!\0[\0C\0D\0A\0T\0A\0[" + /* 64 characters per line */ + A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 + A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 + A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 + A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 + A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 + A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 + A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 + A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 + A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 + A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 + A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 + A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 + A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 + A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 + A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 + A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 + A_TO_P_IN_UTF16 + "\0]\0]\0>\0<\0/\0a\0>"; + const char *expected = + "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP" + "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP" + "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP" + "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP" + "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP" + "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP" + "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP" + "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP" + "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP" + "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP" + "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP" + "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP" + "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP" + "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP" + "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP" + "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP" + "ABCDEFGHIJKLMNOP"; + CharData storage; + void *buffer; + + CharData_Init(&storage); + XML_SetUserData(parser, &storage); + XML_SetCharacterDataHandler(parser, accumulate_characters); + buffer = XML_GetBuffer(parser, sizeof(text) - 1); + if (buffer == NULL) + fail("Could not allocate parse buffer"); + memcpy(buffer, text, sizeof(text) - 1); + if (XML_ParseBuffer(parser, + sizeof(text) - 1, + XML_TRUE) == XML_STATUS_ERROR) + xml_failure(parser); + CharData_CheckXMLChars(&storage, expected); +} +END_TEST + START_TEST(test_bad_cdata) { struct CaseData { @@ -5133,6 +5206,7 @@ make_suite(void) tcase_add_test(tc_basic, test_repeated_stop_parser_between_char_data_calls); tcase_add_test(tc_basic, test_good_cdata_ascii); tcase_add_test(tc_basic, test_good_cdata_utf16); + tcase_add_test(tc_basic, test_long_cdata_utf16); tcase_add_test(tc_basic, test_bad_cdata); tcase_add_test(tc_basic, test_memory_allocation); tcase_add_test(tc_basic, test_default_current); From 9ac26205bcfa70957cef1c3df9b1e413cd7fad8e Mon Sep 17 00:00:00 2001 From: Rhodri James Date: Fri, 24 Feb 2017 14:11:45 +0000 Subject: [PATCH 46/54] Test handling of UTF-16 supplementary plane characters --- expat/tests/runtests.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/expat/tests/runtests.c b/expat/tests/runtests.c index 22a51ad2..79373fe8 100644 --- a/expat/tests/runtests.c +++ b/expat/tests/runtests.c @@ -1758,6 +1758,42 @@ START_TEST(test_long_cdata_utf16) } END_TEST +/* Test handling of multiple unit UTF-16 characters */ +START_TEST(test_multichar_cdata_utf16) +{ + /* Test data is: + * + * + * + * where {MINIM} is U+1d15e (a minim or half-note) + * UTF-16: 0xd834 0xdd5e + * UTF-8: 0xf0 0x9d 0x85 0x9e + * and {CROTCHET} is U+1d15f (a crotchet or quarter-note) + * UTF-16: 0xd834 0xdd5e + * UTF-8: 0xf0 0x9d 0x85 0x9e + */ + const char text[] = + "\0<\0?\0x\0m\0l\0" + " \0v\0e\0r\0s\0i\0o\0n\0=\0'\0\x31\0.\0\x30\0'\0" + " \0e\0n\0c\0o\0d\0i\0n\0g\0=\0'\0u\0t\0f\0-\0""1\0""6\0'" + "\0?\0>\0\n" + "\0<\0a\0>\0<\0!\0[\0C\0D\0A\0T\0A\0[" + "\xd8\x34\xdd\x5e\xd8\x34\xdd\x5f" + "\0]\0]\0>\0<\0/\0a\0>"; + const char *expected = "\xf0\x9d\x85\x9e\xf0\x9d\x85\x9f"; + CharData storage; + + CharData_Init(&storage); + XML_SetUserData(parser, &storage); + XML_SetCharacterDataHandler(parser, accumulate_characters); + + if (_XML_Parse_SINGLE_BYTES(parser, text, sizeof(text) - 1, XML_TRUE) == XML_STATUS_ERROR) + xml_failure(parser); + CharData_CheckXMLChars(&storage, expected); +} +END_TEST + + START_TEST(test_bad_cdata) { struct CaseData { @@ -5207,6 +5243,7 @@ make_suite(void) tcase_add_test(tc_basic, test_good_cdata_ascii); tcase_add_test(tc_basic, test_good_cdata_utf16); tcase_add_test(tc_basic, test_long_cdata_utf16); + tcase_add_test(tc_basic, test_multichar_cdata_utf16); tcase_add_test(tc_basic, test_bad_cdata); tcase_add_test(tc_basic, test_memory_allocation); tcase_add_test(tc_basic, test_default_current); From 1a8297c54c4296c24f4ad8ddcec616f74173edc2 Mon Sep 17 00:00:00 2001 From: Rhodri James Date: Fri, 24 Feb 2017 14:59:44 +0000 Subject: [PATCH 47/54] Test a variety of incomplete UTF-16 CDATA strings --- expat/tests/runtests.c | 82 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/expat/tests/runtests.c b/expat/tests/runtests.c index 79373fe8..dde225ec 100644 --- a/expat/tests/runtests.c +++ b/expat/tests/runtests.c @@ -1848,6 +1848,87 @@ START_TEST(test_bad_cdata) } END_TEST +/* Test failures in UTF-16 CDATA */ +START_TEST(test_bad_cdata_utf16) +{ + struct CaseData { + size_t text_bytes; + const char *text; + enum XML_Error expected_error; + }; + + const char prolog[] = + "\0<\0?\0x\0m\0l\0" + " \0v\0e\0r\0s\0i\0o\0n\0=\0'\0\x31\0.\0\x30\0'\0" + " \0e\0n\0c\0o\0d\0i\0n\0g\0=\0'\0u\0t\0f\0-\0""1\0""6\0'" + "\0?\0>\0\n" + "\0<\0a\0>"; + struct CaseData cases[] = { + {1, "\0", XML_ERROR_UNCLOSED_TOKEN}, + {2, "\0<", XML_ERROR_UNCLOSED_TOKEN}, + {3, "\0<\0", XML_ERROR_UNCLOSED_TOKEN}, + {4, "\0<\0!", XML_ERROR_UNCLOSED_TOKEN}, + {5, "\0<\0!\0", XML_ERROR_UNCLOSED_TOKEN}, + {6, "\0<\0!\0[", XML_ERROR_UNCLOSED_TOKEN}, + {7, "\0<\0!\0[\0", XML_ERROR_UNCLOSED_TOKEN}, + {8, "\0<\0!\0[\0C", XML_ERROR_UNCLOSED_TOKEN}, + {9, "\0<\0!\0[\0C\0", XML_ERROR_UNCLOSED_TOKEN}, + {10, "\0<\0!\0[\0C\0D", XML_ERROR_UNCLOSED_TOKEN}, + {11, "\0<\0!\0[\0C\0D\0", XML_ERROR_UNCLOSED_TOKEN}, + {12, "\0<\0!\0[\0C\0D\0A", XML_ERROR_UNCLOSED_TOKEN}, + {13, "\0<\0!\0[\0C\0D\0A\0", XML_ERROR_UNCLOSED_TOKEN}, + {14, "\0<\0!\0[\0C\0D\0A\0T", XML_ERROR_UNCLOSED_TOKEN}, + {15, "\0<\0!\0[\0C\0D\0A\0T\0", XML_ERROR_UNCLOSED_TOKEN}, + {16, "\0<\0!\0[\0C\0D\0A\0T\0A", XML_ERROR_UNCLOSED_TOKEN}, + {17, "\0<\0!\0[\0C\0D\0A\0T\0A\0", XML_ERROR_UNCLOSED_TOKEN}, + {18, "\0<\0!\0[\0C\0D\0A\0T\0A\0[", + XML_ERROR_UNCLOSED_CDATA_SECTION}, + {19, "\0<\0!\0[\0C\0D\0A\0T\0A\0[\0", + XML_ERROR_UNCLOSED_CDATA_SECTION}, + {20, "\0<\0!\0[\0C\0D\0A\0T\0A\0[\0Z", + XML_ERROR_UNCLOSED_CDATA_SECTION}, + /* Now add a four-byte UTF-16 character */ + {21, "\0<\0!\0[\0C\0D\0A\0T\0A\0[\0Z\xd8", + XML_ERROR_UNCLOSED_CDATA_SECTION}, + {22, "\0<\0!\0[\0C\0D\0A\0T\0A\0[\0Z\xd8\x34", + XML_ERROR_PARTIAL_CHAR}, + {23, "\0<\0!\0[\0C\0D\0A\0T\0A\0[\0Z\xd8\x34\xdd", + XML_ERROR_PARTIAL_CHAR}, + {24, "\0<\0!\0[\0C\0D\0A\0T\0A\0[\0Z\xd8\x34\xdd\x5e", + XML_ERROR_UNCLOSED_CDATA_SECTION} + }; + size_t i; + + for (i = 0; i < sizeof(cases)/sizeof(struct CaseData); i++) { + enum XML_Status actual_status; + enum XML_Error actual_error; + + if (_XML_Parse_SINGLE_BYTES(parser, prolog, sizeof(prolog)-1, + XML_FALSE) == XML_STATUS_ERROR) + xml_failure(parser); + actual_status = _XML_Parse_SINGLE_BYTES(parser, + cases[i].text, + cases[i].text_bytes, + XML_TRUE); + assert(actual_status == XML_STATUS_ERROR); + actual_error = XML_GetErrorCode(parser); + if (actual_error != cases[i].expected_error) { + char message[1024]; + + sprintf(message, + "Expected error %d (%s), got %d (%s) for case %lu\n", + cases[i].expected_error, + XML_ErrorString(cases[i].expected_error), + actual_error, + XML_ErrorString(actual_error), + i+1); + fail(message); + } + XML_ParserReset(parser, NULL); + } +} +END_TEST + /* Test memory allocation functions */ START_TEST(test_memory_allocation) { @@ -5245,6 +5326,7 @@ make_suite(void) tcase_add_test(tc_basic, test_long_cdata_utf16); tcase_add_test(tc_basic, test_multichar_cdata_utf16); tcase_add_test(tc_basic, test_bad_cdata); + tcase_add_test(tc_basic, test_bad_cdata_utf16); tcase_add_test(tc_basic, test_memory_allocation); tcase_add_test(tc_basic, test_default_current); tcase_add_test(tc_basic, test_dtd_elements); From 23c488c8fd36b4a8558c03ae7727d66216106a7e Mon Sep 17 00:00:00 2001 From: Rhodri James Date: Fri, 24 Feb 2017 16:58:44 +0000 Subject: [PATCH 48/54] Test aborting parse while processing CDATA --- expat/tests/runtests.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/expat/tests/runtests.c b/expat/tests/runtests.c index dde225ec..db4f7b9b 100644 --- a/expat/tests/runtests.c +++ b/expat/tests/runtests.c @@ -1929,6 +1929,43 @@ START_TEST(test_bad_cdata_utf16) } END_TEST +static const char *long_cdata_text = + ""; + +/* Test stopping the parser in cdata handler */ +START_TEST(test_stop_parser_between_cdata_calls) +{ + const char *text = long_cdata_text; + + XML_SetCharacterDataHandler(parser, + clearing_aborting_character_handler); + resumable = XML_FALSE; + expect_failure(text, XML_ERROR_ABORTED, + "Parse not aborted in CDATA handler"); +} +END_TEST + /* Test memory allocation functions */ START_TEST(test_memory_allocation) { @@ -5327,6 +5364,7 @@ make_suite(void) tcase_add_test(tc_basic, test_multichar_cdata_utf16); tcase_add_test(tc_basic, test_bad_cdata); tcase_add_test(tc_basic, test_bad_cdata_utf16); + tcase_add_test(tc_basic, test_stop_parser_between_cdata_calls); tcase_add_test(tc_basic, test_memory_allocation); tcase_add_test(tc_basic, test_default_current); tcase_add_test(tc_basic, test_dtd_elements); From 7495f28469925b4c82f9734dd7e725b7ef59b030 Mon Sep 17 00:00:00 2001 From: Rhodri James Date: Fri, 24 Feb 2017 17:05:37 +0000 Subject: [PATCH 49/54] Test suspending the parse in the middle of CDATA handling --- expat/tests/runtests.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/expat/tests/runtests.c b/expat/tests/runtests.c index db4f7b9b..d063414f 100644 --- a/expat/tests/runtests.c +++ b/expat/tests/runtests.c @@ -1966,6 +1966,26 @@ START_TEST(test_stop_parser_between_cdata_calls) } END_TEST +/* Test suspending the parser in cdata handler */ +START_TEST(test_suspend_parser_between_cdata_calls) +{ + const char *text = long_cdata_text; + enum XML_Status result; + + XML_SetCharacterDataHandler(parser, + clearing_aborting_character_handler); + resumable = XML_TRUE; + result = _XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_TRUE); + if (result != XML_STATUS_SUSPENDED) { + if (result == XML_STATUS_ERROR) + xml_failure(parser); + fail("Parse not suspended in CDATA handler"); + } + if (XML_GetErrorCode(parser) != XML_ERROR_NONE) + xml_failure(parser); +} +END_TEST + /* Test memory allocation functions */ START_TEST(test_memory_allocation) { @@ -5365,6 +5385,7 @@ make_suite(void) tcase_add_test(tc_basic, test_bad_cdata); tcase_add_test(tc_basic, test_bad_cdata_utf16); tcase_add_test(tc_basic, test_stop_parser_between_cdata_calls); + tcase_add_test(tc_basic, test_suspend_parser_between_cdata_calls); tcase_add_test(tc_basic, test_memory_allocation); tcase_add_test(tc_basic, test_default_current); tcase_add_test(tc_basic, test_dtd_elements); From da0bac99ada92ef0da8346e50b30cf2e27b591c6 Mon Sep 17 00:00:00 2001 From: Rhodri James Date: Fri, 24 Feb 2017 18:39:38 +0000 Subject: [PATCH 50/54] Exercise conditional exclusion code --- expat/tests/runtests.c | 51 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/expat/tests/runtests.c b/expat/tests/runtests.c index d063414f..edbd2ab3 100644 --- a/expat/tests/runtests.c +++ b/expat/tests/runtests.c @@ -194,6 +194,10 @@ dummy_start_element(void *UNUSED_P(userData), const XML_Char *UNUSED_P(name), const XML_Char **UNUSED_P(atts)) {} +static void XMLCALL +dummy_end_element(void *UNUSED_P(userData), const XML_Char *UNUSED_P(name)) +{} + static void XMLCALL dummy_start_cdata_handler(void *UNUSED_P(userData)) {} @@ -3394,6 +3398,52 @@ START_TEST(test_invalid_tag_in_dtd) } END_TEST +/* Test conditional inclusion (IGNORE) */ +static int XMLCALL +external_entity_load_ignore(XML_Parser parser, + const XML_Char *context, + const XML_Char *UNUSED_P(base), + const XML_Char *UNUSED_P(systemId), + const XML_Char *UNUSED_P(publicId)) +{ + const char *text = "]]>"; + XML_Parser ext_parser; + + ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL); + if (ext_parser == NULL) + fail("Could not create external entity parser"); + if (_XML_Parse_SINGLE_BYTES(ext_parser, text, strlen(text), + XML_TRUE) == XML_STATUS_ERROR) + xml_failure(parser); + return XML_STATUS_OK; +} + +START_TEST(test_ignore_section) +{ + const char *text = + "\n" + "&entity;"; + const char *expected = + "]]>\n&entity;"; + CharData storage; + + CharData_Init(&storage); + XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS); + XML_SetUserData(parser, &storage); + XML_SetExternalEntityRefHandler(parser, external_entity_load_ignore); + XML_SetDefaultHandler(parser, accumulate_characters); + XML_SetStartDoctypeDeclHandler(parser, dummy_start_doctype_handler); + XML_SetEndDoctypeDeclHandler(parser, dummy_end_doctype_handler); + XML_SetElementDeclHandler(parser, dummy_element_decl_handler); + XML_SetStartElementHandler(parser, dummy_start_element); + XML_SetEndElementHandler(parser, dummy_end_element); + if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), + XML_TRUE) == XML_STATUS_ERROR) + xml_failure(parser); + CharData_CheckXMLChars(&storage, expected); +} +END_TEST + /* * Namespaces tests. @@ -5415,6 +5465,7 @@ make_suite(void) tcase_add_test(tc_basic, test_byte_info_at_error); tcase_add_test(tc_basic, test_byte_info_at_cdata); tcase_add_test(tc_basic, test_invalid_tag_in_dtd); + tcase_add_test(tc_basic, test_ignore_section); suite_add_tcase(s, tc_namespace); tcase_add_checked_fixture(tc_namespace, From 7a3664ab294e1826b3f51afb400a845f61a093f5 Mon Sep 17 00:00:00 2001 From: Rhodri James Date: Fri, 24 Feb 2017 19:12:26 +0000 Subject: [PATCH 51/54] Test a broken IGNORE section is faulted --- expat/tests/runtests.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/expat/tests/runtests.c b/expat/tests/runtests.c index edbd2ab3..755ea585 100644 --- a/expat/tests/runtests.c +++ b/expat/tests/runtests.c @@ -3444,6 +3444,35 @@ START_TEST(test_ignore_section) } END_TEST +/* Test mis-formatted conditional exclusion */ +static int XMLCALL +external_entity_bad_ignore(XML_Parser parser, + const XML_Char *context, + const XML_Char *UNUSED_P(base), + const XML_Char *UNUSED_P(systemId), + const XML_Char *UNUSED_P(publicId)) +{ + const char *text = "\n" + "&entity;"; + + XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS); + XML_SetExternalEntityRefHandler(parser, external_entity_bad_ignore); + expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING, + "Incomplete IGNORE section not failed"); +} +END_TEST /* * Namespaces tests. @@ -5466,6 +5495,7 @@ make_suite(void) tcase_add_test(tc_basic, test_byte_info_at_cdata); tcase_add_test(tc_basic, test_invalid_tag_in_dtd); tcase_add_test(tc_basic, test_ignore_section); + tcase_add_test(tc_basic, test_bad_ignore_section); suite_add_tcase(s, tc_namespace); tcase_add_checked_fixture(tc_namespace, From 6cacca3987c463f0197503d24f1b3d16926ad935 Mon Sep 17 00:00:00 2001 From: Rhodri James Date: Mon, 27 Feb 2017 15:27:29 +0000 Subject: [PATCH 52/54] Refactor previous test to use existing test functions --- expat/tests/runtests.c | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/expat/tests/runtests.c b/expat/tests/runtests.c index 755ea585..ddfdfe2b 100644 --- a/expat/tests/runtests.c +++ b/expat/tests/runtests.c @@ -3445,30 +3445,20 @@ START_TEST(test_ignore_section) END_TEST /* Test mis-formatted conditional exclusion */ -static int XMLCALL -external_entity_bad_ignore(XML_Parser parser, - const XML_Char *context, - const XML_Char *UNUSED_P(base), - const XML_Char *UNUSED_P(systemId), - const XML_Char *UNUSED_P(publicId)) -{ - const char *text = "\n" "&entity;"; + ExtFaults fault = { + " Date: Mon, 27 Feb 2017 15:39:47 +0000 Subject: [PATCH 53/54] Increase test coverage of ignore section processing --- expat/tests/runtests.c | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/expat/tests/runtests.c b/expat/tests/runtests.c index ddfdfe2b..4c7d3520 100644 --- a/expat/tests/runtests.c +++ b/expat/tests/runtests.c @@ -3450,17 +3450,29 @@ START_TEST(test_bad_ignore_section) const char *text = "\n" "&entity;"; - ExtFaults fault = { - "", + "Invalid XML character not faulted", + XML_ERROR_INVALID_TOKEN + }, + { NULL, NULL, XML_ERROR_NONE } }; + ExtFaults *fault; - XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS); - XML_SetExternalEntityRefHandler(parser, external_entity_faulter); - XML_SetUserData(parser, &fault); - expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING, - "Incomplete IGNORE section not failed"); + for (fault = &faults[0]; fault->parse_text != NULL; fault++) { + XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS); + XML_SetExternalEntityRefHandler(parser, external_entity_faulter); + XML_SetUserData(parser, fault); + expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING, + "Incomplete IGNORE section not failed"); + XML_ParserReset(parser, NULL); + } } END_TEST From 317a023df29c57a37afb0835cd7bc4cb48ea5221 Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Sun, 16 Jul 2017 19:07:50 +0200 Subject: [PATCH 54/54] runtests.c: Fix memleaks --- expat/tests/runtests.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/expat/tests/runtests.c b/expat/tests/runtests.c index 4c7d3520..edfd8880 100644 --- a/expat/tests/runtests.c +++ b/expat/tests/runtests.c @@ -2929,6 +2929,7 @@ external_entity_good_cdata_ascii(XML_Parser parser, xml_failure(ext_parser); CharData_CheckXMLChars(&storage, expected); + XML_ParserFree(ext_parser); return XML_STATUS_OK; } @@ -3415,6 +3416,8 @@ external_entity_load_ignore(XML_Parser parser, if (_XML_Parse_SINGLE_BYTES(ext_parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR) xml_failure(parser); + + XML_ParserFree(ext_parser); return XML_STATUS_OK; }