Merge pull request #777 from libexpat/xml-dtd-undefined

Fix issues for compilation with XML_DTD undefined
This commit is contained in:
Sebastian Pipping 2023-11-08 14:05:03 +01:00 committed by GitHub
commit 3a0c5d6ae5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 387 additions and 114 deletions

View file

@ -34,4 +34,5 @@ XML_ATTR_INFO
XML_CONTEXT_BYTES
XML_DEV_URANDOM
XML_DTD
XML_GE
XML_NS

View file

@ -39,4 +39,5 @@ XML_ATTR_INFO
XML_CONTEXT_BYTES
XML_DEV_URANDOM
XML_DTD
XML_GE
XML_NS

View file

@ -58,7 +58,9 @@ jobs:
- MODE: qa-sh
FLAT_ENV: CC=clang CXX=clang++ LD=clang++ QA_SANITIZER=address CMAKE_ARGS=-DEXPAT_CONTEXT_BYTES=0
- MODE: qa-sh
FLAT_ENV: CC=clang CXX=clang++ LD=clang++ QA_SANITIZER=address CMAKE_ARGS=-DEXPAT_DTD=OFF
FLAT_ENV: CC=clang CXX=clang++ LD=clang++ QA_SANITIZER=address CMAKE_ARGS="-DEXPAT_DTD=OFF -DEXPAT_GE=ON"
- MODE: qa-sh
FLAT_ENV: CC=clang CXX=clang++ LD=clang++ QA_SANITIZER=address CMAKE_ARGS="-DEXPAT_DTD=OFF -DEXPAT_GE=OFF"
- MODE: qa-sh
FLAT_ENV: CC=clang CXX=clang++ LD=clang++ QA_SANITIZER=address CMAKE_ARGS=-DEXPAT_LARGE_SIZE=ON
- MODE: qa-sh

View file

