untrusted comment: verify with openbsd-79-base.pub RWTSdNN9A3yvWGk8OmqHhsc/fyxGQuCkx/b8rmFTVaHFYhT6GjO8i2HNSEmWWcXuT/HKxjqknVuocN7A8K5Eqi3dqEIzq2yWnww= OpenBSD 7.9 errata 033, October 7, 2026: Backport fixes from libexpat 2.8.5. CVE-2026-93990 Apply by doing: signify -Vep /etc/signify/openbsd-79-base.pub -x 033_expat.patch.sig \ -m - | (cd /usr/src && patch -p0) And then rebuild and install libexpat: cd /usr/src/lib/libexpat make obj make make install Index: lib/libexpat/Changes =================================================================== RCS file: /cvs/src/lib/libexpat/Changes,v diff -u -p -r1.35.2.2 Changes --- lib/libexpat/Changes 10 Sep 2026 20:46:02 -0000 1.35.2.2 +++ lib/libexpat/Changes 2 Oct 2026 22:01:20 -0000 @@ -16,6 +16,33 @@ !! Sebastian Pipping -- Berlin, 2026-08-03 !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +Tue September 22 2026 + Security fixes: + #1282 CVE-2026-93990 -- Reject high surrogates not followed by a + low surrogate during UTF-16 decoding; previously, malformed + UTF-16 could be smuggled into the application using Expat + and could cause arbitrary damage there, depending on how + malformed UTF-16 was handled inside the application; + validation was not their job but Expat's. This is similar + to past vulnerability CVE-2022-25235. + Upstream CVSS 3.1 vector: + AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H (CVSS score: 9.8) + + Bug fixes: + #1346 lib: Fix OOM-related memory leak on a failed overflow check + #1371 lib: Fix memory alignment for architectures with 128bit + pointers like CHERI-RISC-V + + Other changes: + #1354 lib: Reject an XML declaration version other than `1.[0-9]+` + (which is less strict than XML 1.0r4 (fourth edition) + and matches XML 1.0r5 (fifth edition)) + #1357 lib: Drop internal macros FASTCALL, PTRCALL, PTRFASTCALL + #1349 Replace some internal use of XML_Bool with standard bool + #1360 tests|xmlwf: Add `#include "expat_config.h"` where missing + #1378 tests: Fix tail pointer when unlinking the last tracked + allocation + Mon August 31 2026 Security fixes: #1321 #1331 CVE-2026-66046, CVE-2026-76641 -- Fix quadratic runtime from Index: lib/libexpat/lib/internal.h =================================================================== RCS file: /cvs/src/lib/libexpat/lib/internal.h,v diff -u -p -r1.17.2.2 internal.h --- lib/libexpat/lib/internal.h 10 Sep 2026 20:46:02 -0000 1.17.2.2 +++ lib/libexpat/lib/internal.h 2 Oct 2026 22:01:21 -0000 @@ -6,13 +6,6 @@ The following calling convention macros are defined for frequently called functions: - FASTCALL - Used for those internal functions that have a simple - body and a low number of arguments and local variables. - - PTRCALL - Used for functions called though function pointers. - - PTRFASTCALL - Like PTRCALL, but for low number of arguments. - inline - Used for selected internal functions for which inlining may improve performance on some platforms. @@ -58,42 +51,6 @@ SPDX-License-Identifier: MIT */ -#if defined(__GNUC__) && defined(__i386__) && ! defined(__MINGW32__) -/* We'll use this version by default only where we know it helps. - - regparm() generates warnings on Solaris boxes. See SF bug #692878. - - Instability reported with egcs on a RedHat Linux 7.3. - Let's comment out: - #define FASTCALL __attribute__((stdcall, regparm(3))) - and let's try this: -*/ -# define FASTCALL __attribute__((regparm(3))) -# define PTRFASTCALL __attribute__((regparm(3))) -#endif - -/* Using __fastcall seems to have an unexpected negative effect under - MS VC++, especially for function pointers, so we won't use it for - now on that platform. It may be reconsidered for a future release - if it can be made more effective. - Likely reason: __fastcall on Windows is like stdcall, therefore - the compiler cannot perform stack optimizations for call clusters. -*/ - -/* Make sure all of these are defined if they aren't already. */ - -#ifndef FASTCALL -# define FASTCALL -#endif - -#ifndef PTRCALL -# define PTRCALL -#endif - -#ifndef PTRFASTCALL -# define PTRFASTCALL -#endif - #ifndef XML_MIN_SIZE # if ! defined(__cplusplus) && ! defined(inline) # ifdef __GNUC__ @@ -152,7 +109,11 @@ // NOTE: If function expat_alloc was user facing, EXPAT_MALLOC_ALIGNMENT would // have to take sizeof(long double) into account -#define EXPAT_MALLOC_ALIGNMENT sizeof(long long) // largest parser (sub)member +union expat_align { + long long l; + void *p; +}; +#define EXPAT_MALLOC_ALIGNMENT sizeof(union expat_align) #define EXPAT_MALLOC_PADDING ((EXPAT_MALLOC_ALIGNMENT) - sizeof(size_t)) /* NOTE END */ Index: lib/libexpat/lib/xmlparse.c =================================================================== RCS file: /cvs/src/lib/libexpat/lib/xmlparse.c,v diff -u -p -r1.47.2.2 xmlparse.c --- lib/libexpat/lib/xmlparse.c 10 Sep 2026 20:46:02 -0000 1.47.2.2 +++ lib/libexpat/lib/xmlparse.c 2 Oct 2026 22:01:21 -0000 @@ -310,12 +310,12 @@ typedef struct { const XML_Char *publicId; const XML_Char *notation; bool open; - XML_Bool hasMore; /* true if entity has not been completely processed */ - /* An entity can be open while being already completely processed (hasMore == - XML_FALSE). The reason is the delayed closing of entities until their inner + bool hasMore; /* true if entity has not been completely processed */ + /* An entity can be open while being already completely processed (!hasMore). + The reason is the delayed closing of entities until their inner entities are processed and closed */ - XML_Bool is_param; - XML_Bool is_internal; /* true if declared in internal subset outside PE */ + bool is_param; + bool is_internal; /* true if declared in internal subset outside PE */ } ENTITY; typedef struct { @@ -350,8 +350,8 @@ typedef struct { typedef struct attribute_id { XML_Char *name; PREFIX *prefix; - XML_Bool maybeTokenized; - XML_Bool xmlns; + bool maybeTokenized; + bool xmlns; } ATTRIBUTE_ID; typedef struct { @@ -407,12 +407,12 @@ typedef struct { XML_Bool standalone; #ifdef XML_DTD /* indicates if external PE has been read */ - XML_Bool paramEntityRead; + bool paramEntityRead; HASH_TABLE paramEntities; #endif /* XML_DTD */ PREFIX defaultPrefix; /* === scaffolding for building content model === */ - XML_Bool in_eldecl; + bool in_eldecl; CONTENT_SCAFFOLD *scaffold; unsigned contentStringLen; unsigned scaffSize; @@ -434,7 +434,7 @@ typedef struct open_internal_entity { struct open_internal_entity *next; ENTITY *entity; int startTagLevel; - XML_Bool betweenDecl; /* WFC: PE Between Declarations */ + bool betweenDecl; /* WFC: PE Between Declarations */ enum EntityType type; } OPEN_INTERNAL_ENTITY; @@ -471,8 +471,8 @@ typedef struct entity_stats { } ENTITY_STATS; #endif /* XML_GE == 1 */ -typedef enum XML_Error PTRCALL Processor(XML_Parser parser, const char *start, - const char *end, const char **endPtr); +typedef enum XML_Error Processor(XML_Parser parser, const char *start, + const char *end, const char **endPtr); static Processor prologProcessor; static Processor prologInitProcessor; @@ -504,7 +504,7 @@ static enum XML_Error doProlog(XML_Parse XML_Bool haveMore, XML_Bool allowClosingDoctype, enum XML_Account account); static enum XML_Error processEntity(XML_Parser parser, ENTITY *entity, - XML_Bool betweenDecl, enum EntityType type); + bool betweenDecl, enum EntityType type); static enum XML_Error doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, const char *start, const char *end, const char **endPtr, @@ -564,7 +564,7 @@ static void reportDefault(XML_Parser par static const XML_Char *getContext(XML_Parser parser); static XML_Bool setContext(XML_Parser parser, const XML_Char *context); -static void FASTCALL normalizePublicId(XML_Char *s); +static void normalizePublicId(XML_Char *s); static DTD *dtdCreate(XML_Parser parser); /* do not call if m_parentParser != NULL */ @@ -578,32 +578,29 @@ static NAMED *lookupWithLength(XML_Parse size_t nameLen, size_t createSize); static NAMED *lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize); -static void FASTCALL hashTableInit(HASH_TABLE *table, XML_Parser parser); -static void FASTCALL hashTableClear(HASH_TABLE *table); -static void FASTCALL hashTableDestroy(HASH_TABLE *table); -static void FASTCALL hashTableIterInit(HASH_TABLE_ITER *iter, - const HASH_TABLE *table); -static NAMED *FASTCALL hashTableIterNext(HASH_TABLE_ITER *iter); - -static void FASTCALL poolInit(STRING_POOL *pool, XML_Parser parser); -static void FASTCALL poolClear(STRING_POOL *pool); -static void FASTCALL poolDestroy(STRING_POOL *pool); +static void hashTableInit(HASH_TABLE *table, XML_Parser parser); +static void hashTableClear(HASH_TABLE *table); +static void hashTableDestroy(HASH_TABLE *table); +static void hashTableIterInit(HASH_TABLE_ITER *iter, const HASH_TABLE *table); +static NAMED *hashTableIterNext(HASH_TABLE_ITER *iter); + +static void poolInit(STRING_POOL *pool, XML_Parser parser); +static void poolClear(STRING_POOL *pool); +static void poolDestroy(STRING_POOL *pool); static XML_Char *poolAppend(STRING_POOL *pool, const ENCODING *enc, const char *ptr, const char *end); static XML_Char *poolStoreString(STRING_POOL *pool, const ENCODING *enc, const char *ptr, const char *end); -static XML_Bool FASTCALL poolGrow(STRING_POOL *pool); -static bool FASTCALL poolGrowUntil(STRING_POOL *pool, size_t needed); -static const XML_Char *FASTCALL poolCopyString(STRING_POOL *pool, - const XML_Char *s); -static const XML_Char *FASTCALL poolCopyStringNoFinish(STRING_POOL *pool, - const XML_Char *s); +static XML_Bool poolGrow(STRING_POOL *pool); +static bool poolGrowUntil(STRING_POOL *pool, size_t needed); +static const XML_Char *poolCopyString(STRING_POOL *pool, const XML_Char *s); +static const XML_Char *poolCopyStringNoFinish(STRING_POOL *pool, + const XML_Char *s); static const XML_Char *poolCopyStringN(STRING_POOL *pool, const XML_Char *s, int n); -static const XML_Char *FASTCALL poolAppendString(STRING_POOL *pool, - const XML_Char *s); +static const XML_Char *poolAppendString(STRING_POOL *pool, const XML_Char *s); -static int FASTCALL nextScaffoldPart(XML_Parser parser); +static int nextScaffoldPart(XML_Parser parser); static XML_Content *build_model(XML_Parser parser); static ELEMENT_TYPE *getElementType(XML_Parser parser, const ENCODING *enc, const char *ptr, const char *end); @@ -1572,7 +1569,7 @@ parserInit(XML_Parser parser, const XML_ } /* moves list of bindings to m_freeBindingList */ -static void FASTCALL +static void moveToFreeBindingList(XML_Parser parser, BINDING *bindings) { while (bindings) { BINDING *b = bindings; @@ -1845,7 +1842,7 @@ XML_ExternalEntityParserCreate(XML_Parse return parser; } -static void FASTCALL +static void destroyBindings(BINDING *bindings, XML_Parser parser) { for (;;) { BINDING *b = bindings; @@ -3119,7 +3116,7 @@ storeRawNames(XML_Parser parser) { return XML_TRUE; } -static enum XML_Error PTRCALL +static enum XML_Error contentProcessor(XML_Parser parser, const char *start, const char *end, const char **endPtr) { enum XML_Error result = doContent( @@ -3133,7 +3130,7 @@ contentProcessor(XML_Parser parser, cons return result; } -static enum XML_Error PTRCALL +static enum XML_Error externalEntityInitProcessor(XML_Parser parser, const char *start, const char *end, const char **endPtr) { enum XML_Error result = initializeEncoding(parser); @@ -3143,7 +3140,7 @@ externalEntityInitProcessor(XML_Parser p return externalEntityInitProcessor2(parser, start, end, endPtr); } -static enum XML_Error PTRCALL +static enum XML_Error externalEntityInitProcessor2(XML_Parser parser, const char *start, const char *end, const char **endPtr) { const char *next = start; /* XmlContentTok doesn't always set the last arg */ @@ -3188,7 +3185,7 @@ externalEntityInitProcessor2(XML_Parser return externalEntityInitProcessor3(parser, start, end, endPtr); } -static enum XML_Error PTRCALL +static enum XML_Error externalEntityInitProcessor3(XML_Parser parser, const char *start, const char *end, const char **endPtr) { int tok; @@ -3240,7 +3237,7 @@ externalEntityInitProcessor3(XML_Parser return externalEntityContentProcessor(parser, start, end, endPtr); } -static enum XML_Error PTRCALL +static enum XML_Error externalEntityContentProcessor(XML_Parser parser, const char *start, const char *end, const char **endPtr) { enum XML_Error result @@ -4502,6 +4499,7 @@ addBinding(XML_Parser parser, PREFIX *pr /* Detect and prevent integer overflow */ if (len > SIZE_MAX - EXPAND_SPARE || len + EXPAND_SPARE > SIZE_MAX / sizeof(XML_Char)) { + FREE(parser, b); return XML_ERROR_NO_MEMORY; } @@ -4539,7 +4537,7 @@ addBinding(XML_Parser parser, PREFIX *pr /* The idea here is to avoid using stack for each CDATA section when the whole file is parsed with one call. */ -static enum XML_Error PTRCALL +static enum XML_Error cdataSectionProcessor(XML_Parser parser, const char *start, const char *end, const char **endPtr) { enum XML_Error result = doCdataSection( @@ -4705,7 +4703,7 @@ doCdataSection(XML_Parser parser, const /* The idea here is to avoid using stack for each IGNORE section when the whole file is parsed with one call. */ -static enum XML_Error PTRCALL +static enum XML_Error ignoreSectionProcessor(XML_Parser parser, const char *start, const char *end, const char **endPtr) { enum XML_Error result @@ -4975,7 +4973,7 @@ handleUnknownEncoding(XML_Parser parser, return XML_ERROR_UNKNOWN_ENCODING; } -static enum XML_Error PTRCALL +static enum XML_Error prologInitProcessor(XML_Parser parser, const char *s, const char *end, const char **nextPtr) { enum XML_Error result = initializeEncoding(parser); @@ -4987,7 +4985,7 @@ prologInitProcessor(XML_Parser parser, c #ifdef XML_DTD -static enum XML_Error PTRCALL +static enum XML_Error externalParEntInitProcessor(XML_Parser parser, const char *s, const char *end, const char **nextPtr) { enum XML_Error result = initializeEncoding(parser); @@ -4996,7 +4994,7 @@ externalParEntInitProcessor(XML_Parser p /* we know now that XML_Parse(Buffer) has been called, so we consider the external parameter entity read */ - parser->m_dtd->paramEntityRead = XML_TRUE; + parser->m_dtd->paramEntityRead = true; if (parser->m_prologState.inEntityValue) { parser->m_processor = entityValueInitProcessor; @@ -5007,7 +5005,7 @@ externalParEntInitProcessor(XML_Parser p } } -static enum XML_Error PTRCALL +static enum XML_Error entityValueInitProcessor(XML_Parser parser, const char *s, const char *end, const char **nextPtr) { int tok; @@ -5091,7 +5089,7 @@ entityValueInitProcessor(XML_Parser pars } } -static enum XML_Error PTRCALL +static enum XML_Error externalParEntProcessor(XML_Parser parser, const char *s, const char *end, const char **nextPtr) { const char *next = s; @@ -5137,7 +5135,7 @@ externalParEntProcessor(XML_Parser parse XML_ACCOUNT_DIRECT); } -static enum XML_Error PTRCALL +static enum XML_Error entityValueProcessor(XML_Parser parser, const char *s, const char *end, const char **nextPtr) { const char *start = s; @@ -5184,7 +5182,7 @@ entityValueProcessor(XML_Parser parser, #endif /* XML_DTD */ -static enum XML_Error PTRCALL +static enum XML_Error prologProcessor(XML_Parser parser, const char *s, const char *end, const char **nextPtr) { const char *next = s; @@ -5430,7 +5428,7 @@ doProlog(XML_Parser parser, const ENCODI } if (parser->m_useForeignDTD) entity->base = parser->m_curBase; - dtd->paramEntityRead = XML_FALSE; + dtd->paramEntityRead = false; beforeHandler(parser); const int status = parser->m_externalEntityRefHandler( parser->m_externalEntityRefHandlerArg, 0, entity->base, @@ -5480,7 +5478,7 @@ doProlog(XML_Parser parser, const ENCODI if (! entity) return XML_ERROR_NO_MEMORY; entity->base = parser->m_curBase; - dtd->paramEntityRead = XML_FALSE; + dtd->paramEntityRead = false; beforeHandler(parser); const int status = parser->m_externalEntityRefHandler( parser->m_externalEntityRefHandlerArg, 0, entity->base, @@ -5823,7 +5821,7 @@ doProlog(XML_Parser parser, const ENCODI } else { poolFinish(&dtd->pool); parser->m_declEntity->publicId = NULL; - parser->m_declEntity->is_param = XML_FALSE; + parser->m_declEntity->is_param = false; /* if we have a parent parser or are reading an internal parameter entity, then the entity declaration is not considered "internal" */ @@ -5853,7 +5851,7 @@ doProlog(XML_Parser parser, const ENCODI } else { poolFinish(&dtd->pool); parser->m_declEntity->publicId = NULL; - parser->m_declEntity->is_param = XML_TRUE; + parser->m_declEntity->is_param = true; /* if we have a parent parser or are reading an internal parameter entity, then the entity declaration is not considered "internal" */ @@ -6088,8 +6086,7 @@ doProlog(XML_Parser parser, const ENCODI return XML_ERROR_RECURSIVE_ENTITY_REF; if (entity->textPtr) { enum XML_Error result; - XML_Bool betweenDecl - = (role == XML_ROLE_PARAM_ENTITY_REF ? XML_TRUE : XML_FALSE); + bool betweenDecl = (role == XML_ROLE_PARAM_ENTITY_REF); result = processEntity(parser, entity, betweenDecl, ENTITY_INTERNAL); if (result != XML_ERROR_NONE) return result; @@ -6097,7 +6094,7 @@ doProlog(XML_Parser parser, const ENCODI break; } if (parser->m_externalEntityRefHandler) { - dtd->paramEntityRead = XML_FALSE; + dtd->paramEntityRead = false; entity->open = true; entityTrackingOnOpen(parser, entity, __LINE__); beforeHandler(parser); @@ -6141,7 +6138,7 @@ doProlog(XML_Parser parser, const ENCODI return XML_ERROR_NO_MEMORY; dtd->scaffLevel = 0; dtd->scaffCount = 0; - dtd->in_eldecl = XML_TRUE; + dtd->in_eldecl = true; handleDefault = XML_FALSE; } break; @@ -6170,7 +6167,7 @@ doProlog(XML_Parser parser, const ENCODI afterHandler(parser); handleDefault = XML_FALSE; } - dtd->in_eldecl = XML_FALSE; + dtd->in_eldecl = false; } break; @@ -6252,7 +6249,7 @@ doProlog(XML_Parser parser, const ENCODI parser->m_handlerArg, parser->m_declElementType->name, model); afterHandler(parser); } - dtd->in_eldecl = XML_FALSE; + dtd->in_eldecl = false; dtd->contentStringLen = 0; } } @@ -6321,7 +6318,7 @@ doProlog(XML_Parser parser, const ENCODI /* not reached */ } -static enum XML_Error PTRCALL +static enum XML_Error epilogProcessor(XML_Parser parser, const char *s, const char *end, const char **nextPtr) { parser->m_processor = epilogProcessor; @@ -6400,7 +6397,7 @@ epilogProcessor(XML_Parser parser, const } static enum XML_Error -processEntity(XML_Parser parser, ENTITY *entity, XML_Bool betweenDecl, +processEntity(XML_Parser parser, ENTITY *entity, bool betweenDecl, enum EntityType type) { OPEN_INTERNAL_ENTITY *openEntity, **openEntityList; OPEN_INTERNAL_ENTITY **const freeEntityList = &parser->m_freeEntities; @@ -6436,7 +6433,7 @@ processEntity(XML_Parser parser, ENTITY return XML_ERROR_NO_MEMORY; } entity->open = true; - entity->hasMore = XML_TRUE; + entity->hasMore = true; #if XML_GE == 1 entityTrackingOnOpen(parser, entity, __LINE__); #endif @@ -6458,7 +6455,7 @@ processEntity(XML_Parser parser, ENTITY return XML_ERROR_NONE; } -static enum XML_Error PTRCALL +static enum XML_Error internalEntityProcessor(XML_Parser parser, const char *s, const char *end, const char **nextPtr) { UNUSED_P(s); @@ -6508,7 +6505,7 @@ internalEntityProcessor(XML_Parser parse // Entity is complete. We cannot close it here since we need to first // process its possible inner entities (which are added to the // m_openInternalEntities during doProlog or doContent calls above) - entity->hasMore = XML_FALSE; + entity->hasMore = false; if (! entity->is_param && (openEntity->startTagLevel != parser->m_tagLevel)) { return XML_ERROR_ASYNC_ENTITY; @@ -6540,7 +6537,7 @@ internalEntityProcessor(XML_Parser parse return XML_ERROR_NONE; } -static enum XML_Error PTRCALL +static enum XML_Error errorProcessor(XML_Parser parser, const char *s, const char *end, const char **nextPtr) { UNUSED_P(s); @@ -6591,7 +6588,7 @@ storeAttributeValue(XML_Parser parser, c // Entity is complete. We cannot close it here since we need to first // process its possible inner entities (which are added to the // m_openAttributeEntities during appendAttributeValue) - entity->hasMore = XML_FALSE; + entity->hasMore = false; continue; } // End of entity processing, "if" block skips the rest @@ -6899,7 +6896,7 @@ storeEntityValue(XML_Parser parser, cons } if (entity->systemId) { if (parser->m_externalEntityRefHandler) { - dtd->paramEntityRead = XML_FALSE; + dtd->paramEntityRead = false; entity->open = true; entityTrackingOnOpen(parser, entity, __LINE__); beforeHandler(parser); @@ -7051,7 +7048,7 @@ callStoreEntityValue(XML_Parser parser, // Entity is complete. We cannot close it here since we need to first // process its possible inner entities (which are added to the // m_openValueEntities during storeEntityValue) - entity->hasMore = XML_FALSE; + entity->hasMore = false; continue; } // End of entity processing, "if" block skips the rest @@ -7113,7 +7110,7 @@ storeSelfEntityValue(XML_Parser parser, #endif /* XML_GE == 0 */ -static void FASTCALL +static void normalizeLines(XML_Char *s) { XML_Char *p; for (;; s++) { @@ -7279,7 +7276,7 @@ defineAttribute(ELEMENT_TYPE *type, ATTR att->value = value; att->isCdata = isCdata; if (! isCdata) - attId->maybeTokenized = XML_TRUE; + attId->maybeTokenized = true; NAME_AND_DEFAULT_ATTRIBUTE *const nameAndDefaultAttribute = (NAME_AND_DEFAULT_ATTRIBUTE *)lookup( @@ -7364,7 +7361,7 @@ getAttributeId(XML_Parser parser, const else id->prefix = (PREFIX *)lookup(parser, &dtd->prefixes, name + 6, sizeof(PREFIX)); - id->xmlns = XML_TRUE; + id->xmlns = true; } else { int i; for (i = 0; name[i]; i++) { @@ -7554,7 +7551,7 @@ setContext(XML_Parser parser, const XML_ return XML_TRUE; } -static void FASTCALL +static void normalizePublicId(XML_Char *publicId) { XML_Char *p = publicId; XML_Char *s; @@ -7587,13 +7584,13 @@ dtdCreate(XML_Parser parser) { hashTableInit(&(p->attributeIds), parser); hashTableInit(&(p->prefixes), parser); #ifdef XML_DTD - p->paramEntityRead = XML_FALSE; + p->paramEntityRead = false; hashTableInit(&(p->paramEntities), parser); #endif /* XML_DTD */ p->defaultPrefix.name = NULL; p->defaultPrefix.binding = NULL; - p->in_eldecl = XML_FALSE; + p->in_eldecl = false; p->scaffIndex = NULL; p->scaffIndexSize = 0; p->scaffold = NULL; @@ -7621,7 +7618,7 @@ dtdReset(DTD *p, XML_Parser parser) { } hashTableClear(&(p->generalEntities)); #ifdef XML_DTD - p->paramEntityRead = XML_FALSE; + p->paramEntityRead = false; hashTableClear(&(p->paramEntities)); #endif /* XML_DTD */ hashTableClear(&(p->elementTypes)); @@ -7632,7 +7629,7 @@ dtdReset(DTD *p, XML_Parser parser) { p->defaultPrefix.name = NULL; p->defaultPrefix.binding = NULL; - p->in_eldecl = XML_FALSE; + p->in_eldecl = false; FREE(parser, p->scaffIndex); p->scaffIndex = NULL; @@ -7900,7 +7897,7 @@ copyEntityTable(XML_Parser oldParser, HA // Compares two strings `s1` and `s2` whereas: // - `s2` is zero-terminated but // - `s1` is made up of exactly (not just up to) `s1len` non-zero characters. -static XML_Bool FASTCALL +static XML_Bool keyeq(KEY s1, size_t s1len, KEY s2) { #ifdef XML_UNICODE # ifdef XML_UNICODE_WCHAR_T @@ -7930,7 +7927,7 @@ copy_salt_to_sipkey(XML_Parser parser, s *key = rootParser->m_hash_secret_salt_128; } -static unsigned long FASTCALL +static unsigned long hash(XML_Parser parser, KEY s, size_t keyLen) { struct siphash state; struct sipkey key; @@ -8072,7 +8069,7 @@ lookup(XML_Parser parser, HASH_TABLE *ta return lookupWithLength(parser, table, name, keylen(name), createSize); } -static void FASTCALL +static void hashTableClear(HASH_TABLE *table) { size_t i; for (i = 0; i < table->size; i++) { @@ -8082,7 +8079,7 @@ hashTableClear(HASH_TABLE *table) { table->used = 0; } -static void FASTCALL +static void hashTableDestroy(HASH_TABLE *table) { size_t i; for (i = 0; i < table->size; i++) @@ -8090,7 +8087,7 @@ hashTableDestroy(HASH_TABLE *table) { FREE(table->parser, table->v); } -static void FASTCALL +static void hashTableInit(HASH_TABLE *p, XML_Parser parser) { p->power = 0; p->size = 0; @@ -8099,13 +8096,13 @@ hashTableInit(HASH_TABLE *p, XML_Parser p->parser = parser; } -static void FASTCALL +static void hashTableIterInit(HASH_TABLE_ITER *iter, const HASH_TABLE *table) { iter->p = table->v; iter->end = iter->p ? iter->p + table->size : NULL; } -static NAMED *FASTCALL +static NAMED * hashTableIterNext(HASH_TABLE_ITER *iter) { while (iter->p != iter->end) { NAMED *tem = *(iter->p)++; @@ -8115,7 +8112,7 @@ hashTableIterNext(HASH_TABLE_ITER *iter) return NULL; } -static void FASTCALL +static void poolInit(STRING_POOL *pool, XML_Parser parser) { pool->blocks = NULL; pool->freeBlocks = NULL; @@ -8125,7 +8122,7 @@ poolInit(STRING_POOL *pool, XML_Parser p pool->parser = parser; } -static void FASTCALL +static void poolClear(STRING_POOL *pool) { if (! pool->freeBlocks) pool->freeBlocks = pool->blocks; @@ -8144,7 +8141,7 @@ poolClear(STRING_POOL *pool) { pool->end = NULL; } -static void FASTCALL +static void poolDestroy(STRING_POOL *pool) { BLOCK *p = pool->blocks; while (p) { @@ -8177,7 +8174,7 @@ poolAppend(STRING_POOL *pool, const ENCO return pool->start; } -static const XML_Char *FASTCALL +static const XML_Char * poolCopyString(STRING_POOL *pool, const XML_Char *s) { if (! poolAppendChars(pool, s, xcslen(s) + /*null terminator*/ 1)) return NULL; @@ -8188,7 +8185,7 @@ poolCopyString(STRING_POOL *pool, const // A version of `poolCopyString` that does not call `poolFinish` // and reverts any partial advancement upon failure. -static const XML_Char *FASTCALL +static const XML_Char * poolCopyStringNoFinish(STRING_POOL *pool, const XML_Char *s) { const XML_Char *const original = s; do { @@ -8226,7 +8223,7 @@ poolCopyStringN(STRING_POOL *pool, const return s; } -static const XML_Char *FASTCALL +static const XML_Char * poolAppendString(STRING_POOL *pool, const XML_Char *s) { if (! poolAppendChars(pool, s, xcslen(s))) return NULL; @@ -8271,7 +8268,7 @@ poolBytesToAllocateFor(int blockSize) { } } -static XML_Bool FASTCALL +static XML_Bool poolGrow(STRING_POOL *pool) { if (pool->freeBlocks) { if (pool->start == NULL) { @@ -8376,7 +8373,7 @@ poolGrow(STRING_POOL *pool) { return XML_TRUE; } -static bool FASTCALL +static bool poolGrowUntil(STRING_POOL *pool, size_t needed) { for (;;) { const size_t available = pool->end - pool->ptr; @@ -8389,7 +8386,7 @@ poolGrowUntil(STRING_POOL *pool, size_t } } -static int FASTCALL +static int nextScaffoldPart(XML_Parser parser) { DTD *const dtd = parser->m_dtd; /* save one level of indirection */ CONTENT_SCAFFOLD *me; Index: lib/libexpat/lib/xmlrole.c =================================================================== RCS file: /cvs/src/lib/libexpat/lib/xmlrole.c,v diff -u -p -r1.15.4.1 xmlrole.c --- lib/libexpat/lib/xmlrole.c 20 Aug 2026 07:49:22 -0000 1.15.4.1 +++ lib/libexpat/lib/xmlrole.c 2 Oct 2026 22:01:22 -0000 @@ -121,9 +121,8 @@ static const char KW_SYSTEM[] # define setTopLevel(state) ((state)->handler = internalSubset) #endif /* not XML_DTD */ -typedef int PTRCALL PROLOG_HANDLER(PROLOG_STATE *state, int tok, - const char *ptr, const char *end, - const ENCODING *enc); +typedef int PROLOG_HANDLER(PROLOG_STATE *state, int tok, const char *ptr, + const char *end, const ENCODING *enc); static PROLOG_HANDLER prolog0, prolog1, prolog2, doctype0, doctype1, doctype2, doctype3, doctype4, doctype5, internalSubset, entity0, entity1, entity2, @@ -137,9 +136,9 @@ static PROLOG_HANDLER prolog0, prolog1, #endif /* XML_DTD */ declClose, error; -static int FASTCALL common(PROLOG_STATE *state, int tok); +static int common(PROLOG_STATE *state, int tok); -static int PTRCALL +static int prolog0(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc) { switch (tok) { @@ -170,7 +169,7 @@ prolog0(PROLOG_STATE *state, int tok, co return common(state, tok); } -static int PTRCALL +static int prolog1(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc) { switch (tok) { @@ -202,7 +201,7 @@ prolog1(PROLOG_STATE *state, int tok, co return common(state, tok); } -static int PTRCALL +static int prolog2(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc) { UNUSED_P(ptr); @@ -222,7 +221,7 @@ prolog2(PROLOG_STATE *state, int tok, co return common(state, tok); } -static int PTRCALL +static int doctype0(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc) { UNUSED_P(ptr); @@ -239,7 +238,7 @@ doctype0(PROLOG_STATE *state, int tok, c return common(state, tok); } -static int PTRCALL +static int doctype1(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc) { switch (tok) { @@ -265,7 +264,7 @@ doctype1(PROLOG_STATE *state, int tok, c return common(state, tok); } -static int PTRCALL +static int doctype2(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc) { UNUSED_P(ptr); @@ -281,7 +280,7 @@ doctype2(PROLOG_STATE *state, int tok, c return common(state, tok); } -static int PTRCALL +static int doctype3(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc) { UNUSED_P(ptr); @@ -297,7 +296,7 @@ doctype3(PROLOG_STATE *state, int tok, c return common(state, tok); } -static int PTRCALL +static int doctype4(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc) { UNUSED_P(ptr); @@ -316,7 +315,7 @@ doctype4(PROLOG_STATE *state, int tok, c return common(state, tok); } -static int PTRCALL +static int doctype5(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc) { UNUSED_P(ptr); @@ -332,7 +331,7 @@ doctype5(PROLOG_STATE *state, int tok, c return common(state, tok); } -static int PTRCALL +static int internalSubset(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc) { switch (tok) { @@ -377,7 +376,7 @@ internalSubset(PROLOG_STATE *state, int #ifdef XML_DTD -static int PTRCALL +static int externalSubset0(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc) { state->handler = externalSubset1; @@ -386,7 +385,7 @@ externalSubset0(PROLOG_STATE *state, int return externalSubset1(state, tok, ptr, end, enc); } -static int PTRCALL +static int externalSubset1(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc) { switch (tok) { @@ -414,7 +413,7 @@ externalSubset1(PROLOG_STATE *state, int #endif /* XML_DTD */ -static int PTRCALL +static int entity0(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc) { UNUSED_P(ptr); @@ -433,7 +432,7 @@ entity0(PROLOG_STATE *state, int tok, co return common(state, tok); } -static int PTRCALL +static int entity1(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc) { UNUSED_P(ptr); @@ -449,7 +448,7 @@ entity1(PROLOG_STATE *state, int tok, co return common(state, tok); } -static int PTRCALL +static int entity2(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc) { switch (tok) { @@ -473,7 +472,7 @@ entity2(PROLOG_STATE *state, int tok, co return common(state, tok); } -static int PTRCALL +static int entity3(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc) { UNUSED_P(ptr); @@ -489,7 +488,7 @@ entity3(PROLOG_STATE *state, int tok, co return common(state, tok); } -static int PTRCALL +static int entity4(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc) { UNUSED_P(ptr); @@ -505,7 +504,7 @@ entity4(PROLOG_STATE *state, int tok, co return common(state, tok); } -static int PTRCALL +static int entity5(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc) { switch (tok) { @@ -524,7 +523,7 @@ entity5(PROLOG_STATE *state, int tok, co return common(state, tok); } -static int PTRCALL +static int entity6(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc) { UNUSED_P(ptr); @@ -541,7 +540,7 @@ entity6(PROLOG_STATE *state, int tok, co return common(state, tok); } -static int PTRCALL +static int entity7(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc) { switch (tok) { @@ -565,7 +564,7 @@ entity7(PROLOG_STATE *state, int tok, co return common(state, tok); } -static int PTRCALL +static int entity8(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc) { UNUSED_P(ptr); @@ -581,7 +580,7 @@ entity8(PROLOG_STATE *state, int tok, co return common(state, tok); } -static int PTRCALL +static int entity9(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc) { UNUSED_P(ptr); @@ -597,7 +596,7 @@ entity9(PROLOG_STATE *state, int tok, co return common(state, tok); } -static int PTRCALL +static int entity10(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc) { UNUSED_P(ptr); @@ -613,7 +612,7 @@ entity10(PROLOG_STATE *state, int tok, c return common(state, tok); } -static int PTRCALL +static int notation0(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc) { UNUSED_P(ptr); @@ -629,7 +628,7 @@ notation0(PROLOG_STATE *state, int tok, return common(state, tok); } -static int PTRCALL +static int notation1(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc) { switch (tok) { @@ -649,7 +648,7 @@ notation1(PROLOG_STATE *state, int tok, return common(state, tok); } -static int PTRCALL +static int notation2(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc) { UNUSED_P(ptr); @@ -665,7 +664,7 @@ notation2(PROLOG_STATE *state, int tok, return common(state, tok); } -static int PTRCALL +static int notation3(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc) { UNUSED_P(ptr); @@ -682,7 +681,7 @@ notation3(PROLOG_STATE *state, int tok, return common(state, tok); } -static int PTRCALL +static int notation4(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc) { UNUSED_P(ptr); @@ -702,7 +701,7 @@ notation4(PROLOG_STATE *state, int tok, return common(state, tok); } -static int PTRCALL +static int attlist0(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc) { UNUSED_P(ptr); @@ -719,7 +718,7 @@ attlist0(PROLOG_STATE *state, int tok, c return common(state, tok); } -static int PTRCALL +static int attlist1(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc) { UNUSED_P(ptr); @@ -739,7 +738,7 @@ attlist1(PROLOG_STATE *state, int tok, c return common(state, tok); } -static int PTRCALL +static int attlist2(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc) { switch (tok) { @@ -769,7 +768,7 @@ attlist2(PROLOG_STATE *state, int tok, c return common(state, tok); } -static int PTRCALL +static int attlist3(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc) { UNUSED_P(ptr); @@ -787,7 +786,7 @@ attlist3(PROLOG_STATE *state, int tok, c return common(state, tok); } -static int PTRCALL +static int attlist4(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc) { UNUSED_P(ptr); @@ -806,7 +805,7 @@ attlist4(PROLOG_STATE *state, int tok, c return common(state, tok); } -static int PTRCALL +static int attlist5(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc) { UNUSED_P(ptr); @@ -822,7 +821,7 @@ attlist5(PROLOG_STATE *state, int tok, c return common(state, tok); } -static int PTRCALL +static int attlist6(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc) { UNUSED_P(ptr); @@ -838,7 +837,7 @@ attlist6(PROLOG_STATE *state, int tok, c return common(state, tok); } -static int PTRCALL +static int attlist7(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc) { UNUSED_P(ptr); @@ -858,7 +857,7 @@ attlist7(PROLOG_STATE *state, int tok, c } /* default value */ -static int PTRCALL +static int attlist8(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc) { switch (tok) { @@ -888,7 +887,7 @@ attlist8(PROLOG_STATE *state, int tok, c return common(state, tok); } -static int PTRCALL +static int attlist9(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc) { UNUSED_P(ptr); @@ -904,7 +903,7 @@ attlist9(PROLOG_STATE *state, int tok, c return common(state, tok); } -static int PTRCALL +static int element0(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc) { UNUSED_P(ptr); @@ -921,7 +920,7 @@ element0(PROLOG_STATE *state, int tok, c return common(state, tok); } -static int PTRCALL +static int element1(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc) { switch (tok) { @@ -947,7 +946,7 @@ element1(PROLOG_STATE *state, int tok, c return common(state, tok); } -static int PTRCALL +static int element2(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc) { switch (tok) { @@ -981,7 +980,7 @@ element2(PROLOG_STATE *state, int tok, c return common(state, tok); } -static int PTRCALL +static int element3(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc) { UNUSED_P(ptr); @@ -1005,7 +1004,7 @@ element3(PROLOG_STATE *state, int tok, c return common(state, tok); } -static int PTRCALL +static int element4(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc) { UNUSED_P(ptr); @@ -1022,7 +1021,7 @@ element4(PROLOG_STATE *state, int tok, c return common(state, tok); } -static int PTRCALL +static int element5(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc) { UNUSED_P(ptr); @@ -1042,7 +1041,7 @@ element5(PROLOG_STATE *state, int tok, c return common(state, tok); } -static int PTRCALL +static int element6(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc) { UNUSED_P(ptr); @@ -1071,7 +1070,7 @@ element6(PROLOG_STATE *state, int tok, c return common(state, tok); } -static int PTRCALL +static int element7(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc) { UNUSED_P(ptr); @@ -1120,7 +1119,7 @@ element7(PROLOG_STATE *state, int tok, c #ifdef XML_DTD -static int PTRCALL +static int condSect0(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc) { switch (tok) { @@ -1140,7 +1139,7 @@ condSect0(PROLOG_STATE *state, int tok, return common(state, tok); } -static int PTRCALL +static int condSect1(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc) { UNUSED_P(ptr); @@ -1157,7 +1156,7 @@ condSect1(PROLOG_STATE *state, int tok, return common(state, tok); } -static int PTRCALL +static int condSect2(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc) { UNUSED_P(ptr); @@ -1175,7 +1174,7 @@ condSect2(PROLOG_STATE *state, int tok, #endif /* XML_DTD */ -static int PTRCALL +static int declClose(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc) { UNUSED_P(ptr); @@ -1211,7 +1210,7 @@ declClose(PROLOG_STATE *state, int tok, * * LCOV_EXCL_START */ -static int PTRCALL +static int error(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc) { UNUSED_P(state); @@ -1223,7 +1222,7 @@ error(PROLOG_STATE *state, int tok, cons } /* LCOV_EXCL_STOP */ -static int FASTCALL +static int common(PROLOG_STATE *state, int tok) { #ifdef XML_DTD if (! state->documentEntity && tok == XML_TOK_PARAM_ENTITY_REF) Index: lib/libexpat/lib/xmlrole.h =================================================================== RCS file: /cvs/src/lib/libexpat/lib/xmlrole.h,v diff -u -p -r1.7.6.1 xmlrole.h --- lib/libexpat/lib/xmlrole.h 20 Aug 2026 07:49:22 -0000 1.7.6.1 +++ lib/libexpat/lib/xmlrole.h 2 Oct 2026 22:01:22 -0000 @@ -112,8 +112,8 @@ enum { }; typedef struct prolog_state { - int(PTRCALL *handler)(struct prolog_state *state, int tok, const char *ptr, - const char *end, const ENCODING *enc); + int (*handler)(struct prolog_state *state, int tok, const char *ptr, + const char *end, const ENCODING *enc); unsigned level; int role_none; # ifdef XML_DTD Index: lib/libexpat/lib/xmltok.c =================================================================== RCS file: /cvs/src/lib/libexpat/lib/xmltok.c,v diff -u -p -r1.20.4.1 xmltok.c --- lib/libexpat/lib/xmltok.c 20 Aug 2026 07:49:22 -0000 1.20.4.1 +++ lib/libexpat/lib/xmltok.c 2 Oct 2026 22:01:22 -0000 @@ -136,20 +136,20 @@ : ((p)[1] & 0x80) == 0 \ || ((*p) == 0xF4 ? (p)[1] > 0x8F : ((p)[1] & 0xC0) == 0xC0))) -static int PTRFASTCALL +static int isNever(const ENCODING *enc, const char *p) { UNUSED_P(enc); UNUSED_P(p); return 0; } -static int PTRFASTCALL +static int utf8_isName2(const ENCODING *enc, const char *p) { UNUSED_P(enc); return UTF8_GET_NAMING2(namePages, (const unsigned char *)p); } -static int PTRFASTCALL +static int utf8_isName3(const ENCODING *enc, const char *p) { UNUSED_P(enc); return UTF8_GET_NAMING3(namePages, (const unsigned char *)p); @@ -157,13 +157,13 @@ utf8_isName3(const ENCODING *enc, const #define utf8_isName4 isNever -static int PTRFASTCALL +static int utf8_isNmstrt2(const ENCODING *enc, const char *p) { UNUSED_P(enc); return UTF8_GET_NAMING2(nmstrtPages, (const unsigned char *)p); } -static int PTRFASTCALL +static int utf8_isNmstrt3(const ENCODING *enc, const char *p) { UNUSED_P(enc); return UTF8_GET_NAMING3(nmstrtPages, (const unsigned char *)p); @@ -171,19 +171,19 @@ utf8_isNmstrt3(const ENCODING *enc, cons #define utf8_isNmstrt4 isNever -static int PTRFASTCALL +static int utf8_isInvalid2(const ENCODING *enc, const char *p) { UNUSED_P(enc); return UTF8_INVALID2((const unsigned char *)p); } -static int PTRFASTCALL +static int utf8_isInvalid3(const ENCODING *enc, const char *p) { UNUSED_P(enc); return UTF8_INVALID3((const unsigned char *)p); } -static int PTRFASTCALL +static int utf8_isInvalid4(const ENCODING *enc, const char *p) { UNUSED_P(enc); return UTF8_INVALID4((const unsigned char *)p); @@ -193,21 +193,21 @@ struct normal_encoding { ENCODING enc; unsigned char type[256]; #ifdef XML_MIN_SIZE - int(PTRFASTCALL *byteType)(const ENCODING *, const char *); - int(PTRFASTCALL *isNameMin)(const ENCODING *, const char *); - int(PTRFASTCALL *isNmstrtMin)(const ENCODING *, const char *); - int(PTRFASTCALL *byteToAscii)(const ENCODING *, const char *); - int(PTRCALL *charMatches)(const ENCODING *, const char *, int); + int (*byteType)(const ENCODING *, const char *); + int (*isNameMin)(const ENCODING *, const char *); + int (*isNmstrtMin)(const ENCODING *, const char *); + int (*byteToAscii)(const ENCODING *, const char *); + int (*charMatches)(const ENCODING *, const char *, int); #endif /* XML_MIN_SIZE */ - int(PTRFASTCALL *isName2)(const ENCODING *, const char *); - int(PTRFASTCALL *isName3)(const ENCODING *, const char *); - int(PTRFASTCALL *isName4)(const ENCODING *, const char *); - int(PTRFASTCALL *isNmstrt2)(const ENCODING *, const char *); - int(PTRFASTCALL *isNmstrt3)(const ENCODING *, const char *); - int(PTRFASTCALL *isNmstrt4)(const ENCODING *, const char *); - int(PTRFASTCALL *isInvalid2)(const ENCODING *, const char *); - int(PTRFASTCALL *isInvalid3)(const ENCODING *, const char *); - int(PTRFASTCALL *isInvalid4)(const ENCODING *, const char *); + int (*isName2)(const ENCODING *, const char *); + int (*isName3)(const ENCODING *, const char *); + int (*isName4)(const ENCODING *, const char *); + int (*isNmstrt2)(const ENCODING *, const char *); + int (*isNmstrt3)(const ENCODING *, const char *); + int (*isNmstrt4)(const ENCODING *, const char *); + int (*isInvalid2)(const ENCODING *, const char *); + int (*isInvalid3)(const ENCODING *, const char *); + int (*isInvalid4)(const ENCODING *, const char *); }; #define AS_NORMAL_ENCODING(enc) ((const struct normal_encoding *)(enc)) @@ -232,7 +232,20 @@ struct normal_encoding { /* isNmstrt2 */ NULL, /* isNmstrt3 */ NULL, /* isNmstrt4 */ NULL, \ /* isInvalid2 */ NULL, /* isInvalid3 */ NULL, /* isInvalid4 */ NULL -static int FASTCALL checkCharRefNumber(int result); +/* Like NULL_VTABLE but with a real isInvalid4 so the UTF-16 encodings reject a + high surrogate that is not followed by a low surrogate. Only needed for the + XML_MIN_SIZE build, where the shared tokenizer dispatches through the vtable; + the regular build inlines the same check via IS_INVALID_CHAR. */ +#ifdef XML_MIN_SIZE +# define UTF16_NULL_VTABLE(E) \ + /* isName2 */ NULL, /* isName3 */ NULL, /* isName4 */ NULL, \ + /* isNmstrt2 */ NULL, /* isNmstrt3 */ NULL, /* isNmstrt4 */ NULL, \ + /* isInvalid2 */ NULL, /* isInvalid3 */ NULL, E##isInvalid4 +#else +# define UTF16_NULL_VTABLE(E) NULL_VTABLE +#endif + +static int checkCharRefNumber(int result); #include "xmltok_impl.h" #include "ascii.h" @@ -253,7 +266,7 @@ static int FASTCALL checkCharRefNumber(i (((const struct normal_encoding *)(enc))->type[(unsigned char)*(p)]) #ifdef XML_MIN_SIZE -static int PTRFASTCALL +static int sb_byteType(const ENCODING *enc, const char *p) { return SB_BYTE_TYPE(enc, p); } @@ -264,7 +277,7 @@ sb_byteType(const ENCODING *enc, const c #ifdef XML_MIN_SIZE # define BYTE_TO_ASCII(enc, p) (AS_NORMAL_ENCODING(enc)->byteToAscii(enc, p)) -static int PTRFASTCALL +static int sb_byteToAscii(const ENCODING *enc, const char *p) { UNUSED_P(enc); return *p; @@ -297,7 +310,7 @@ sb_byteToAscii(const ENCODING *enc, cons #ifdef XML_MIN_SIZE # define CHAR_MATCHES(enc, p, c) \ (AS_NORMAL_ENCODING(enc)->charMatches(enc, p, c)) -static int PTRCALL +static int sb_charMatches(const ENCODING *enc, const char *p, int c) { UNUSED_P(enc); return *p == c; @@ -368,7 +381,7 @@ _INTERNAL_trim_to_complete_utf8_characte *fromLimRef = fromLim; } -static enum XML_Convert_Result PTRCALL +static enum XML_Convert_Result utf8_toUtf8(const ENCODING *enc, const char **fromP, const char *fromLim, char **toP, const char *toLim) { bool input_incomplete = false; @@ -407,7 +420,7 @@ utf8_toUtf8(const ENCODING *enc, const c return XML_CONVERT_COMPLETED; } -static enum XML_Convert_Result PTRCALL +static enum XML_Convert_Result utf8_toUtf16(const ENCODING *enc, const char **fromP, const char *fromLim, unsigned short **toP, const unsigned short *toLim) { enum XML_Convert_Result res = XML_CONVERT_COMPLETED; @@ -505,7 +518,7 @@ static const struct normal_encoding inte }, STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_)}; -static enum XML_Convert_Result PTRCALL +static enum XML_Convert_Result latin1_toUtf8(const ENCODING *enc, const char **fromP, const char *fromLim, char **toP, const char *toLim) { UNUSED_P(enc); @@ -528,7 +541,7 @@ latin1_toUtf8(const ENCODING *enc, const } } -static enum XML_Convert_Result PTRCALL +static enum XML_Convert_Result latin1_toUtf16(const ENCODING *enc, const char **fromP, const char *fromLim, unsigned short **toP, const unsigned short *toLim) { UNUSED_P(enc); @@ -563,7 +576,7 @@ static const struct normal_encoding lati }, STANDARD_VTABLE(sb_) NULL_VTABLE}; -static enum XML_Convert_Result PTRCALL +static enum XML_Convert_Result ascii_toUtf8(const ENCODING *enc, const char **fromP, const char *fromLim, char **toP, const char *toLim) { UNUSED_P(enc); @@ -598,7 +611,7 @@ static const struct normal_encoding asci }, STANDARD_VTABLE(sb_) NULL_VTABLE}; -static int PTRFASTCALL +static int unicode_byte_type(char hi, char lo) { switch ((unsigned char)hi) { /* 0xD800-0xDBFF first 16-bit code unit or high surrogate (W1) */ @@ -625,7 +638,7 @@ unicode_byte_type(char hi, char lo) { } #define DEFINE_UTF16_TO_UTF8(E) \ - static enum XML_Convert_Result PTRCALL E##toUtf8( \ + static enum XML_Convert_Result E##toUtf8( \ const ENCODING *enc, const char **fromP, const char *fromLim, \ char **toP, const char *toLim) { \ const char *from = *fromP; \ @@ -702,7 +715,7 @@ unicode_byte_type(char hi, char lo) { } #define DEFINE_UTF16_TO_UTF16(E) \ - static enum XML_Convert_Result PTRCALL E##toUtf16( \ + static enum XML_Convert_Result E##toUtf16( \ const ENCODING *enc, const char **fromP, const char *fromLim, \ unsigned short **toP, const unsigned short *toLim) { \ enum XML_Convert_Result res = XML_CONVERT_COMPLETED; \ @@ -749,38 +762,49 @@ DEFINE_UTF16_TO_UTF16(big2_) UCS2_GET_NAMING(namePages, (unsigned char)p[1], (unsigned char)p[0]) #define LITTLE2_IS_NMSTRT_CHAR_MINBPC(p) \ UCS2_GET_NAMING(nmstrtPages, (unsigned char)p[1], (unsigned char)p[0]) +/* A 4-byte UTF-16 character is a surrogate pair; byteType only reports BT_LEAD4 + for a high surrogate, so the pair is invalid unless the second unit is a low + surrogate (U+DC00..U+DFFF, i.e. high byte 0xDC..0xDF). */ +#define LITTLE2_IS_INVALID_CHAR(p, n) \ + ((n) == 4 && ((unsigned char)(p)[3] & 0xFC) != 0xDC) #ifdef XML_MIN_SIZE -static int PTRFASTCALL +static int little2_byteType(const ENCODING *enc, const char *p) { return LITTLE2_BYTE_TYPE(enc, p); } -static int PTRFASTCALL +static int little2_byteToAscii(const ENCODING *enc, const char *p) { UNUSED_P(enc); return LITTLE2_BYTE_TO_ASCII(p); } -static int PTRCALL +static int little2_charMatches(const ENCODING *enc, const char *p, int c) { UNUSED_P(enc); return LITTLE2_CHAR_MATCHES(p, c); } -static int PTRFASTCALL +static int little2_isNameMin(const ENCODING *enc, const char *p) { UNUSED_P(enc); return LITTLE2_IS_NAME_CHAR_MINBPC(p); } -static int PTRFASTCALL +static int little2_isNmstrtMin(const ENCODING *enc, const char *p) { UNUSED_P(enc); return LITTLE2_IS_NMSTRT_CHAR_MINBPC(p); } +static int +little2_isInvalid4(const ENCODING *enc, const char *p) { + UNUSED_P(enc); + return LITTLE2_IS_INVALID_CHAR(p, 4); +} + # undef VTABLE # define VTABLE VTABLE1, little2_toUtf8, little2_toUtf16 @@ -797,6 +821,7 @@ little2_isNmstrtMin(const ENCODING *enc, # define IS_NAME_CHAR_MINBPC(enc, p) LITTLE2_IS_NAME_CHAR_MINBPC(p) # define IS_NMSTRT_CHAR(enc, p, n) (0) # define IS_NMSTRT_CHAR_MINBPC(enc, p) LITTLE2_IS_NMSTRT_CHAR_MINBPC(p) +# define IS_INVALID_CHAR(enc, p, n) LITTLE2_IS_INVALID_CHAR(p, n) # define XML_TOK_IMPL_C # include "xmltok_impl.c" @@ -828,7 +853,7 @@ static const struct normal_encoding litt # include "asciitab.h" # include "latin1tab.h" }, - STANDARD_VTABLE(little2_) NULL_VTABLE}; + STANDARD_VTABLE(little2_) UTF16_NULL_VTABLE(little2_)}; #endif @@ -846,7 +871,7 @@ static const struct normal_encoding litt #undef BT_COLON #include "latin1tab.h" }, - STANDARD_VTABLE(little2_) NULL_VTABLE}; + STANDARD_VTABLE(little2_) UTF16_NULL_VTABLE(little2_)}; #if BYTEORDER != 4321 @@ -858,7 +883,7 @@ static const struct normal_encoding inte # include "iasciitab.h" # include "latin1tab.h" }, - STANDARD_VTABLE(little2_) NULL_VTABLE}; + STANDARD_VTABLE(little2_) UTF16_NULL_VTABLE(little2_)}; # endif @@ -870,7 +895,7 @@ static const struct normal_encoding inte # undef BT_COLON # include "latin1tab.h" }, - STANDARD_VTABLE(little2_) NULL_VTABLE}; + STANDARD_VTABLE(little2_) UTF16_NULL_VTABLE(little2_)}; #endif @@ -882,38 +907,49 @@ static const struct normal_encoding inte UCS2_GET_NAMING(namePages, (unsigned char)p[0], (unsigned char)p[1]) #define BIG2_IS_NMSTRT_CHAR_MINBPC(p) \ UCS2_GET_NAMING(nmstrtPages, (unsigned char)p[0], (unsigned char)p[1]) +/* A 4-byte UTF-16 character is a surrogate pair; byteType only reports BT_LEAD4 + for a high surrogate, so the pair is invalid unless the second unit is a low + surrogate (U+DC00..U+DFFF, i.e. high byte 0xDC..0xDF). */ +#define BIG2_IS_INVALID_CHAR(p, n) \ + ((n) == 4 && ((unsigned char)(p)[2] & 0xFC) != 0xDC) #ifdef XML_MIN_SIZE -static int PTRFASTCALL +static int big2_byteType(const ENCODING *enc, const char *p) { return BIG2_BYTE_TYPE(enc, p); } -static int PTRFASTCALL +static int big2_byteToAscii(const ENCODING *enc, const char *p) { UNUSED_P(enc); return BIG2_BYTE_TO_ASCII(p); } -static int PTRCALL +static int big2_charMatches(const ENCODING *enc, const char *p, int c) { UNUSED_P(enc); return BIG2_CHAR_MATCHES(p, c); } -static int PTRFASTCALL +static int big2_isNameMin(const ENCODING *enc, const char *p) { UNUSED_P(enc); return BIG2_IS_NAME_CHAR_MINBPC(p); } -static int PTRFASTCALL +static int big2_isNmstrtMin(const ENCODING *enc, const char *p) { UNUSED_P(enc); return BIG2_IS_NMSTRT_CHAR_MINBPC(p); } +static int +big2_isInvalid4(const ENCODING *enc, const char *p) { + UNUSED_P(enc); + return BIG2_IS_INVALID_CHAR(p, 4); +} + # undef VTABLE # define VTABLE VTABLE1, big2_toUtf8, big2_toUtf16 @@ -930,6 +966,7 @@ big2_isNmstrtMin(const ENCODING *enc, co # define IS_NAME_CHAR_MINBPC(enc, p) BIG2_IS_NAME_CHAR_MINBPC(p) # define IS_NMSTRT_CHAR(enc, p, n) (0) # define IS_NMSTRT_CHAR_MINBPC(enc, p) BIG2_IS_NMSTRT_CHAR_MINBPC(p) +# define IS_INVALID_CHAR(enc, p, n) BIG2_IS_INVALID_CHAR(p, n) # define XML_TOK_IMPL_C # include "xmltok_impl.c" @@ -961,7 +998,7 @@ static const struct normal_encoding big2 # include "asciitab.h" # include "latin1tab.h" }, - STANDARD_VTABLE(big2_) NULL_VTABLE}; + STANDARD_VTABLE(big2_) UTF16_NULL_VTABLE(big2_)}; #endif @@ -979,7 +1016,7 @@ static const struct normal_encoding big2 #undef BT_COLON #include "latin1tab.h" }, - STANDARD_VTABLE(big2_) NULL_VTABLE}; + STANDARD_VTABLE(big2_) UTF16_NULL_VTABLE(big2_)}; #if BYTEORDER != 1234 @@ -991,7 +1028,7 @@ static const struct normal_encoding inte # include "iasciitab.h" # include "latin1tab.h" }, - STANDARD_VTABLE(big2_) NULL_VTABLE}; + STANDARD_VTABLE(big2_) UTF16_NULL_VTABLE(big2_)}; # endif @@ -1003,13 +1040,13 @@ static const struct normal_encoding inte # undef BT_COLON # include "latin1tab.h" }, - STANDARD_VTABLE(big2_) NULL_VTABLE}; + STANDARD_VTABLE(big2_) UTF16_NULL_VTABLE(big2_)}; #endif #undef PREFIX -static int FASTCALL +static int streqci(const char *s1, const char *s2) { for (;;) { char c1 = *s1++; @@ -1030,7 +1067,7 @@ streqci(const char *s1, const char *s2) return 1; } -static void PTRCALL +static void initUpdatePosition(const ENCODING *enc, const char *ptr, const char *end, POSITION *pos) { UNUSED_P(enc); @@ -1048,7 +1085,7 @@ toAscii(const ENCODING *enc, const char return buf[0]; } -static int FASTCALL +static int isSpace(int c) { switch (c) { case 0x20: @@ -1154,6 +1191,34 @@ static const char KW_yes[] = {ASCII_y, A static const char KW_no[] = {ASCII_n, ASCII_o, '\0'}; +static const char KW_1_dot[] = {ASCII_1, ASCII_PERIOD, '\0'}; + +/* Checks a version pseudo-attribute value against the VersionNum production. + XML 1.0 Fourth Edition only allows the literal "1.0", but the Fifth + Edition relaxed this to "1." followed by one or more digits, since Expat + only implements 1.0 itself but plans to track the Fifth Edition's laxer + grammar here so that "1.1" and similar aren't rejected only to have that + rejection reverted later. Returns true for a value matching "1.[0-9]+". + val/valEnd bound the value itself; valEnd is the upper bound used when + decoding the individual characters between them. */ +static bool +checkXmlDeclVersionNum(const ENCODING *enc, const char *val, + const char *valEnd) { + if (valEnd - val < 2 * enc->minBytesPerChar + || ! XmlNameMatchesAscii(enc, val, val + 2 * enc->minBytesPerChar, + KW_1_dot)) + return false; + val += 2 * enc->minBytesPerChar; + if (val == valEnd) + return false; + for (; val != valEnd; val += enc->minBytesPerChar) { + int c = toAscii(enc, val, valEnd); + if (c < ASCII_0 || c > ASCII_9) + return false; + } + return true; +} + static int doParseXmlDecl(const ENCODING *(*encodingFinder)(const ENCODING *, const char *, const char *), @@ -1188,6 +1253,15 @@ doParseXmlDecl(const ENCODING *(*encodin *badPtr = val; return 0; } + /* Expat implements XML 1.0 only, so any version outside the "1.0"/"1.x" + family is rejected. Following the Fifth Edition's VersionNum + production (rather than the Fourth Edition's exact "1.0") avoids + rejecting "1.1" now only to have to revert that once Expat tracks + the newer edition. */ + if (! checkXmlDeclVersionNum(enc, val, ptr - enc->minBytesPerChar)) { + *badPtr = val; + return 0; + } if (! parsePseudoAttribute(enc, ptr, end, &name, &nameEnd, &val, &ptr)) { *badPtr = ptr; return 0; @@ -1242,7 +1316,7 @@ doParseXmlDecl(const ENCODING *(*encodin return 1; } -static int FASTCALL +static int checkCharRefNumber(int result) { switch (result >> 8) { case 0xD8: @@ -1266,7 +1340,7 @@ checkCharRefNumber(int result) { return result; } -int FASTCALL +int XmlUtf8Encode(int c, char *buf) { enum { /* minN is minimum legal resulting value for N byte sequence */ @@ -1302,7 +1376,7 @@ XmlUtf8Encode(int c, char *buf) { return 0; /* LCOV_EXCL_LINE: this case too is eliminated before calling */ } -int FASTCALL +int XmlUtf16Encode(int charNum, unsigned short *buf) { if (charNum < 0) return 0; @@ -1334,7 +1408,7 @@ XmlSizeOfUnknownEncoding(void) { return sizeof(struct unknown_encoding); } -static int PTRFASTCALL +static int unknown_isName(const ENCODING *enc, const char *p) { const struct unknown_encoding *uenc = AS_UNKNOWN_ENCODING(enc); int c = uenc->convert(uenc->userData, p); @@ -1343,7 +1417,7 @@ unknown_isName(const ENCODING *enc, cons return UCS2_GET_NAMING(namePages, c >> 8, c & 0xFF); } -static int PTRFASTCALL +static int unknown_isNmstrt(const ENCODING *enc, const char *p) { const struct unknown_encoding *uenc = AS_UNKNOWN_ENCODING(enc); int c = uenc->convert(uenc->userData, p); @@ -1352,14 +1426,14 @@ unknown_isNmstrt(const ENCODING *enc, co return UCS2_GET_NAMING(nmstrtPages, c >> 8, c & 0xFF); } -static int PTRFASTCALL +static int unknown_isInvalid(const ENCODING *enc, const char *p) { const struct unknown_encoding *uenc = AS_UNKNOWN_ENCODING(enc); int c = uenc->convert(uenc->userData, p); return (c & ~0xFFFF) || checkCharRefNumber(c) < 0; } -static enum XML_Convert_Result PTRCALL +static enum XML_Convert_Result unknown_toUtf8(const ENCODING *enc, const char **fromP, const char *fromLim, char **toP, const char *toLim) { const struct unknown_encoding *uenc = AS_UNKNOWN_ENCODING(enc); @@ -1389,7 +1463,7 @@ unknown_toUtf8(const ENCODING *enc, cons } } -static enum XML_Convert_Result PTRCALL +static enum XML_Convert_Result unknown_toUtf16(const ENCODING *enc, const char **fromP, const char *fromLim, unsigned short **toP, const unsigned short *toLim) { const struct unknown_encoding *uenc = AS_UNKNOWN_ENCODING(enc); @@ -1513,7 +1587,7 @@ static const char KW_UTF_16LE[] = {ASCII_U, ASCII_T, ASCII_F, ASCII_MINUS, ASCII_1, ASCII_6, ASCII_L, ASCII_E, '\0'}; -static int FASTCALL +static int getEncodingIndex(const char *name) { static const char *const encodingNames[] = { KW_ISO_8859_1, KW_US_ASCII, KW_UTF_8, KW_UTF_16, KW_UTF_16BE, KW_UTF_16LE, Index: lib/libexpat/lib/xmltok.h =================================================================== RCS file: /cvs/src/lib/libexpat/lib/xmltok.h,v diff -u -p -r1.9.6.2 xmltok.h --- lib/libexpat/lib/xmltok.h 10 Sep 2026 20:46:02 -0000 1.9.6.2 +++ lib/libexpat/lib/xmltok.h 2 Oct 2026 22:01:22 -0000 @@ -163,8 +163,8 @@ typedef struct { struct encoding; typedef struct encoding ENCODING; -typedef int(PTRCALL *SCANNER)(const ENCODING *, const char *, const char *, - const char **); +typedef int (*SCANNER)(const ENCODING *, const char *, const char *, + const char **); enum XML_Convert_Result { XML_CONVERT_COMPLETED = 0, @@ -176,28 +176,27 @@ enum XML_Convert_Result { struct encoding { SCANNER scanners[XML_N_STATES]; SCANNER literalScanners[XML_N_LITERAL_TYPES]; - int(PTRCALL *nameMatchesAscii)(const ENCODING *, const char *, const char *, - const char *); - int(PTRFASTCALL *nameLength)(const ENCODING *, const char *); - const char *(PTRFASTCALL *skipS)(const ENCODING *, const char *); - int(PTRCALL *getAtts)(const ENCODING *enc, const char *ptr, int attsMax, - ATTRIBUTE *atts); - int(PTRFASTCALL *charRefNumber)(const ENCODING *enc, const char *ptr); - int(PTRCALL *predefinedEntityName)(const ENCODING *, const char *, - const char *); - void(PTRCALL *updatePosition)(const ENCODING *, const char *ptr, - const char *end, POSITION *); - int(PTRCALL *isPublicId)(const ENCODING *enc, const char *ptr, - const char *end, const char **badPtr); - enum XML_Convert_Result(PTRCALL *utf8Convert)(const ENCODING *enc, - const char **fromP, - const char *fromLim, char **toP, - const char *toLim); - enum XML_Convert_Result(PTRCALL *utf16Convert)(const ENCODING *enc, - const char **fromP, - const char *fromLim, - unsigned short **toP, - const unsigned short *toLim); + int (*nameMatchesAscii)(const ENCODING *, const char *, const char *, + const char *); + int (*nameLength)(const ENCODING *, const char *); + const char *(*skipS)(const ENCODING *, const char *); + int (*getAtts)(const ENCODING *enc, const char *ptr, int attsMax, + ATTRIBUTE *atts); + int (*charRefNumber)(const ENCODING *enc, const char *ptr); + int (*predefinedEntityName)(const ENCODING *, const char *, const char *); + void (*updatePosition)(const ENCODING *, const char *ptr, const char *end, + POSITION *); + int (*isPublicId)(const ENCODING *enc, const char *ptr, const char *end, + const char **badPtr); + enum XML_Convert_Result (*utf8Convert)(const ENCODING *enc, + const char **fromP, + const char *fromLim, char **toP, + const char *toLim); + enum XML_Convert_Result (*utf16Convert)(const ENCODING *enc, + const char **fromP, + const char *fromLim, + unsigned short **toP, + const unsigned short *toLim); int minBytesPerChar; char isUtf8; char isUtf16; @@ -297,8 +296,8 @@ int XmlInitEncoding(INIT_ENCODING *p, co const char *name); const ENCODING *XmlGetUtf8InternalEncoding(void); const ENCODING *XmlGetUtf16InternalEncoding(void); -int FASTCALL XmlUtf8Encode(int charNumber, char *buf); -int FASTCALL XmlUtf16Encode(int charNumber, unsigned short *buf); +int XmlUtf8Encode(int charNumber, char *buf); +int XmlUtf16Encode(int charNumber, unsigned short *buf); int XmlSizeOfUnknownEncoding(void); typedef int(XMLCALL *CONVERTER)(void *userData, const char *p); Index: lib/libexpat/lib/xmltok_impl.c =================================================================== RCS file: /cvs/src/lib/libexpat/lib/xmltok_impl.c,v diff -u -p -r1.18.12.1 xmltok_impl.c --- lib/libexpat/lib/xmltok_impl.c 20 Aug 2026 07:49:22 -0000 1.18.12.1 +++ lib/libexpat/lib/xmltok_impl.c 2 Oct 2026 22:01:22 -0000 @@ -44,10 +44,6 @@ #ifdef XML_TOK_IMPL_C -# ifndef IS_INVALID_CHAR // i.e. for UTF-16 and XML_MIN_SIZE not defined -# define IS_INVALID_CHAR(enc, ptr, n) (0) -# endif - # define INVALID_LEAD_CASE(n, ptr, nextTokPtr) \ case BT_LEAD##n: \ if (end - ptr < n) \ @@ -144,7 +140,7 @@ /* ptr points to character following "= end) @@ -430,7 +426,7 @@ PREFIX(cdataSectionTok)(const ENCODING * /* ptr points to character following "= end) @@ -922,7 +918,7 @@ PREFIX(contentTok)(const ENCODING *enc, /* ptr points to character following "%" */ -static int PTRCALL +static int PREFIX(scanPercent)(const ENCODING *enc, const char *ptr, const char *end, const char **nextTokPtr) { REQUIRE_CHAR(enc, ptr, end); @@ -952,7 +948,7 @@ PREFIX(scanPercent)(const ENCODING *enc, return XML_TOK_PARTIAL; } -static int PTRCALL +static int PREFIX(scanPoundName)(const ENCODING *enc, const char *ptr, const char *end, const char **nextTokPtr) { REQUIRE_CHAR(enc, ptr, end); @@ -982,7 +978,7 @@ PREFIX(scanPoundName)(const ENCODING *en return -XML_TOK_POUND_NAME; } -static int PTRCALL +static int PREFIX(scanLit)(int open, const ENCODING *enc, const char *ptr, const char *end, const char **nextTokPtr) { while (HAS_CHAR(enc, ptr, end)) { @@ -1016,7 +1012,7 @@ PREFIX(scanLit)(int open, const ENCODING return XML_TOK_PARTIAL; } -static int PTRCALL +static int PREFIX(prologTok)(const ENCODING *enc, const char *ptr, const char *end, const char **nextTokPtr) { int tok; @@ -1260,7 +1256,7 @@ PREFIX(prologTok)(const ENCODING *enc, c return -tok; } -static int PTRCALL +static int PREFIX(attributeValueTok)(const ENCODING *enc, const char *ptr, const char *end, const char **nextTokPtr) { const char *start; @@ -1329,7 +1325,7 @@ PREFIX(attributeValueTok)(const ENCODING return XML_TOK_DATA_CHARS; } -static int PTRCALL +static int PREFIX(entityValueTok)(const ENCODING *enc, const char *ptr, const char *end, const char **nextTokPtr) { const char *start; @@ -1396,7 +1392,7 @@ PREFIX(entityValueTok)(const ENCODING *e # ifdef XML_DTD -static int PTRCALL +static int PREFIX(ignoreSectionTok)(const ENCODING *enc, const char *ptr, const char *end, const char **nextTokPtr) { int level = 0; @@ -1448,7 +1444,7 @@ PREFIX(ignoreSectionTok)(const ENCODING # endif /* XML_DTD */ -static int PTRCALL +static int PREFIX(isPublicId)(const ENCODING *enc, const char *ptr, const char *end, const char **badPtr) { ptr += MINBPC(enc); @@ -1508,7 +1504,7 @@ PREFIX(isPublicId)(const ENCODING *enc, first attsMax attributes are stored in atts. */ -static int PTRCALL +static int PREFIX(getAtts)(const ENCODING *enc, const char *ptr, int attsMax, ATTRIBUTE *atts) { enum { other, inName, inValue } state = inName; @@ -1601,7 +1597,7 @@ PREFIX(getAtts)(const ENCODING *enc, con /* not reached */ } -static int PTRFASTCALL +static int PREFIX(charRefNumber)(const ENCODING *enc, const char *ptr) { int result = 0; /* skip &# */ @@ -1659,7 +1655,7 @@ PREFIX(charRefNumber)(const ENCODING *en return checkCharRefNumber(result); } -static int PTRCALL +static int PREFIX(predefinedEntityName)(const ENCODING *enc, const char *ptr, const char *end) { UNUSED_P(enc); @@ -1713,7 +1709,7 @@ PREFIX(predefinedEntityName)(const ENCOD return 0; } -static int PTRCALL +static int PREFIX(nameMatchesAscii)(const ENCODING *enc, const char *ptr1, const char *end1, const char *ptr2) { UNUSED_P(enc); @@ -1732,7 +1728,7 @@ PREFIX(nameMatchesAscii)(const ENCODING return ptr1 == end1; } -static int PTRFASTCALL +static int PREFIX(nameLength)(const ENCODING *enc, const char *ptr) { const char *start = ptr; for (;;) { @@ -1762,7 +1758,7 @@ PREFIX(nameLength)(const ENCODING *enc, } } -static const char *PTRFASTCALL +static const char * PREFIX(skipS)(const ENCODING *enc, const char *ptr) { for (;;) { switch (BYTE_TYPE(enc, ptr)) { @@ -1777,7 +1773,7 @@ PREFIX(skipS)(const ENCODING *enc, const } } -static void PTRCALL +static void PREFIX(updatePosition)(const ENCODING *enc, const char *ptr, const char *end, POSITION *pos) { while (HAS_CHAR(enc, ptr, end)) { Index: lib/libexpat/lib/xmltok_ns.c =================================================================== RCS file: /cvs/src/lib/libexpat/lib/xmltok_ns.c,v diff -u -p -r1.9.4.1 xmltok_ns.c --- lib/libexpat/lib/xmltok_ns.c 20 Aug 2026 07:49:22 -0000 1.9.4.1 +++ lib/libexpat/lib/xmltok_ns.c 2 Oct 2026 22:01:22 -0000 @@ -64,14 +64,14 @@ static const ENCODING *const NS(encoding &ns(utf8_encoding).enc /* NO_ENC */ }; -static int PTRCALL +static int NS(initScanProlog)(const ENCODING *enc, const char *ptr, const char *end, const char **nextTokPtr) { return initScan(NS(encodings), (const INIT_ENCODING *)enc, XML_PROLOG_STATE, ptr, end, nextTokPtr); } -static int PTRCALL +static int NS(initScanContent)(const ENCODING *enc, const char *ptr, const char *end, const char **nextTokPtr) { return initScan(NS(encodings), (const INIT_ENCODING *)enc, XML_CONTENT_STATE, Index: lib/libexpat/tests/basic_tests.c =================================================================== RCS file: /cvs/src/lib/libexpat/tests/basic_tests.c,v diff -u -p -r1.9.4.2 basic_tests.c --- lib/libexpat/tests/basic_tests.c 10 Sep 2026 20:46:02 -0000 1.9.4.2 +++ lib/libexpat/tests/basic_tests.c 2 Oct 2026 22:01:22 -0000 @@ -974,6 +974,50 @@ START_TEST(test_xmldecl_empty_version) { } END_TEST +/* Regression test for GH #967: Expat only implements XML 1.0 Fourth + Edition, so a declared version outside the "1.x" family must be + rejected rather than silently accepted. A version matching the Fifth + Edition's VersionNum production ("1." followed by one or more digits) + is accepted even though Expat itself only implements 1.0 Fourth + Edition, per GH #967's review thread: rejecting "1.1" now would just + have to be reverted once Expat tracks the Fifth Edition, so it's let + through rather than blocked twice. */ +START_TEST(test_xmldecl_wrong_version_number) { + const char *const badVersions[] = {"2.3", "0.9", "10", "1.", "1", " 1.0 "}; + + for (size_t i = 0; i < sizeof(badVersions) / sizeof(badVersions[0]); i++) { + char doc[64]; + snprintf(doc, sizeof(doc), "\n", badVersions[i]); + set_subtest("version='%s'", badVersions[i]); + + XML_Parser parser = XML_ParserCreate(NULL); + assert_true(_XML_Parse_SINGLE_BYTES(parser, doc, (int)strlen(doc), XML_TRUE) + == XML_STATUS_ERROR); + assert_true(XML_GetErrorCode(parser) == XML_ERROR_XML_DECL); + XML_ParserFree(parser); + } +} +END_TEST + +/* GH #967's review pointed out that XML 1.0 Fifth Edition relaxed + VersionNum to "1." followed by one or more digits, so versions like + "1.1" and "1.123" should parse rather than being rejected. */ +START_TEST(test_xmldecl_accepts_1_x_version) { + const char *const goodVersions[] = {"1.1", "1.123"}; + + for (size_t i = 0; i < sizeof(goodVersions) / sizeof(goodVersions[0]); i++) { + char doc[64]; + snprintf(doc, sizeof(doc), "\n", goodVersions[i]); + set_subtest("version='%s'", goodVersions[i]); + + XML_Parser parser = XML_ParserCreate(NULL); + assert_true(_XML_Parse_SINGLE_BYTES(parser, doc, (int)strlen(doc), XML_TRUE) + == XML_STATUS_OK); + XML_ParserFree(parser); + } +} +END_TEST + /* Regression test for SF bug #584832. */ START_TEST(test_unknown_encoding_internal_entity) { const char *text = "\n" @@ -1822,6 +1866,301 @@ START_TEST(test_utf16_bad_surrogate_pair } END_TEST +// Helper that creates a UTF-16LE copy of UTF-16BE literal input and vice versa +static char * +utf16_dup_flipped(const char *text, size_t lenBytes) { + assert_true(lenBytes < SIZE_MAX); + assert_true(lenBytes % 2 == 0); + char *const buffer = malloc(lenBytes + 1); + assert_true(buffer != NULL); + + for (size_t i = 0; i < lenBytes; i++) { + // This maps 0 -> 1, 1 -> 0, 2 -> 3, 3 -> 2, 4 -> 5, .. + size_t j = i + ((i % 2 == 0) ? +1 : -1); + assert_true(j < lenBytes); + buffer[j] = text[i]; + } + + buffer[lenBytes] = '\0'; + + return buffer; +} + +/* Tests that invalid combinations of surrogates are detected when decoding + UTF-16, both little-endian and big-endian. + Previously, a high surrogate not followed by a low surrogate slipped + through. Without validation the high would consume the next + code unit as a fake low, hiding e.g. a following '<' from the + tokenizer. */ +START_TEST(test_utf16_surrogate_pairs) { + struct TestCase { + const char *idea; + const char *content; + bool expectedSuccess; + }; + + struct TestCase testCases[] = { + // Group {smallest high - 1}{*} + {"{smallest high - 1}{smallest high - 1}", + "\0<\0a\0>" + "\xD7\xFF" + "\xD7\xFF" + "\0<\0/\0a\0>", + true}, + {"{smallest high - 1}{smallest high}", + "\0<\0a\0>" + "\xD7\xFF" + "\xD8\x00" + "\0<\0/\0a\0>", + false}, + {"{smallest high - 1}{largest high}", + "\0<\0a\0>" + "\xD7\xFF" + "\xDB\xFF" + "\0<\0/\0a\0>", + false}, + {"{smallest high - 1}{smallest low}", + "\0<\0a\0>" + "\xD7\xFF" + "\xDC\x00" + "\0<\0/\0a\0>", + false}, + {"{smallest high - 1}{largest low}", + "\0<\0a\0>" + "\xD7\xFF" + "\xDF\xFF" + "\0<\0/\0a\0>", + false}, + {"{smallest high - 1}{largest low + 1}", + "\0<\0a\0>" + "\xD7\xFF" + "\xE0\x00" + "\0<\0/\0a\0>", + true}, + // Group {smallest high}{*} + {"{smallest high}{smallest high - 1}", + "\0<\0a\0>" + "\xD8\x00" + "\xD7\xFF" + "\0<\0/\0a\0>", + false}, + {"{smallest high}{smallest high}", + "\0<\0a\0>" + "\xD8\x00" + "\xD8\x00" + "\0<\0/\0a\0>", + false}, + {"{smallest high}{largest high}", + "\0<\0a\0>" + "\xD8\x00" + "\xDB\xFF" + "\0<\0/\0a\0>", + false}, + {"{smallest high}{smallest low}", + "\0<\0a\0>" + "\xD8\x00" + "\xDC\x00" + "\0<\0/\0a\0>", + true}, + {"{smallest high}{largest low}", + "\0<\0a\0>" + "\xD8\x00" + "\xDF\xFF" + "\0<\0/\0a\0>", + true}, + {"{smallest high}{largest low + 1}", + "\0<\0a\0>" + "\xD8\x00" + "\xE0\x00" + "\0<\0/\0a\0>", + false}, + // Group {largest high}{*} + {"{largest high}{smallest high - 1}", + "\0<\0a\0>" + "\xDB\xFF" + "\xD7\xFF" + "\0<\0/\0a\0>", + false}, + {"{largest high}{smallest high}", + "\0<\0a\0>" + "\xDB\xFF" + "\xD8\x00" + "\0<\0/\0a\0>", + false}, + {"{largest high}{largest high}", + "\0<\0a\0>" + "\xDB\xFF" + "\xDB\xFF" + "\0<\0/\0a\0>", + false}, + {"{largest high}{smallest low}", + "\0<\0a\0>" + "\xDB\xFF" + "\xDC\x00" + "\0<\0/\0a\0>", + true}, + {"{largest high}{largest low}", + "\0<\0a\0>" + "\xDB\xFF" + "\xDF\xFF" + "\0<\0/\0a\0>", + true}, + {"{largest high}{largest low + 1}", + "\0<\0a\0>" + "\xDB\xFF" + "\xE0\x00" + "\0<\0/\0a\0>", + false}, + // Group {smallest low}{*} + {"{smallest low}{smallest high - 1}", + "\0<\0a\0>" + "\xDC\x00" + "\xD7\xFF" + "\0<\0/\0a\0>", + false}, + {"{smallest low}{smallest high}", + "\0<\0a\0>" + "\xDC\x00" + "\xD8\x00" + "\0<\0/\0a\0>", + false}, + {"{smallest low}{largest high}", + "\0<\0a\0>" + "\xDC\x00" + "\xDB\xFF" + "\0<\0/\0a\0>", + false}, + {"{smallest low}{smallest low}", + "\0<\0a\0>" + "\xDC\x00" + "\xDC\x00" + "\0<\0/\0a\0>", + false}, + {"{smallest low}{largest low}", + "\0<\0a\0>" + "\xDC\x00" + "\xDF\xFF" + "\0<\0/\0a\0>", + false}, + {"{smallest low}{largest low + 1}", + "\0<\0a\0>" + "\xDC\x00" + "\xE0\x00" + "\0<\0/\0a\0>", + false}, + // Group {largest low}{*} + {"{largest low}{smallest high - 1}", + "\0<\0a\0>" + "\xDF\xFF" + "\xD7\xFF" + "\0<\0/\0a\0>", + false}, + {"{largest low}{smallest high}", + "\0<\0a\0>" + "\xDF\xFF" + "\xD8\x00" + "\0<\0/\0a\0>", + false}, + {"{largest low}{largest high}", + "\0<\0a\0>" + "\xDF\xFF" + "\xDB\xFF" + "\0<\0/\0a\0>", + false}, + {"{largest low}{smallest low}", + "\0<\0a\0>" + "\xDF\xFF" + "\xDC\x00" + "\0<\0/\0a\0>", + false}, + {"{largest low}{largest low}", + "\0<\0a\0>" + "\xDF\xFF" + "\xDF\xFF" + "\0<\0/\0a\0>", + false}, + {"{largest low}{largest low + 1}", + "\0<\0a\0>" + "\xDF\xFF" + "\xE0\x00" + "\0<\0/\0a\0>", + false}, + // Group {largest low + 1}{*} + {"{largest low + 1}{smallest high - 1}", + "\0<\0a\0>" + "\xE0\x00" + "\xD7\xFF" + "\0<\0/\0a\0>", + true}, + {"{largest low + 1}{smallest high}", + "\0<\0a\0>" + "\xE0\x00" + "\xD8\x00" + "\0<\0/\0a\0>", + false}, + {"{largest low + 1}{largest high}", + "\0<\0a\0>" + "\xE0\x00" + "\xDB\xFF" + "\0<\0/\0a\0>", + false}, + {"{largest low + 1}{smallest low}", + "\0<\0a\0>" + "\xE0\x00" + "\xDC\x00" + "\0<\0/\0a\0>", + false}, + {"{largest low + 1}{largest low}", + "\0<\0a\0>" + "\xE0\x00" + "\xDF\xFF" + "\0<\0/\0a\0>", + false}, + {"{largest low + 1}{largest low + 1}", + "\0<\0a\0>" + "\xE0\x00" + "\xE0\x00" + "\0<\0/\0a\0>", + true}, + }; + + for (size_t i = 0; i < sizeof(testCases) / sizeof(testCases[0]); i++) { + set_subtest("%s", testCases[i].idea); + + const int lenBytes = /**/ 6 + /*first*/ 2 + /*second*/ 2 + /**/ 8; + const bool expectedSuccess = testCases[i].expectedSuccess; + const enum XML_Status expectedStatus + = (expectedSuccess ? XML_STATUS_OK : XML_STATUS_ERROR); + + const char *const bigEndian = testCases[i].content; + char *const littleEndian = utf16_dup_flipped(bigEndian, lenBytes); + assert_true(littleEndian != NULL); + const char *endianCases[] = {bigEndian, littleEndian}; + + for (size_t j = 0; j < sizeof(endianCases) / sizeof(endianCases[0]); j++) { + const char *text = endianCases[j]; + + assert_true(text[lenBytes] == '\0'); // self-test + assert_true((text[0] == '\0') + != (text[lenBytes - 1] == '\0')); // self-test + + XML_Parser parser = XML_ParserCreate(NULL); + assert_true(parser != NULL); + + assert_true(_XML_Parse_SINGLE_BYTES(parser, text, lenBytes, XML_TRUE) + == expectedStatus); + if (! expectedSuccess) { + assert_true(XML_GetErrorCode(parser) == XML_ERROR_INVALID_TOKEN); + } + + XML_ParserFree(parser); + } + + free(littleEndian); + } +} +END_TEST + START_TEST(test_bad_cdata) { struct CaseData { const char *text; @@ -6735,6 +7074,8 @@ make_basic_test_case(Suite *s) { tcase_add_test(tc_basic, test_xmldecl_missing_attr); tcase_add_test(tc_basic, test_xmldecl_missing_value); tcase_add_test(tc_basic, test_xmldecl_empty_version); + tcase_add_test(tc_basic, test_xmldecl_wrong_version_number); + tcase_add_test(tc_basic, test_xmldecl_accepts_1_x_version); tcase_add_test__if_xml_ge(tc_basic, test_unknown_encoding_internal_entity); tcase_add_test(tc_basic, test_unrecognised_encoding_internal_entity); tcase_add_test__ifdef_xml_dtd(tc_basic, test_ext_entity_set_encoding); @@ -6768,6 +7109,7 @@ make_basic_test_case(Suite *s) { tcase_add_test(tc_basic, test_long_cdata_utf16); tcase_add_test(tc_basic, test_multichar_cdata_utf16); tcase_add_test(tc_basic, test_utf16_bad_surrogate_pair); + tcase_add_test(tc_basic, test_utf16_surrogate_pairs); 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); Index: lib/libexpat/tests/memcheck.c =================================================================== RCS file: /cvs/src/lib/libexpat/tests/memcheck.c,v diff -u -p -r1.6.12.1 memcheck.c --- lib/libexpat/tests/memcheck.c 20 Aug 2026 07:49:22 -0000 1.6.12.1 +++ lib/libexpat/tests/memcheck.c 2 Oct 2026 22:01:22 -0000 @@ -117,7 +117,7 @@ tracking_free(void *ptr) { if (entry->next != NULL) entry->next->prev = entry->prev; else - alloc_tail = entry->next; + alloc_tail = entry->prev; free(entry); } else { printf("Attempting to free unallocated memory at %p\n", ptr); Index: lib/libexpat/tests/nsalloc_tests.c =================================================================== RCS file: /cvs/src/lib/libexpat/tests/nsalloc_tests.c,v diff -u -p -r1.3.4.1 nsalloc_tests.c --- lib/libexpat/tests/nsalloc_tests.c 20 Aug 2026 07:49:22 -0000 1.3.4.1 +++ lib/libexpat/tests/nsalloc_tests.c 2 Oct 2026 22:01:22 -0000 @@ -43,6 +43,8 @@ SPDX-License-Identifier: MIT */ +#include "expat_config.h" + #if defined(NDEBUG) # undef NDEBUG /* because test suite relies on assert(...) at the moment */ #endif