diff --git a/expat/CMakeLists.txt b/expat/CMakeLists.txt index 2b4c13c5..72cf0b01 100644 --- a/expat/CMakeLists.txt +++ b/expat/CMakeLists.txt @@ -579,10 +579,8 @@ endif() # C code examples # if(EXPAT_BUILD_EXAMPLES) - add_executable(elements examples/elements.c) - add_executable(outline examples/outline.c) - - foreach(_target elements outline) + foreach(_target element_declarations elements outline) + add_executable(${_target} examples/${_target}.c) set_property(TARGET ${_target} PROPERTY RUNTIME_OUTPUT_DIRECTORY examples) target_link_libraries(${_target} expat) endforeach() diff --git a/expat/Changes b/expat/Changes index e6717105..4032ef77 100644 --- a/expat/Changes +++ b/expat/Changes @@ -2,6 +2,10 @@ NOTE: We are looking for help with a few things: https://github.com/libexpat/libexpat/labels/help%20wanted If you can help, please get in touch. Thanks! +Release 2.5.1 xxx xxxxxxx xx xxxx + Other changes: + #673 examples: Add new example "element_declarations.c" + Release 2.5.0 Tue October 25 2022 Security fixes: #616 #649 #650 CVE-2022-43680 -- Fix heap use-after-free after overeager diff --git a/expat/examples/Makefile.am b/expat/examples/Makefile.am index d386b592..e2e22bce 100644 --- a/expat/examples/Makefile.am +++ b/expat/examples/Makefile.am @@ -6,8 +6,8 @@ # \___/_/\_\ .__/ \__,_|\__| # |_| XML parser # -# Copyright (c) 2017 Sebastian Pipping -# Copyright (c) 2020 Jeffrey Walton +# Copyright (c) 2017-2022 Sebastian Pipping +# Copyright (c) 2020 Jeffrey Walton # Licensed under the MIT license: # # Permission is hereby granted, free of charge, to any person obtaining @@ -31,7 +31,10 @@ AM_CPPFLAGS = @AM_CPPFLAGS@ -I$(srcdir)/../lib -noinst_PROGRAMS = elements outline +noinst_PROGRAMS = element_declarations elements outline + +element_declarations_SOURCES = element_declarations.c +element_declarations_LDADD = ../lib/libexpat.la elements_SOURCES = elements.c elements_LDADD = ../lib/libexpat.la diff --git a/expat/examples/element_declarations.c b/expat/examples/element_declarations.c new file mode 100644 index 00000000..437b0996 --- /dev/null +++ b/expat/examples/element_declarations.c @@ -0,0 +1,229 @@ +/* Read an XML document from standard input and print + element declarations (if any) to standard output. + It must be used with Expat compiled for UTF-8 output. + __ __ _ + ___\ \/ /_ __ __ _| |_ + / _ \\ /| '_ \ / _` | __| + | __// \| |_) | (_| | |_ + \___/_/\_\ .__/ \__,_|\__| + |_| XML parser + + Copyright (c) 1997-2000 Thai Open Source Software Center Ltd + Copyright (c) 2001-2003 Fred L. Drake, Jr. + Copyright (c) 2004-2006 Karl Waclawek + Copyright (c) 2005-2007 Steven Solie + Copyright (c) 2016-2022 Sebastian Pipping + Copyright (c) 2017 Rhodri James + Copyright (c) 2019 Zhongyuan Zhou + Licensed under the MIT license: + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to permit + persons to whom the Software is furnished to do so, subject to the + following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN + NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include +#include +#include +#include + +#ifdef XML_LARGE_SIZE +# define XML_FMT_INT_MOD "ll" +#else +# define XML_FMT_INT_MOD "l" +#endif + +#ifdef XML_UNICODE_WCHAR_T +# define XML_FMT_STR "ls" +#else +# define XML_FMT_STR "s" +#endif + +// While traversing the XML_Content tree, we avoid recursion +// to not be vulnerable to a denial of service attack. +typedef struct StackStruct { + const XML_Content *model; + unsigned level; + struct StackStruct *prev; +} Stack; + +static Stack * +stackPushMalloc(Stack *stackTop, const XML_Content *model, unsigned level) { + Stack *const newStackTop = malloc(sizeof(Stack)); + if (! newStackTop) { + return NULL; + } + newStackTop->model = model; + newStackTop->level = level; + newStackTop->prev = stackTop; + return newStackTop; +} + +static Stack * +stackPopFree(Stack *stackTop) { + Stack *const newStackTop = stackTop->prev; + free(stackTop); + return newStackTop; +} + +static char * +contentTypeName(enum XML_Content_Type contentType) { + switch (contentType) { + case XML_CTYPE_EMPTY: + return "EMPTY"; + case XML_CTYPE_ANY: + return "ANY"; + case XML_CTYPE_MIXED: + return "MIXED"; + case XML_CTYPE_NAME: + return "NAME"; + case XML_CTYPE_CHOICE: + return "CHOICE"; + case XML_CTYPE_SEQ: + return "SEQ"; + default: + return "???"; + } +} + +static char * +contentQuantName(enum XML_Content_Quant contentQuant) { + switch (contentQuant) { + case XML_CQUANT_NONE: + return "NONE"; + case XML_CQUANT_OPT: + return "OPT"; + case XML_CQUANT_REP: + return "REP"; + case XML_CQUANT_PLUS: + return "PLUS"; + default: + return "???"; + } +} + +static void +dumpContentModelElement(const XML_Content *model, unsigned level, + const XML_Content *root) { + // Indent + unsigned u = 0; + for (; u < level; u++) { + printf(" "); + } + + // Node + printf("[%u] type=%s(%d), quant=%s(%d)", (unsigned)(model - root), + contentTypeName(model->type), model->type, + contentQuantName(model->quant), model->quant); + if (model->name) { + printf(", name=\"%" XML_FMT_STR "\"", model->name); + } else { + printf(", name=NULL"); + } + printf(", numchildren=%d", model->numchildren); + printf("\n"); +} + +static bool +dumpContentModel(const XML_Char *name, const XML_Content *root) { + printf("Element \"%" XML_FMT_STR "\":\n", name); + Stack *stackTop = NULL; + stackTop = stackPushMalloc(stackTop, root, 1); + if (! stackTop) { + return false; + } + + while (stackTop) { + const XML_Content *const model = stackTop->model; + const unsigned level = stackTop->level; + + dumpContentModelElement(model, level, root); + + stackTop = stackPopFree(stackTop); + + for (size_t u = model->numchildren; u >= 1; u--) { + stackTop + = stackPushMalloc(stackTop, model->children + (u - 1), level + 1); + if (! stackTop) { + return false; + } + } + } + + printf("\n"); + return true; +} + +static void XMLCALL +handleElementDeclaration(void *userData, const XML_Char *name, + XML_Content *model) { + XML_Parser parser = (XML_Parser)userData; + const bool success = dumpContentModel(name, model); + XML_FreeContentModel(parser, model); + if (! success) { + XML_StopParser(parser, /* resumable= */ XML_FALSE); + } +} + +int +main(void) { + XML_Parser parser = XML_ParserCreate(NULL); + int done; + + if (! parser) { + fprintf(stderr, "Couldn't allocate memory for parser\n"); + return 1; + } + + XML_SetUserData(parser, parser); + XML_SetElementDeclHandler(parser, handleElementDeclaration); + + do { + void *const buf = XML_GetBuffer(parser, BUFSIZ); + if (! buf) { + fprintf(stderr, "Couldn't allocate memory for buffer\n"); + XML_ParserFree(parser); + return 1; + } + + const size_t len = fread(buf, 1, BUFSIZ, stdin); + + if (ferror(stdin)) { + fprintf(stderr, "Read error\n"); + XML_ParserFree(parser); + return 1; + } + + done = feof(stdin); + + if (XML_ParseBuffer(parser, (int)len, done) == XML_STATUS_ERROR) { + enum XML_Error errorCode = XML_GetErrorCode(parser); + if (errorCode == XML_ERROR_ABORTED) { + errorCode = XML_ERROR_NO_MEMORY; + } + fprintf(stderr, + "Parse error at line %" XML_FMT_INT_MOD "u:\n%" XML_FMT_STR "\n", + XML_GetCurrentLineNumber(parser), XML_ErrorString(errorCode)); + XML_ParserFree(parser); + return 1; + } + } while (! done); + + XML_ParserFree(parser); + return 0; +}