@ -143,6 +143,8 @@ expat_shy_set(EXPAT_CONTEXT_BYTES 1024 CACHE STRING "Define to specify how much
mark_as_advanced(EXPAT_CONTEXT_BYTES)
expat_shy_set(EXPAT_DTD ON CACHE BOOL "Define to make parameter entity parsing functionality available")
mark_as_advanced(EXPAT_DTD)
expat_shy_set(EXPAT_GE ON CACHE BOOL "Define to make general entity parsing functionality available")
mark_as_advanced(EXPAT_GE)
expat_shy_set(EXPAT_NS ON CACHE BOOL "Define to make XML Namespaces functionality available")
mark_as_advanced(EXPAT_NS)
expat_shy_set(EXPAT_WARNINGS_AS_ERRORS OFF CACHE BOOL "Treat all compiler warnings as errors")
@ -179,6 +181,11 @@ endif()
#
# Environment checks
#
if(EXPAT_DTD AND NOT EXPAT_GE)
message(SEND_ERROR "Option EXPAT_DTD requires that EXPAT_GE is also enabled.")
message(SEND_ERROR "Please either enable option EXPAT_GE (recommended) or disable EXPAT_DTD also.")
endif()
if(EXPAT_WITH_LIBBSD)
find_library(LIB_BSD NAMES bsd)
if(NOT LIB_BSD)
@ -281,6 +288,7 @@ endif()
_expat_copy_bool_int(EXPAT_ATTR_INFO XML_ATTR_INFO)
_expat_copy_bool_int(EXPAT_DTD XML_DTD)
_expat_copy_bool_int(EXPAT_GE XML_GE)
_expat_copy_bool_int(EXPAT_LARGE_SIZE XML_LARGE_SIZE)
_expat_copy_bool_int(EXPAT_MIN_SIZE XML_MIN_SIZE)
_expat_copy_bool_int(EXPAT_NS XML_NS)
@ -395,7 +403,13 @@ if(EXPAT_SHARED_LIBS)
endif()
endmacro()
_expat_def_file_toggle(EXPAT_DTD _EXPAT_COMMENT_DTD)
if(EXPAT_DTD OR EXPAT_GE)
set(_EXPAT_DTD_OR_GE TRUE)
else()
set(_EXPAT_DTD_OR_GE FALSE)
endif()
_expat_def_file_toggle(_EXPAT_DTD_OR_GE _EXPAT_COMMENT_DTD_OR_GE)
_expat_def_file_toggle(EXPAT_ATTR_INFO _EXPAT_COMMENT_ATTR_INFO)
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/lib/libexpat.def.cmake" "${CMAKE_CURRENT_BINARY_DIR}/lib/libexpat.def")
@ -932,6 +946,7 @@ message(STATUS " // Advanced options, changes not advised")
message(STATUS " Attributes info .......... ${EXPAT_ATTR_INFO}")
message(STATUS " Context bytes ............ ${EXPAT_CONTEXT_BYTES}")
message(STATUS " DTD support .............. ${EXPAT_DTD}")
message(STATUS " General entities ......... ${EXPAT_GE}")
message(STATUS " Large size ............... ${EXPAT_LARGE_SIZE}")
message(STATUS " Minimum size ............. ${EXPAT_MIN_SIZE}")
message(STATUS " Namespace support ........ ${EXPAT_NS}")

View file

@ -303,6 +303,8 @@ AC_SUBST(FILEMAP)
dnl Some basic configuration:
AC_DEFINE([XML_NS], 1,
[Define to make XML Namespaces functionality available.])
AC_DEFINE([XML_GE], 1,
[Define as 1/0 to enable/disable support for general entities.])
AC_DEFINE([XML_DTD], 1,
[Define to make parameter entity parsing functionality available.])
AC_DEFINE([XML_DEV_URANDOM], 1,

View file

@ -68,7 +68,17 @@ _get_build_dir() {
m32_part=__m32
fi
echo "build__${version}__xml_context_${xml_context}${libbsd_part}${mingw_part}${char_part}${xml_attr_part}${m32_part}"
local ge_part=
if ${with_ge}; then
ge_part=__ge
fi
local dtd_part=
if ${with_dtd}; then
dtd_part=__dtd
fi
echo "build__${version}__xml_context_${xml_context}${libbsd_part}${mingw_part}${char_part}${ge_part}${dtd_part}${xml_attr_part}${m32_part}"
}
@ -95,6 +105,8 @@ _call_cmake() {
${with_libbsd} && cmake_args+=( -DEXPAT_WITH_LIBBSD=ON )
${with_mingw} && cmake_args+=( -DCMAKE_TOOLCHAIN_FILE="${abs_source_dir}"/cmake/mingw-toolchain.cmake )
${with_m32} && cmake_args+=( -D_EXPAT_M32=ON )
${with_ge} || cmake_args+=( -DEXPAT_GE=OFF )
${with_dtd} || cmake_args+=( -DEXPAT_DTD=OFF )
(
set -x
@ -184,7 +196,10 @@ _run() {
fi
set -x
make CTEST_OUTPUT_ON_FAILURE=1 test run-xmltest
make CTEST_OUTPUT_ON_FAILURE=1 test
if ${with_dtd}; then
make run-xmltest
fi
lcov -c -d "${capture_dir}" -o "${coverage_info}-test" &>> run.log
lcov \
@ -291,6 +306,8 @@ _main() {
with_unsigned_char=false
with_libbsd=false
with_m32=false
with_dtd=true
with_ge=true
for with_mingw in true false ; do
for unicode_enabled in true false ; do
if ${unicode_enabled} && ! ${with_mingw} ; then
@ -309,6 +326,8 @@ _main() {
with_libbsd=true _build_case
with_unsigned_char=true _build_case
with_m32=true _build_case
with_dtd=false with_ge=true _build_case
with_dtd=false with_ge=false _build_case
echo
echo 'Merging coverage files...'

View file

@ -360,13 +360,40 @@ and the definition of character types in the case of
<code>XML_UNICODE_WCHAR_T</code>. The symbols are:</p>
<dl class="cpp-symbols">
<dt><a name="XML_GE">XML_GE</a></dt>
<dd>
Added in Expat 2.6.0.
Include support for
<a href="https://www.w3.org/TR/2006/REC-xml-20060816/#sec-physical-struct">general entities</a>
(syntax <code>&amp;e1;</code> to reference and
syntax <code>&lt;!ENTITY e1 'value1'&gt;</code> (an internal general entity) or
<code>&lt;!ENTITY e2 SYSTEM 'file2'&gt;</code> (an external general entity) to declare).
With <code>XML_GE</code> enabled, general entities will be replaced by their declared replacement text;
for this to work for <em>external</em> general entities, in addition an
<code><a href="#XML_SetExternalEntityRefHandler">XML_ExternalEntityRefHandler</a></code> must be set using
<code><a href="#XML_SetExternalEntityRefHandler">XML_SetExternalEntityRefHandler</a></code>.
Also, enabling <code>XML_GE</code> makes
the functions <code><a href="#XML_SetBillionLaughsAttackProtectionMaximumAmplification">
XML_SetBillionLaughsAttackProtectionMaximumAmplification</a></code> and <code>
<a href="#XML_SetBillionLaughsAttackProtectionActivationThreshold">
XML_SetBillionLaughsAttackProtectionActivationThreshold</a></code> available.
<br/>
With <code>XML_GE</code> disabled, Expat has a smaller memory footprint and can be faster, but will
not load external general entities and will replace all general entities
(except the <a href="https://www.w3.org/TR/2006/REC-xml-20060816/#sec-predefined-ent">predefined five</a>:
<code>amp</code>, <code>apos</code>, <code>gt</code>, <code>lt</code>, <code>quot</code>)
with a self-reference:
for example, referencing an entity <code>e1</code> via <code>&amp;e1;</code> will be replaced
by text <code>&amp;e1;</code>.
</dd>
<dt><a name="XML_DTD">XML_DTD</a></dt>
<dd>Include support for using and reporting DTD-based content. If
this is defined, default attribute values from an external DTD subset
are reported and attribute value normalization occurs based on the
type of attributes defined in the external subset. Without
this, Expat has a smaller memory footprint and can be faster, but will
not load external entities or process conditional sections. If defined, makes
not load external parameter entities or process conditional sections. If defined, makes
the functions <code><a
href="#XML_SetBillionLaughsAttackProtectionMaximumAmplification">
XML_SetBillionLaughsAttackProtectionMaximumAmplification</a></code> and <code>

View file

@ -105,6 +105,9 @@
/* Define to make parameter entity parsing functionality available. */
#cmakedefine XML_DTD
/* Define as 1/0 to enable/disable support for general entities. */
#define XML_GE @XML_GE@
/* Define to make XML Namespaces functionality available. */
#cmakedefine XML_NS

View file

@ -1025,7 +1025,9 @@ enum XML_FeatureEnum {
XML_FEATURE_ATTR_INFO,
/* Added in Expat 2.4.0. */
XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAULT,
XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT
XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT,
/* Added in Expat 2.6.0. */
XML_FEATURE_GE
/* Additional features must be added to the end of this enum. */
};
@ -1038,13 +1040,15 @@ typedef struct {
XMLPARSEAPI(const XML_Feature *)
XML_GetFeatureList(void);
#ifdef XML_DTD
/* Added in Expat 2.4.0. */
#if XML_GE == 1
/* Added in Expat 2.4.0 for XML_DTD defined and
* added in Expat 2.6.0 for XML_GE == 1. */
XMLPARSEAPI(XML_Bool)
XML_SetBillionLaughsAttackProtectionMaximumAmplification(
XML_Parser parser, float maximumAmplificationFactor);
/* Added in Expat 2.4.0. */
/* Added in Expat 2.4.0 for XML_DTD defined and
* added in Expat 2.6.0 for XML_GE == 1. */
XMLPARSEAPI(XML_Bool)
XML_SetBillionLaughsAttackProtectionActivationThreshold(
XML_Parser parser, unsigned long long activationThresholdBytes);

View file

@ -154,7 +154,7 @@ extern "C" {
void _INTERNAL_trim_to_complete_utf8_characters(const char *from,
const char **fromLimRef);
#if defined(XML_DTD)
#if XML_GE == 1
unsigned long long testingAccountingGetCountBytesDirect(XML_Parser parser);
unsigned long long testingAccountingGetCountBytesIndirect(XML_Parser parser);
const char *unsignedCharToPrintable(unsigned char c);

View file

@ -75,5 +75,5 @@ EXPORTS
XML_SetHashSalt @67
; internal @68 removed with version 2.3.1
; added with version 2.4.0
@_EXPAT_COMMENT_DTD@ XML_SetBillionLaughsAttackProtectionActivationThreshold @69
@_EXPAT_COMMENT_DTD@ XML_SetBillionLaughsAttackProtectionMaximumAmplification @70
@_EXPAT_COMMENT_DTD_OR_GE@ XML_SetBillionLaughsAttackProtectionActivationThreshold @69
@_EXPAT_COMMENT_DTD_OR_GE@ XML_SetBillionLaughsAttackProtectionMaximumAmplification @70

View file

@ -63,6 +63,14 @@
#include "expat_config.h"
#if ! defined(XML_GE) || (1 - XML_GE - 1 == 2) || (XML_GE < 0) || (XML_GE > 1)
# error XML_GE (for general entities) must be defined, non-empty, either 1 or 0 (0 to disable, 1 to enable; 1 is a common default)
#endif
#if defined(XML_DTD) && XML_GE == 0
# error Either undefine XML_DTD or define XML_GE to 1.
#endif
#if ! defined(XML_CONTEXT_BYTES) || (1 - XML_CONTEXT_BYTES - 1 == 2) \
|| (XML_CONTEXT_BYTES + 0 < 0)
# error XML_CONTEXT_BYTES must be defined, non-empty and >=0 (0 to disable, >=1 to enable; 1024 is a common default)
@ -416,7 +424,7 @@ enum XML_Account {
XML_ACCOUNT_NONE /* i.e. do not account, was accounted already */
};
#ifdef XML_DTD
#if XML_GE == 1
typedef unsigned long long XmlBigCount;
typedef struct accounting {
XmlBigCount countBytesDirect;
@ -432,7 +440,7 @@ typedef struct entity_stats {
unsigned int maximumDepthSeen;
unsigned long debugLevel;
} ENTITY_STATS;
#endif /* XML_DTD */
#endif /* XML_GE == 1 */
typedef enum XML_Error PTRCALL Processor(XML_Parser parser, const char *start,
const char *end, const char **endPtr);
@ -504,9 +512,13 @@ static enum XML_Error appendAttributeValue(XML_Parser parser, const ENCODING *,
static ATTRIBUTE_ID *getAttributeId(XML_Parser parser, const ENCODING *enc,
const char *start, const char *end);
static int setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *);
#if XML_GE == 1
static enum XML_Error storeEntityValue(XML_Parser parser, const ENCODING *enc,
const char *start, const char *end,
enum XML_Account account);
#else
static enum XML_Error storeSelfEntityValue(XML_Parser parser, ENTITY *entity);
#endif
static int reportProcessingInstruction(XML_Parser parser, const ENCODING *enc,
const char *start, const char *end);
static int reportComment(XML_Parser parser, const ENCODING *enc,
@ -570,7 +582,7 @@ static XML_Parser parserCreate(const XML_Char *encodingName,
static void parserInit(XML_Parser parser, const XML_Char *encodingName);
#ifdef XML_DTD
#if XML_GE == 1
static float accountingGetCurrentAmplification(XML_Parser rootParser);
static void accountingReportStats(XML_Parser originParser, const char *epilog);
static void accountingOnAbort(XML_Parser originParser);
@ -593,7 +605,7 @@ static void entityTrackingOnClose(XML_Parser parser, ENTITY *entity,
static XML_Parser getRootParserOf(XML_Parser parser,
unsigned int *outLevelDiff);
#endif /* XML_DTD */
#endif /* XML_GE == 1 */
static unsigned long getDebugLevel(const char *variableName,
unsigned long defaultDebugLevel);
@ -718,7 +730,7 @@ struct XML_ParserStruct {
enum XML_ParamEntityParsing m_paramEntityParsing;
#endif
unsigned long m_hash_secret_salt;
#ifdef XML_DTD
#if XML_GE == 1
ACCOUNTING m_accounting;
ENTITY_STATS m_entity_stats;
#endif
@ -1178,7 +1190,7 @@ parserInit(XML_Parser parser, const XML_Char *encodingName) {
#endif
parser->m_hash_secret_salt = 0;
#ifdef XML_DTD
#if XML_GE == 1
memset(&parser->m_accounting, 0, sizeof(ACCOUNTING));
parser->m_accounting.debugLevel = getDebugLevel("EXPAT_ACCOUNTING_DEBUG", 0u);
parser->m_accounting.maximumAmplificationFactor
@ -2534,8 +2546,9 @@ XML_GetFeatureList(void) {
#ifdef XML_ATTR_INFO
{XML_FEATURE_ATTR_INFO, XML_L("XML_ATTR_INFO"), 0},
#endif
#ifdef XML_DTD
/* Added in Expat 2.4.0. */
#if XML_GE == 1
/* Added in Expat 2.4.0 for XML_DTD defined and
* added in Expat 2.6.0 for XML_GE == 1. */
{XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAULT,
XML_L("XML_BLAP_MAX_AMP"),
(long int)
@ -2543,6 +2556,8 @@ XML_GetFeatureList(void) {
{XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT,
XML_L("XML_BLAP_ACT_THRES"),
EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT},
/* Added in Expat 2.6.0. */
{XML_FEATURE_GE, XML_L("XML_GE"), 0},
#endif
{XML_FEATURE_END, NULL, 0}
};
@ -2550,7 +2565,7 @@ XML_GetFeatureList(void) {
return features;
}
#ifdef XML_DTD
#if XML_GE == 1
XML_Bool XMLCALL
XML_SetBillionLaughsAttackProtectionMaximumAmplification(
XML_Parser parser, float maximumAmplificationFactor) {
@ -2572,7 +2587,7 @@ XML_SetBillionLaughsAttackProtectionActivationThreshold(
parser->m_accounting.activationThresholdBytes = activationThresholdBytes;
return XML_TRUE;
}
#endif /* XML_DTD */
#endif /* XML_GE == 1 */
/* Initially tag->rawName always points into the parse buffer;
for those TAG instances opened while the current parse buffer was
@ -2658,13 +2673,13 @@ externalEntityInitProcessor2(XML_Parser parser, const char *start,
int tok = XmlContentTok(parser->m_encoding, start, end, &next);
switch (tok) {
case XML_TOK_BOM:
#ifdef XML_DTD
#if XML_GE == 1
if (! accountingDiffTolerated(parser, tok, start, next, __LINE__,
XML_ACCOUNT_DIRECT)) {
accountingOnAbort(parser);
return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
}
#endif /* XML_DTD */
#endif /* XML_GE == 1 */
/* If we are at the end of the buffer, this would cause the next stage,
i.e. externalEntityInitProcessor3, to pass control directly to
@ -2778,7 +2793,7 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
for (;;) {
const char *next = s; /* XmlContentTok doesn't always set the last arg */
int tok = XmlContentTok(enc, s, end, &next);
#ifdef XML_DTD
#if XML_GE == 1
const char *accountAfter
= ((tok == XML_TOK_TRAILING_RSQB) || (tok == XML_TOK_TRAILING_CR))
? (haveMore ? s /* i.e. 0 bytes */ : end)
@ -2844,14 +2859,14 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
XML_Char ch = (XML_Char)XmlPredefinedEntityName(
enc, s + enc->minBytesPerChar, next - enc->minBytesPerChar);
if (ch) {
#ifdef XML_DTD
#if XML_GE == 1
/* NOTE: We are replacing 4-6 characters original input for 1 character
* so there is no amplification and hence recording without
* protection. */
accountingDiffTolerated(parser, tok, (char *)&ch,
((char *)&ch) + sizeof(XML_Char), __LINE__,
XML_ACCOUNT_ENTITY_EXPANSION);
#endif /* XML_DTD */
#endif /* XML_GE == 1 */
if (parser->m_characterDataHandler)
parser->m_characterDataHandler(parser->m_handlerArg, &ch, 1);
else if (parser->m_defaultHandler)
@ -4053,7 +4068,7 @@ doCdataSection(XML_Parser parser, const ENCODING *enc, const char **startPtr,
for (;;) {
const char *next = s; /* in case of XML_TOK_NONE or XML_TOK_PARTIAL */
int tok = XmlCdataSectionTok(enc, s, end, &next);
#ifdef XML_DTD
#if XML_GE == 1
if (! accountingDiffTolerated(parser, tok, s, next, __LINE__, account)) {
accountingOnAbort(parser);
return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
@ -4205,7 +4220,7 @@ doIgnoreSection(XML_Parser parser, const ENCODING *enc, const char **startPtr,
*eventPP = s;
*startPtr = NULL;
tok = XmlIgnoreSectionTok(enc, s, end, &next);
# ifdef XML_DTD
# if XML_GE == 1
if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
XML_ACCOUNT_DIRECT)) {
accountingOnAbort(parser);
@ -4297,7 +4312,7 @@ processXmlDecl(XML_Parser parser, int isGeneralTextEntity, const char *s,
const XML_Char *storedversion = NULL;
int standalone = -1;
#ifdef XML_DTD
#if XML_GE == 1
if (! accountingDiffTolerated(parser, XML_TOK_XML_DECL, s, next, __LINE__,
XML_ACCOUNT_DIRECT)) {
accountingOnAbort(parser);
@ -4504,7 +4519,7 @@ entityValueInitProcessor(XML_Parser parser, const char *s, const char *end,
is not valid to have multiple BOMs.
*/
else if (tok == XML_TOK_BOM) {
# ifdef XML_DTD
# if XML_GE == 1
if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
XML_ACCOUNT_DIRECT)) {
accountingOnAbort(parser);
@ -4720,11 +4735,13 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
}
}
role = XmlTokenRole(&parser->m_prologState, tok, s, next, enc);
#ifdef XML_DTD
#if XML_GE == 1
switch (role) {
case XML_ROLE_INSTANCE_START: // bytes accounted in contentProcessor
case XML_ROLE_XML_DECL: // bytes accounted in processXmlDecl
case XML_ROLE_TEXT_DECL: // bytes accounted in processXmlDecl
# ifdef XML_DTD
case XML_ROLE_TEXT_DECL: // bytes accounted in processXmlDecl
# endif
break;
default:
if (! accountingDiffTolerated(parser, tok, s, next, __LINE__, account)) {
@ -5042,6 +5059,9 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
break;
case XML_ROLE_ENTITY_VALUE:
if (dtd->keepProcessing) {
#if XML_GE == 1
// This will store the given replacement text in
// parser->m_declEntity->textPtr.
enum XML_Error result
= storeEntityValue(parser, enc, s + enc->minBytesPerChar,
next - enc->minBytesPerChar, XML_ACCOUNT_NONE);
@ -5062,6 +5082,25 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
poolDiscard(&dtd->entityValuePool);
if (result != XML_ERROR_NONE)
return result;
#else
// This will store "&amp;entity123;" in parser->m_declEntity->textPtr
// to end up as "&entity123;" in the handler.
if (parser->m_declEntity != NULL) {
const enum XML_Error result
= storeSelfEntityValue(parser, parser->m_declEntity);
if (result != XML_ERROR_NONE)
return result;
if (parser->m_entityDeclHandler) {
*eventEndPP = s;
parser->m_entityDeclHandler(
parser->m_handlerArg, parser->m_declEntity->name,
parser->m_declEntity->is_param, parser->m_declEntity->textPtr,
parser->m_declEntity->textLen, parser->m_curBase, 0, 0, 0);
handleDefault = XML_FALSE;
}
}
#endif
}
break;
case XML_ROLE_DOCTYPE_SYSTEM_ID:
@ -5120,6 +5159,16 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
}
break;
case XML_ROLE_ENTITY_COMPLETE:
#if XML_GE == 0
// This will store "&amp;entity123;" in entity->textPtr
// to end up as "&entity123;" in the handler.
if (parser->m_declEntity != NULL) {
const enum XML_Error result
= storeSelfEntityValue(parser, parser->m_declEntity);
if (result != XML_ERROR_NONE)
return result;
}
#endif
if (dtd->keepProcessing && parser->m_declEntity
&& parser->m_entityDeclHandler) {
*eventEndPP = s;
@ -5661,7 +5710,7 @@ epilogProcessor(XML_Parser parser, const char *s, const char *end,
for (;;) {
const char *next = NULL;
int tok = XmlPrologTok(parser->m_encoding, s, end, &next);
#ifdef XML_DTD
#if XML_GE == 1
if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
XML_ACCOUNT_DIRECT)) {
accountingOnAbort(parser);
@ -5741,7 +5790,7 @@ processInternalEntity(XML_Parser parser, ENTITY *entity, XML_Bool betweenDecl) {
return XML_ERROR_NO_MEMORY;
}
entity->open = XML_TRUE;
#ifdef XML_DTD
#if XML_GE == 1
entityTrackingOnOpen(parser, entity, __LINE__);
#endif
entity->processed = 0;
@ -5775,9 +5824,9 @@ processInternalEntity(XML_Parser parser, ENTITY *entity, XML_Bool betweenDecl) {
entity->processed = (int)(next - textStart);
parser->m_processor = internalEntityProcessor;
} else {
#ifdef XML_DTD
#if XML_GE == 1
entityTrackingOnClose(parser, entity, __LINE__);
#endif /* XML_DTD */
#endif /* XML_GE == 1 */
entity->open = XML_FALSE;
parser->m_openInternalEntities = openEntity->next;
/* put openEntity back in list of free instances */
@ -5826,7 +5875,7 @@ internalEntityProcessor(XML_Parser parser, const char *s, const char *end,
return result;
}
#ifdef XML_DTD
#if XML_GE == 1
entityTrackingOnClose(parser, entity, __LINE__);
#endif
entity->open = XML_FALSE;
@ -5905,7 +5954,7 @@ appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
const char *next
= ptr; /* XmlAttributeValueTok doesn't always set the last arg */
int tok = XmlAttributeValueTok(enc, ptr, end, &next);
#ifdef XML_DTD
#if XML_GE == 1
if (! accountingDiffTolerated(parser, tok, ptr, next, __LINE__, account)) {
accountingOnAbort(parser);
return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
@ -5970,14 +6019,14 @@ appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
XML_Char ch = (XML_Char)XmlPredefinedEntityName(
enc, ptr + enc->minBytesPerChar, next - enc->minBytesPerChar);
if (ch) {
#ifdef XML_DTD
#if XML_GE == 1
/* NOTE: We are replacing 4-6 characters original input for 1 character
* so there is no amplification and hence recording without
* protection. */
accountingDiffTolerated(parser, tok, (char *)&ch,
((char *)&ch) + sizeof(XML_Char), __LINE__,
XML_ACCOUNT_ENTITY_EXPANSION);
#endif /* XML_DTD */
#endif /* XML_GE == 1 */
if (! poolAppendChar(pool, ch))
return XML_ERROR_NO_MEMORY;
break;
@ -6055,14 +6104,14 @@ appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
enum XML_Error result;
const XML_Char *textEnd = entity->textPtr + entity->textLen;
entity->open = XML_TRUE;
#ifdef XML_DTD
#if XML_GE == 1
entityTrackingOnOpen(parser, entity, __LINE__);
#endif
result = appendAttributeValue(parser, parser->m_internalEncoding,
isCdata, (const char *)entity->textPtr,
(const char *)textEnd, pool,
XML_ACCOUNT_ENTITY_EXPANSION);
#ifdef XML_DTD
#if XML_GE == 1
entityTrackingOnClose(parser, entity, __LINE__);
#endif
entity->open = XML_FALSE;
@ -6092,6 +6141,7 @@ appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
/* not reached */
}
#if XML_GE == 1
static enum XML_Error
storeEntityValue(XML_Parser parser, const ENCODING *enc,
const char *entityTextPtr, const char *entityTextEnd,
@ -6099,12 +6149,12 @@ storeEntityValue(XML_Parser parser, const ENCODING *enc,
DTD *const dtd = parser->m_dtd; /* save one level of indirection */
STRING_POOL *pool = &(dtd->entityValuePool);
enum XML_Error result = XML_ERROR_NONE;
#ifdef XML_DTD
# ifdef XML_DTD
int oldInEntityValue = parser->m_prologState.inEntityValue;
parser->m_prologState.inEntityValue = 1;
#else
# else
UNUSED_P(account);
#endif /* XML_DTD */
# endif /* XML_DTD */
/* never return Null for the value argument in EntityDeclHandler,
since this would indicate an external entity; therefore we
have to make sure that entityValuePool.start is not null */
@ -6118,18 +6168,16 @@ storeEntityValue(XML_Parser parser, const ENCODING *enc,
= entityTextPtr; /* XmlEntityValueTok doesn't always set the last arg */
int tok = XmlEntityValueTok(enc, entityTextPtr, entityTextEnd, &next);
#ifdef XML_DTD
if (! accountingDiffTolerated(parser, tok, entityTextPtr, next, __LINE__,
account)) {
accountingOnAbort(parser);
result = XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
goto endEntityValue;
}
#endif
switch (tok) {
case XML_TOK_PARAM_ENTITY_REF:
#ifdef XML_DTD
# ifdef XML_DTD
if (parser->m_isParamEntity || enc != parser->m_encoding) {
const XML_Char *name;
ENTITY *entity;
@ -6191,7 +6239,7 @@ storeEntityValue(XML_Parser parser, const ENCODING *enc,
}
break;
}
#endif /* XML_DTD */
# endif /* XML_DTD */
/* In the internal subset, PE references are not legal
within markup declarations, e.g entity values in this case. */
parser->m_eventPtr = entityTextPtr;
@ -6272,12 +6320,38 @@ storeEntityValue(XML_Parser parser, const ENCODING *enc,
entityTextPtr = next;
}
endEntityValue:
#ifdef XML_DTD
# ifdef XML_DTD
parser->m_prologState.inEntityValue = oldInEntityValue;
#endif /* XML_DTD */
# endif /* XML_DTD */
return result;
}
#else /* XML_GE == 0 */
static enum XML_Error
storeSelfEntityValue(XML_Parser parser, ENTITY *entity) {
// This will store "&amp;entity123;" in entity->textPtr
// to end up as "&entity123;" in the handler.
const char *const entity_start = "&amp;";
const char *const entity_end = ";";
STRING_POOL *const pool = &(parser->m_dtd->entityValuePool);
if (! poolAppendString(pool, entity_start)
|| ! poolAppendString(pool, entity->name)
|| ! poolAppendString(pool, entity_end)) {
poolDiscard(pool);
return XML_ERROR_NO_MEMORY;
}
entity->textPtr = poolStart(pool);
entity->textLen = (int)(poolLength(pool));
poolFinish(pool);
return XML_ERROR_NONE;
}
#endif /* XML_GE == 0 */
static void FASTCALL
normalizeLines(XML_Char *s) {
XML_Char *p;
@ -7669,7 +7743,7 @@ copyString(const XML_Char *s, const XML_Memory_Handling_Suite *memsuite) {
return result;
}
#ifdef XML_DTD
#if XML_GE == 1
static float
accountingGetCurrentAmplification(XML_Parser rootParser) {
@ -8400,7 +8474,7 @@ unsignedCharToPrintable(unsigned char c) {
assert(0); /* never gets here */
}
#endif /* XML_DTD */
#endif /* XML_GE == 1 */
static unsigned long
getDebugLevel(const char *variableName, unsigned long defaultDebugLevel) {

View file

@ -55,7 +55,7 @@
#include "handlers.h"
#include "acc_tests.h"
#if defined(XML_DTD)
#if XML_GE == 1
START_TEST(test_accounting_precision) {
struct AccountingTestCase cases[] = {
{"<e/>", NULL, NULL, 0},
@ -93,9 +93,12 @@ START_TEST(test_accounting_precision) {
/* Processing instructions */
{"<?xml-stylesheet type=\"text/xsl\" href=\"https://domain.invalid/\" media=\"all\"?><e/>",
NULL, NULL, 0},
{"<?pi0?><?pi1 ?><?pi2 ?><r/><?pi4?>", NULL, NULL, 0},
# ifdef XML_DTD
{"<?pi0?><?pi1 ?><?pi2 ?><!DOCTYPE r SYSTEM 'first.ent'><r/>",
"<?pi3?><!ENTITY % e1 SYSTEM 'second.ent'><?pi4?>%e1;<?pi5?>", "<?pi6?>",
0},
# endif /* XML_DTD */
/* CDATA */
{"<e><![CDATA[one two three]]></e>", NULL, NULL, 0},
@ -109,6 +112,7 @@ START_TEST(test_accounting_precision) {
"<r>&e;</r>\n",
NULL, NULL, sizeof(XML_Char) * strlen("111<![CDATA[2 <= 2]]>333")},
# ifdef XML_DTD
/* Conditional sections */
{"<!DOCTYPE r [\n"
"<!ENTITY % draft 'INCLUDE'>\n"
@ -120,6 +124,7 @@ START_TEST(test_accounting_precision) {
"<![%draft;[<!--1-->]]>\n"
"<![%final;[<!--22-->]]>",
NULL, sizeof(XML_Char) * (strlen("INCLUDE") + strlen("IGNORE"))},
# endif /* XML_DTD */
/* General entities */
{"<!DOCTYPE root [\n"
@ -151,6 +156,7 @@ START_TEST(test_accounting_precision) {
"<r>&five;</r>",
"\xEF\xBB\xBF" /* UTF-8 BOM */, NULL, 0},
# ifdef XML_DTD
/* Parameter entities */
{"<!DOCTYPE r [\n"
"<!ENTITY % comment \"<!---->\">\n"
@ -229,6 +235,7 @@ START_TEST(test_accounting_precision) {
"%e1;\n",
"\xEF\xBB\xBF<!ATTLIST doc a1 CDATA 'value'>" /* UTF-8 BOM */,
strlen("\xEF\xBB\xBF<!ATTLIST doc a1 CDATA 'value'>")},
# endif /* XML_DTD */
};
const size_t countCases = sizeof(cases) / sizeof(cases[0]);
@ -288,8 +295,8 @@ END_TEST
START_TEST(test_billion_laughs_attack_protection_api) {
XML_Parser parserWithoutParent = XML_ParserCreate(NULL);
XML_Parser parserWithParent
= XML_ExternalEntityParserCreate(parserWithoutParent, NULL, NULL);
XML_Parser parserWithParent = XML_ExternalEntityParserCreate(
parserWithoutParent, XCS("entity123"), NULL);
if (parserWithoutParent == NULL)
fail("parserWithoutParent is NULL");
if (parserWithParent == NULL)
@ -371,11 +378,11 @@ START_TEST(test_helper_unsigned_char_to_printable) {
fail("unsignedCharToPrintable result mistaken");
}
END_TEST
#endif // defined(XML_DTD)
#endif // XML_GE == 1
void
make_accounting_test_case(Suite *s) {
#if defined(XML_DTD)
#if XML_GE == 1
TCase *tc_accounting = tcase_create("accounting tests");
suite_add_tcase(s, tc_accounting);
@ -385,5 +392,5 @@ make_accounting_test_case(Suite *s) {
tcase_add_test(tc_accounting, test_helper_unsigned_char_to_printable);
#else
UNUSED_P(s);
#endif /* defined(XML_DTD) */
#endif /* XML_GE == 1 */
}

View file

@ -2083,7 +2083,7 @@ make_alloc_test_case(Suite *s) {
tcase_add_test(tc_alloc, test_alloc_explicit_encoding);
tcase_add_test(tc_alloc, test_alloc_set_base);
tcase_add_test(tc_alloc, test_alloc_realloc_buffer);
tcase_add_test(tc_alloc, test_alloc_ext_entity_realloc_buffer);
tcase_add_test__if_xml_ge(tc_alloc, test_alloc_ext_entity_realloc_buffer);
tcase_add_test(tc_alloc, test_alloc_realloc_many_attributes);
tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_public_entity_value);
tcase_add_test__ifdef_xml_dtd(tc_alloc,
@ -2096,7 +2096,7 @@ make_alloc_test_case(Suite *s) {
test_alloc_realloc_attribute_enum_value);
tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_realloc_implied_attribute);
tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_realloc_default_attribute);
tcase_add_test(tc_alloc, test_alloc_notation);
tcase_add_test__if_xml_ge(tc_alloc, test_alloc_notation);
tcase_add_test(tc_alloc, test_alloc_public_notation);
tcase_add_test(tc_alloc, test_alloc_system_notation);
tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_nested_groups);
@ -2110,17 +2110,17 @@ make_alloc_test_case(Suite *s) {
tcase_add_test(tc_alloc, test_alloc_attribute_whitespace);
tcase_add_test(tc_alloc, test_alloc_attribute_predefined_entity);
tcase_add_test(tc_alloc, test_alloc_long_attr_default_with_char_ref);
tcase_add_test(tc_alloc, test_alloc_long_attr_value);
tcase_add_test__if_xml_ge(tc_alloc, test_alloc_long_attr_value);
tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_nested_entities);
tcase_add_test__ifdef_xml_dtd(tc_alloc,
test_alloc_realloc_param_entity_newline);
tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_realloc_ce_extends_pe);
tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_realloc_attributes);
tcase_add_test(tc_alloc, test_alloc_long_doc_name);
tcase_add_test(tc_alloc, test_alloc_long_base);
tcase_add_test(tc_alloc, test_alloc_long_public_id);
tcase_add_test(tc_alloc, test_alloc_long_entity_value);
tcase_add_test(tc_alloc, test_alloc_long_notation);
tcase_add_test__if_xml_ge(tc_alloc, test_alloc_long_base);
tcase_add_test__if_xml_ge(tc_alloc, test_alloc_long_public_id);
tcase_add_test__if_xml_ge(tc_alloc, test_alloc_long_entity_value);
tcase_add_test__if_xml_ge(tc_alloc, test_alloc_long_notation);
tcase_add_test__ifdef_xml_dtd(
tc_alloc, test_alloc_reset_after_external_entity_parser_create_fail);

View file

@ -5218,7 +5218,7 @@ make_basic_test_case(Suite *s) {
tcase_add_test(tc_basic, test_xmldecl_invalid);
tcase_add_test(tc_basic, test_xmldecl_missing_attr);
tcase_add_test(tc_basic, test_xmldecl_missing_value);
tcase_add_test(tc_basic, test_unknown_encoding_internal_entity);
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);
tcase_add_test__ifdef_xml_dtd(tc_basic, test_ext_entity_no_handler);
@ -5234,9 +5234,9 @@ make_basic_test_case(Suite *s) {
tcase_add_test(tc_basic, test_wfc_undeclared_entity_with_external_subset);
tcase_add_test(tc_basic, test_not_standalone_handler_reject);
tcase_add_test(tc_basic, test_not_standalone_handler_accept);
tcase_add_test(tc_basic, test_wfc_no_recursive_entity_refs);
tcase_add_test__if_xml_ge(tc_basic, test_wfc_no_recursive_entity_refs);
tcase_add_test__ifdef_xml_dtd(tc_basic, test_ext_entity_invalid_parse);
tcase_add_test(tc_basic, test_dtd_default_handling);
tcase_add_test__if_xml_ge(tc_basic, test_dtd_default_handling);
tcase_add_test(tc_basic, test_dtd_attr_handling);
tcase_add_test(tc_basic, test_empty_ns_without_namespaces);
tcase_add_test(tc_basic, test_ns_in_attribute_default_without_namespaces);
@ -5254,7 +5254,7 @@ make_basic_test_case(Suite *s) {
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__if_xml_ge(tc_basic, test_default_current);
tcase_add_test(tc_basic, test_dtd_elements);
tcase_add_test(tc_basic, test_dtd_elements_nesting);
tcase_add_test__ifdef_xml_dtd(tc_basic, test_set_foreign_dtd);
@ -5266,22 +5266,22 @@ make_basic_test_case(Suite *s) {
tcase_add_test__ifdef_xml_dtd(tc_basic, test_empty_foreign_dtd);
tcase_add_test(tc_basic, test_set_base);
tcase_add_test(tc_basic, test_attributes);
tcase_add_test(tc_basic, test_reset_in_entity);
tcase_add_test__if_xml_ge(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);
tcase_add_test(tc_basic, test_subordinate_xdecl_abort);
tcase_add_test__if_xml_ge(tc_basic, test_subordinate_xdecl_suspend);
tcase_add_test__if_xml_ge(tc_basic, test_subordinate_xdecl_abort);
tcase_add_test__ifdef_xml_dtd(tc_basic,
test_ext_entity_invalid_suspended_parse);
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__if_xml_ge(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__if_xml_ge(tc_basic, test_ext_entity_trailing_rsqb);
tcase_add_test__if_xml_ge(tc_basic, test_ext_entity_good_cdata);
tcase_add_test__ifdef_xml_dtd(tc_basic, test_user_parameters);
tcase_add_test__ifdef_xml_dtd(tc_basic, test_ext_entity_ref_parameter);
tcase_add_test(tc_basic, test_empty_parse);
@ -5338,10 +5338,10 @@ make_basic_test_case(Suite *s) {
tcase_add_test(tc_basic, test_skipped_null_loaded_ext_entity);
tcase_add_test(tc_basic, test_skipped_unloaded_ext_entity);
tcase_add_test__ifdef_xml_dtd(tc_basic, test_param_entity_with_trailing_cr);
tcase_add_test(tc_basic, test_invalid_character_entity);
tcase_add_test(tc_basic, test_invalid_character_entity_2);
tcase_add_test(tc_basic, test_invalid_character_entity_3);
tcase_add_test(tc_basic, test_invalid_character_entity_4);
tcase_add_test__if_xml_ge(tc_basic, test_invalid_character_entity);
tcase_add_test__if_xml_ge(tc_basic, test_invalid_character_entity_2);
tcase_add_test__if_xml_ge(tc_basic, test_invalid_character_entity_3);
tcase_add_test__if_xml_ge(tc_basic, test_invalid_character_entity_4);
tcase_add_test(tc_basic, test_pi_handled_in_default);
tcase_add_test(tc_basic, test_comment_handled_in_default);
tcase_add_test(tc_basic, test_pi_yml);
@ -5366,14 +5366,14 @@ make_basic_test_case(Suite *s) {
tcase_add_test(tc_basic, test_unknown_encoding_invalid_surrogate);
tcase_add_test(tc_basic, test_unknown_encoding_invalid_high);
tcase_add_test(tc_basic, test_unknown_encoding_invalid_attr_value);
tcase_add_test(tc_basic, test_ext_entity_latin1_utf16le_bom);
tcase_add_test(tc_basic, test_ext_entity_latin1_utf16be_bom);
tcase_add_test(tc_basic, test_ext_entity_latin1_utf16le_bom2);
tcase_add_test(tc_basic, test_ext_entity_latin1_utf16be_bom2);
tcase_add_test(tc_basic, test_ext_entity_utf16_be);
tcase_add_test(tc_basic, test_ext_entity_utf16_le);
tcase_add_test(tc_basic, test_ext_entity_utf16_unknown);
tcase_add_test(tc_basic, test_ext_entity_utf8_non_bom);
tcase_add_test__if_xml_ge(tc_basic, test_ext_entity_latin1_utf16le_bom);
tcase_add_test__if_xml_ge(tc_basic, test_ext_entity_latin1_utf16be_bom);
tcase_add_test__if_xml_ge(tc_basic, test_ext_entity_latin1_utf16le_bom2);
tcase_add_test__if_xml_ge(tc_basic, test_ext_entity_latin1_utf16be_bom2);
tcase_add_test__if_xml_ge(tc_basic, test_ext_entity_utf16_be);
tcase_add_test__if_xml_ge(tc_basic, test_ext_entity_utf16_le);
tcase_add_test__if_xml_ge(tc_basic, test_ext_entity_utf16_unknown);
tcase_add_test__if_xml_ge(tc_basic, test_ext_entity_utf8_non_bom);
tcase_add_test(tc_basic, test_utf8_in_cdata_section);
tcase_add_test(tc_basic, test_utf8_in_cdata_section_2);
tcase_add_test(tc_basic, test_utf8_in_start_tags);
@ -5408,5 +5408,5 @@ make_basic_test_case(Suite *s) {
tcase_add_test(tc_basic, test_empty_element_abort);
tcase_add_test__ifdef_xml_dtd(tc_basic,
test_pool_integrity_with_unfinished_attr);
tcase_add_test(tc_basic, test_nested_entity_suspend);
tcase_add_test__if_xml_ge(tc_basic, test_nested_entity_suspend);
}

View file

@ -153,6 +153,16 @@ tcase_add_test__ifdef_xml_dtd(TCase *tc, tcase_test_function test) {
#endif
}
void
tcase_add_test__if_xml_ge(TCase *tc, tcase_test_function test) {
#if XML_GE == 1
tcase_add_test(tc, test);
#else
UNUSED_P(tc);
UNUSED_P(test);
#endif
}
void
basic_teardown(void) {
if (g_parser != NULL) {

View file

@ -90,6 +90,7 @@ extern const char *long_cdata_text;
extern const char *get_buffer_test_text;
extern void tcase_add_test__ifdef_xml_dtd(TCase *tc, tcase_test_function test);
extern void tcase_add_test__if_xml_ge(TCase *tc, tcase_test_function test);
extern void basic_teardown(void);

View file

@ -669,6 +669,24 @@ external_entity_suspending_faulter(XML_Parser parser, const XML_Char *context,
return XML_STATUS_ERROR;
}
int XMLCALL
external_entity_failer__if_not_xml_ge(XML_Parser parser,
const XML_Char *context,
const XML_Char *base,
const XML_Char *systemId,
const XML_Char *publicId) {
UNUSED_P(parser);
UNUSED_P(context);
UNUSED_P(base);
UNUSED_P(systemId);
UNUSED_P(publicId);
#if XML_GE == 0
fail(
"Function external_entity_suspending_failer was called despite XML_GE==0.");
#endif
return XML_STATUS_OK;
}
int XMLCALL
external_entity_cr_catcher(XML_Parser parser, const XML_Char *context,
const XML_Char *base, const XML_Char *systemId,
@ -1476,7 +1494,7 @@ external_entity_parser_create_alloc_fail_handler(XML_Parser parser,
return XML_STATUS_ERROR;
}
#if defined(XML_DTD)
#if XML_GE == 1
int
accounting_external_entity_ref_handler(XML_Parser parser,
const XML_Char *context,
@ -1508,7 +1526,7 @@ accounting_external_entity_ref_handler(XML_Parser parser,
XML_ParserFree(entParser);
return status;
}
#endif /* XML_DTD */
#endif /* XML_GE == 1 */
/* NotStandalone handlers */
@ -1853,10 +1871,43 @@ accumulate_entity_decl(void *userData, const XML_Char *entityName,
UNUSED_P(notationName);
CharData_AppendXMLChars(storage, entityName, -1);
CharData_AppendXMLChars(storage, XCS("="), 1);
CharData_AppendXMLChars(storage, value, value_length);
if (value == NULL)
CharData_AppendXMLChars(storage, XCS("(null)"), -1);
else
CharData_AppendXMLChars(storage, value, value_length);
CharData_AppendXMLChars(storage, XCS("\n"), 1);
}
void XMLCALL
accumulate_char_data(void *userData, const XML_Char *s, int len) {
CharData *const storage = (CharData *)userData;
CharData_AppendXMLChars(storage, s, len);
}
void XMLCALL
accumulate_start_element(void *userData, const XML_Char *name,
const XML_Char **atts) {
CharData *const storage = (CharData *)userData;
CharData_AppendXMLChars(storage, XCS("("), 1);
CharData_AppendXMLChars(storage, name, -1);
if ((atts != NULL) && (atts[0] != NULL)) {
CharData_AppendXMLChars(storage, XCS("("), 1);
while (atts[0] != NULL) {
CharData_AppendXMLChars(storage, atts[0], -1);
CharData_AppendXMLChars(storage, XCS("="), 1);
CharData_AppendXMLChars(storage, atts[1], -1);
atts += 2;
if (atts[0] != NULL) {
CharData_AppendXMLChars(storage, XCS(","), 1);
}
}
CharData_AppendXMLChars(storage, XCS(")"), 1);
}
CharData_AppendXMLChars(storage, XCS(")\n"), 2);
}
void XMLCALL
checking_default_handler(void *userData, const XML_Char *s, int len) {
DefaultCheck *data = (DefaultCheck *)userData;

View file

@ -185,6 +185,9 @@ extern int XMLCALL external_entity_faulter(XML_Parser parser,
const XML_Char *base,
const XML_Char *systemId,
const XML_Char *publicId);
extern int XMLCALL external_entity_failer__if_not_xml_ge(
XML_Parser parser, const XML_Char *context, const XML_Char *base,
const XML_Char *systemId, const XML_Char *publicId);
extern int XMLCALL external_entity_null_loader(XML_Parser parser,
const XML_Char *context,
const XML_Char *base,
@ -404,7 +407,6 @@ extern int XMLCALL external_entity_parser_create_alloc_fail_handler(
XML_Parser parser, const XML_Char *context, const XML_Char *base,
const XML_Char *systemId, const XML_Char *publicId);
# if defined(XML_DTD)
struct AccountingTestCase {
const char *primaryText;
const char *firstExternalText; /* often NULL */
@ -417,7 +419,6 @@ extern int accounting_external_entity_ref_handler(XML_Parser parser,
const XML_Char *base,
const XML_Char *systemId,
const XML_Char *publicId);
# endif /* defined(XML_DTD) */
/* NotStandalone handlers */
@ -563,6 +564,13 @@ extern void XMLCALL accumulate_entity_decl(
const XML_Char *systemId, const XML_Char *publicId,
const XML_Char *notationName);
extern void XMLCALL accumulate_char_data(void *userData, const XML_Char *s,
int len);
extern void XMLCALL accumulate_start_element(void *userData,
const XML_Char *name,
const XML_Char **atts);
typedef struct default_check {
const XML_Char *expected;
const int expectedLen;

View file

@ -406,6 +406,50 @@ START_TEST(test_misc_create_external_entity_parser_with_null_context) {
}
END_TEST
START_TEST(test_misc_general_entities_support) {
const char *const doc
= "<!DOCTYPE r [\n"
"<!ENTITY e1 'v1'>\n"
"<!ENTITY e2 SYSTEM 'v2'>\n"
"]>\n"
"<r a1='[&e1;]'>[&e1;][&e2;][&amp;&apos;&gt;&lt;&quot;]</r>";
CharData storage;
CharData_Init(&storage);
XML_Parser parser = XML_ParserCreate(NULL);
XML_SetUserData(parser, &storage);
XML_SetStartElementHandler(parser, accumulate_start_element);
XML_SetExternalEntityRefHandler(parser,
external_entity_failer__if_not_xml_ge);
XML_SetEntityDeclHandler(parser, accumulate_entity_decl);
XML_SetCharacterDataHandler(parser, accumulate_char_data);
if (_XML_Parse_SINGLE_BYTES(parser, doc, (int)strlen(doc), XML_TRUE)
!= XML_STATUS_OK) {
xml_failure(parser);
}
XML_ParserFree(parser);
CharData_CheckXMLChars(&storage,
/* clang-format off */
#if XML_GE == 1
XCS("e1=v1\n")
XCS("e2=(null)\n")
XCS("(r(a1=[v1]))\n")
XCS("[v1][][&'><\"]")
#else
XCS("e1=&amp;e1;\n")
XCS("e2=(null)\n")
XCS("(r(a1=[&e1;]))\n")
XCS("[&e1;][&e2;][&'><\"]")
#endif
);
/* clang-format on */
}
END_TEST
void
make_miscellaneous_test_case(Suite *s) {
TCase *tc_misc = tcase_create("miscellaneous tests");
@ -428,4 +472,5 @@ make_miscellaneous_test_case(Suite *s) {
tcase_add_test(tc_misc, test_misc_tag_mismatch_reset_leak);
tcase_add_test(tc_misc,
test_misc_create_external_entity_parser_with_null_context);
tcase_add_test(tc_misc, test_misc_general_entities_support);
}

View file

@ -747,7 +747,7 @@ make_namespace_test_case(Suite *s) {
tcase_add_test(tc_namespace, test_ns_bad_element_leafname);
tcase_add_test(tc_namespace, test_ns_utf16_leafname);
tcase_add_test(tc_namespace, test_ns_utf16_element_leafname);
tcase_add_test(tc_namespace, test_ns_utf16_doctype);
tcase_add_test__if_xml_ge(tc_namespace, test_ns_utf16_doctype);
tcase_add_test(tc_namespace, test_ns_invalid_doctype);
tcase_add_test(tc_namespace, test_ns_double_colon_doctype);
tcase_add_test(tc_namespace, test_ns_separator_in_uri);

View file

@ -1521,16 +1521,17 @@ make_nsalloc_test_case(Suite *s) {
tcase_add_test(tc_nsalloc, test_nsalloc_long_namespace);
tcase_add_test(tc_nsalloc, test_nsalloc_less_long_namespace);
tcase_add_test(tc_nsalloc, test_nsalloc_long_context);
tcase_add_test(tc_nsalloc, test_nsalloc_realloc_long_context);
tcase_add_test(tc_nsalloc, test_nsalloc_realloc_long_context_2);
tcase_add_test(tc_nsalloc, test_nsalloc_realloc_long_context_3);
tcase_add_test(tc_nsalloc, test_nsalloc_realloc_long_context_4);
tcase_add_test(tc_nsalloc, test_nsalloc_realloc_long_context_5);
tcase_add_test(tc_nsalloc, test_nsalloc_realloc_long_context_6);
tcase_add_test(tc_nsalloc, test_nsalloc_realloc_long_context_7);
tcase_add_test__if_xml_ge(tc_nsalloc, test_nsalloc_realloc_long_context);
tcase_add_test__if_xml_ge(tc_nsalloc, test_nsalloc_realloc_long_context_2);
tcase_add_test__if_xml_ge(tc_nsalloc, test_nsalloc_realloc_long_context_3);
tcase_add_test__if_xml_ge(tc_nsalloc, test_nsalloc_realloc_long_context_4);
tcase_add_test__if_xml_ge(tc_nsalloc, test_nsalloc_realloc_long_context_5);
tcase_add_test__if_xml_ge(tc_nsalloc, test_nsalloc_realloc_long_context_6);
tcase_add_test__if_xml_ge(tc_nsalloc, test_nsalloc_realloc_long_context_7);
tcase_add_test(tc_nsalloc, test_nsalloc_realloc_long_ge_name);
tcase_add_test(tc_nsalloc, test_nsalloc_realloc_long_context_in_dtd);
tcase_add_test(tc_nsalloc, test_nsalloc_long_default_in_ext);
tcase_add_test__if_xml_ge(tc_nsalloc,
test_nsalloc_realloc_long_context_in_dtd);
tcase_add_test__if_xml_ge(tc_nsalloc, test_nsalloc_long_default_in_ext);
tcase_add_test(tc_nsalloc, test_nsalloc_long_systemid_in_ext);
tcase_add_test(tc_nsalloc, test_nsalloc_prefixed_element);
}

View file

@ -69,7 +69,7 @@ make_suite(void) {
make_miscellaneous_test_case(s);
make_alloc_test_case(s);
make_nsalloc_test_case(s);
#if defined(XML_DTD)
#if XML_GE == 1
make_accounting_test_case(s);
#endif

View file

@ -1096,9 +1096,10 @@ tmain(int argc, XML_Char **argv) {
" (needs a floating point number greater or equal than 1.0)"));
exit(XMLWF_EXIT_USAGE_ERROR);
}
#ifndef XML_DTD
ftprintf(stderr, T("Warning: Given amplification limit ignored") T(
", xmlwf has been compiled without DTD support.\n"));
#if XML_GE == 0
ftprintf(stderr,
T("Warning: Given amplification limit ignored")
T(", xmlwf has been compiled without DTD/GE support.\n"));
#endif
break;
}
@ -1117,9 +1118,10 @@ tmain(int argc, XML_Char **argv) {
exit(XMLWF_EXIT_USAGE_ERROR);
}
attackThresholdGiven = XML_TRUE;
#ifndef XML_DTD
ftprintf(stderr, T("Warning: Given attack threshold ignored") T(
", xmlwf has been compiled without DTD support.\n"));
#if XML_GE == 0
ftprintf(stderr,
T("Warning: Given attack threshold ignored")
T(", xmlwf has been compiled without DTD/GE support.\n"));
#endif
break;
}
@ -1155,13 +1157,13 @@ tmain(int argc, XML_Char **argv) {
}
if (attackMaximumAmplification != -1.0f) {
#ifdef XML_DTD
#if XML_GE == 1
XML_SetBillionLaughsAttackProtectionMaximumAmplification(
parser, attackMaximumAmplification);
#endif
}
if (attackThresholdGiven) {
#ifdef XML_DTD
#if XML_GE == 1
XML_SetBillionLaughsAttackProtectionActivationThreshold(
parser, attackThresholdBytes);
#else