Fixes issue #14234: CVE-2012-0876: Randomize hashes of xml attributes
in the hash table internal to the pyexpat module's copy of the expat library to avoid a denial of service due to hash collisions. Patch by David Malcolm with some modifications by the expat project.
This commit is contained in:
parent
273cd1812a
commit
8e91cf6a5e
|
@ -15,6 +15,11 @@ Core and Builtins
|
||||||
service attacks due to hash collisions within the dict and set types. Patch
|
service attacks due to hash collisions within the dict and set types. Patch
|
||||||
by David Malcolm, based on work by Victor Stinner.
|
by David Malcolm, based on work by Victor Stinner.
|
||||||
|
|
||||||
|
- Issue #14234: CVE-2012-0876: Randomize hashes of xml attributes in the hash
|
||||||
|
table internal to the pyexpat module's copy of the expat library to avoid a
|
||||||
|
denial of service due to hash collisions. Patch by David Malcolm with some
|
||||||
|
modifications by the expat project.
|
||||||
|
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
|
|
@ -883,6 +883,15 @@ XMLPARSEAPI(int)
|
||||||
XML_SetParamEntityParsing(XML_Parser parser,
|
XML_SetParamEntityParsing(XML_Parser parser,
|
||||||
enum XML_ParamEntityParsing parsing);
|
enum XML_ParamEntityParsing parsing);
|
||||||
|
|
||||||
|
/* Sets the hash salt to use for internal hash calculations.
|
||||||
|
Helps in preventing DoS attacks based on predicting hash
|
||||||
|
function behavior. This must be called before parsing is started.
|
||||||
|
Returns 1 if successful, 0 when called after parsing has started.
|
||||||
|
*/
|
||||||
|
XMLPARSEAPI(int)
|
||||||
|
XML_SetHashSalt(XML_Parser parser,
|
||||||
|
unsigned long hash_salt);
|
||||||
|
|
||||||
/* If XML_Parse or XML_ParseBuffer have returned XML_STATUS_ERROR, then
|
/* If XML_Parse or XML_ParseBuffer have returned XML_STATUS_ERROR, then
|
||||||
XML_GetErrorCode returns information about the error.
|
XML_GetErrorCode returns information about the error.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -97,6 +97,7 @@
|
||||||
#define XML_SetEntityDeclHandler PyExpat_XML_SetEntityDeclHandler
|
#define XML_SetEntityDeclHandler PyExpat_XML_SetEntityDeclHandler
|
||||||
#define XML_SetExternalEntityRefHandler PyExpat_XML_SetExternalEntityRefHandler
|
#define XML_SetExternalEntityRefHandler PyExpat_XML_SetExternalEntityRefHandler
|
||||||
#define XML_SetExternalEntityRefHandlerArg PyExpat_XML_SetExternalEntityRefHandlerArg
|
#define XML_SetExternalEntityRefHandlerArg PyExpat_XML_SetExternalEntityRefHandlerArg
|
||||||
|
#define XML_SetHashSalt PyExpat_XML_SetHashSalt
|
||||||
#define XML_SetNamespaceDeclHandler PyExpat_XML_SetNamespaceDeclHandler
|
#define XML_SetNamespaceDeclHandler PyExpat_XML_SetNamespaceDeclHandler
|
||||||
#define XML_SetNotationDeclHandler PyExpat_XML_SetNotationDeclHandler
|
#define XML_SetNotationDeclHandler PyExpat_XML_SetNotationDeclHandler
|
||||||
#define XML_SetNotStandaloneHandler PyExpat_XML_SetNotStandaloneHandler
|
#define XML_SetNotStandaloneHandler PyExpat_XML_SetNotStandaloneHandler
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <string.h> /* memset(), memcpy() */
|
#include <string.h> /* memset(), memcpy() */
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <limits.h> /* UINT_MAX */
|
||||||
|
#include <time.h> /* time() */
|
||||||
|
|
||||||
#include "expat.h"
|
#include "expat.h"
|
||||||
|
|
||||||
|
@ -387,12 +389,13 @@ static void dtdReset(DTD *p, const XML_Memory_Handling_Suite *ms);
|
||||||
static void
|
static void
|
||||||
dtdDestroy(DTD *p, XML_Bool isDocEntity, const XML_Memory_Handling_Suite *ms);
|
dtdDestroy(DTD *p, XML_Bool isDocEntity, const XML_Memory_Handling_Suite *ms);
|
||||||
static int
|
static int
|
||||||
dtdCopy(DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms);
|
dtdCopy(XML_Parser oldParser,
|
||||||
|
DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms);
|
||||||
static int
|
static int
|
||||||
copyEntityTable(HASH_TABLE *, STRING_POOL *, const HASH_TABLE *);
|
copyEntityTable(XML_Parser oldParser,
|
||||||
|
HASH_TABLE *, STRING_POOL *, const HASH_TABLE *);
|
||||||
static NAMED *
|
static NAMED *
|
||||||
lookup(HASH_TABLE *table, KEY name, size_t createSize);
|
lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize);
|
||||||
static void FASTCALL
|
static void FASTCALL
|
||||||
hashTableInit(HASH_TABLE *, const XML_Memory_Handling_Suite *ms);
|
hashTableInit(HASH_TABLE *, const XML_Memory_Handling_Suite *ms);
|
||||||
static void FASTCALL hashTableClear(HASH_TABLE *);
|
static void FASTCALL hashTableClear(HASH_TABLE *);
|
||||||
|
@ -425,6 +428,9 @@ static ELEMENT_TYPE *
|
||||||
getElementType(XML_Parser parser, const ENCODING *enc,
|
getElementType(XML_Parser parser, const ENCODING *enc,
|
||||||
const char *ptr, const char *end);
|
const char *ptr, const char *end);
|
||||||
|
|
||||||
|
static unsigned long generate_hash_secret_salt(void);
|
||||||
|
static XML_Bool startParsing(XML_Parser parser);
|
||||||
|
|
||||||
static XML_Parser
|
static XML_Parser
|
||||||
parserCreate(const XML_Char *encodingName,
|
parserCreate(const XML_Char *encodingName,
|
||||||
const XML_Memory_Handling_Suite *memsuite,
|
const XML_Memory_Handling_Suite *memsuite,
|
||||||
|
@ -542,6 +548,7 @@ struct XML_ParserStruct {
|
||||||
XML_Bool m_useForeignDTD;
|
XML_Bool m_useForeignDTD;
|
||||||
enum XML_ParamEntityParsing m_paramEntityParsing;
|
enum XML_ParamEntityParsing m_paramEntityParsing;
|
||||||
#endif
|
#endif
|
||||||
|
unsigned long m_hash_secret_salt;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define MALLOC(s) (parser->m_mem.malloc_fcn((s)))
|
#define MALLOC(s) (parser->m_mem.malloc_fcn((s)))
|
||||||
|
@ -649,6 +656,7 @@ struct XML_ParserStruct {
|
||||||
#define useForeignDTD (parser->m_useForeignDTD)
|
#define useForeignDTD (parser->m_useForeignDTD)
|
||||||
#define paramEntityParsing (parser->m_paramEntityParsing)
|
#define paramEntityParsing (parser->m_paramEntityParsing)
|
||||||
#endif /* XML_DTD */
|
#endif /* XML_DTD */
|
||||||
|
#define hash_secret_salt (parser->m_hash_secret_salt)
|
||||||
|
|
||||||
XML_Parser XMLCALL
|
XML_Parser XMLCALL
|
||||||
XML_ParserCreate(const XML_Char *encodingName)
|
XML_ParserCreate(const XML_Char *encodingName)
|
||||||
|
@ -671,22 +679,36 @@ static const XML_Char implicitContext[] = {
|
||||||
'n', 'a', 'm', 'e', 's', 'p', 'a', 'c', 'e', '\0'
|
'n', 'a', 'm', 'e', 's', 'p', 'a', 'c', 'e', '\0'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static unsigned long
|
||||||
|
generate_hash_secret_salt(void)
|
||||||
|
{
|
||||||
|
unsigned int seed = time(NULL) % UINT_MAX;
|
||||||
|
srand(seed);
|
||||||
|
return rand();
|
||||||
|
}
|
||||||
|
|
||||||
|
static XML_Bool /* only valid for root parser */
|
||||||
|
startParsing(XML_Parser parser)
|
||||||
|
{
|
||||||
|
/* hash functions must be initialized before setContext() is called */
|
||||||
|
|
||||||
|
if (hash_secret_salt == 0)
|
||||||
|
hash_secret_salt = generate_hash_secret_salt();
|
||||||
|
if (ns) {
|
||||||
|
/* implicit context only set for root parser, since child
|
||||||
|
parsers (i.e. external entity parsers) will inherit it
|
||||||
|
*/
|
||||||
|
return setContext(parser, implicitContext);
|
||||||
|
}
|
||||||
|
return XML_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
XML_Parser XMLCALL
|
XML_Parser XMLCALL
|
||||||
XML_ParserCreate_MM(const XML_Char *encodingName,
|
XML_ParserCreate_MM(const XML_Char *encodingName,
|
||||||
const XML_Memory_Handling_Suite *memsuite,
|
const XML_Memory_Handling_Suite *memsuite,
|
||||||
const XML_Char *nameSep)
|
const XML_Char *nameSep)
|
||||||
{
|
{
|
||||||
XML_Parser parser = parserCreate(encodingName, memsuite, nameSep, NULL);
|
return parserCreate(encodingName, memsuite, nameSep, NULL);
|
||||||
if (parser != NULL && ns) {
|
|
||||||
/* implicit context only set for root parser, since child
|
|
||||||
parsers (i.e. external entity parsers) will inherit it
|
|
||||||
*/
|
|
||||||
if (!setContext(parser, implicitContext)) {
|
|
||||||
XML_ParserFree(parser);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return parser;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static XML_Parser
|
static XML_Parser
|
||||||
|
@ -860,6 +882,7 @@ parserInit(XML_Parser parser, const XML_Char *encodingName)
|
||||||
useForeignDTD = XML_FALSE;
|
useForeignDTD = XML_FALSE;
|
||||||
paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER;
|
paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER;
|
||||||
#endif
|
#endif
|
||||||
|
hash_secret_salt = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* moves list of bindings to freeBindingList */
|
/* moves list of bindings to freeBindingList */
|
||||||
|
@ -907,7 +930,7 @@ XML_ParserReset(XML_Parser parser, const XML_Char *encodingName)
|
||||||
poolClear(&temp2Pool);
|
poolClear(&temp2Pool);
|
||||||
parserInit(parser, encodingName);
|
parserInit(parser, encodingName);
|
||||||
dtdReset(_dtd, &parser->m_mem);
|
dtdReset(_dtd, &parser->m_mem);
|
||||||
return setContext(parser, implicitContext);
|
return XML_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum XML_Status XMLCALL
|
enum XML_Status XMLCALL
|
||||||
|
@ -976,6 +999,12 @@ XML_ExternalEntityParserCreate(XML_Parser oldParser,
|
||||||
int oldInEntityValue = prologState.inEntityValue;
|
int oldInEntityValue = prologState.inEntityValue;
|
||||||
#endif
|
#endif
|
||||||
XML_Bool oldns_triplets = ns_triplets;
|
XML_Bool oldns_triplets = ns_triplets;
|
||||||
|
/* Note that the new parser shares the same hash secret as the old
|
||||||
|
parser, so that dtdCopy and copyEntityTable can lookup values
|
||||||
|
from hash tables associated with either parser without us having
|
||||||
|
to worry which hash secrets each table has.
|
||||||
|
*/
|
||||||
|
unsigned long oldhash_secret_salt = hash_secret_salt;
|
||||||
|
|
||||||
#ifdef XML_DTD
|
#ifdef XML_DTD
|
||||||
if (!context)
|
if (!context)
|
||||||
|
@ -1029,13 +1058,14 @@ XML_ExternalEntityParserCreate(XML_Parser oldParser,
|
||||||
externalEntityRefHandlerArg = oldExternalEntityRefHandlerArg;
|
externalEntityRefHandlerArg = oldExternalEntityRefHandlerArg;
|
||||||
defaultExpandInternalEntities = oldDefaultExpandInternalEntities;
|
defaultExpandInternalEntities = oldDefaultExpandInternalEntities;
|
||||||
ns_triplets = oldns_triplets;
|
ns_triplets = oldns_triplets;
|
||||||
|
hash_secret_salt = oldhash_secret_salt;
|
||||||
parentParser = oldParser;
|
parentParser = oldParser;
|
||||||
#ifdef XML_DTD
|
#ifdef XML_DTD
|
||||||
paramEntityParsing = oldParamEntityParsing;
|
paramEntityParsing = oldParamEntityParsing;
|
||||||
prologState.inEntityValue = oldInEntityValue;
|
prologState.inEntityValue = oldInEntityValue;
|
||||||
if (context) {
|
if (context) {
|
||||||
#endif /* XML_DTD */
|
#endif /* XML_DTD */
|
||||||
if (!dtdCopy(_dtd, oldDtd, &parser->m_mem)
|
if (!dtdCopy(oldParser, _dtd, oldDtd, &parser->m_mem)
|
||||||
|| !setContext(parser, context)) {
|
|| !setContext(parser, context)) {
|
||||||
XML_ParserFree(parser);
|
XML_ParserFree(parser);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -1420,6 +1450,17 @@ XML_SetParamEntityParsing(XML_Parser parser,
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int XMLCALL
|
||||||
|
XML_SetHashSalt(XML_Parser parser,
|
||||||
|
unsigned long hash_salt)
|
||||||
|
{
|
||||||
|
/* block after XML_Parse()/XML_ParseBuffer() has been called */
|
||||||
|
if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED)
|
||||||
|
return 0;
|
||||||
|
hash_secret_salt = hash_salt;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
enum XML_Status XMLCALL
|
enum XML_Status XMLCALL
|
||||||
XML_Parse(XML_Parser parser, const char *s, int len, int isFinal)
|
XML_Parse(XML_Parser parser, const char *s, int len, int isFinal)
|
||||||
{
|
{
|
||||||
|
@ -1430,6 +1471,11 @@ XML_Parse(XML_Parser parser, const char *s, int len, int isFinal)
|
||||||
case XML_FINISHED:
|
case XML_FINISHED:
|
||||||
errorCode = XML_ERROR_FINISHED;
|
errorCode = XML_ERROR_FINISHED;
|
||||||
return XML_STATUS_ERROR;
|
return XML_STATUS_ERROR;
|
||||||
|
case XML_INITIALIZED:
|
||||||
|
if (parentParser == NULL && !startParsing(parser)) {
|
||||||
|
errorCode = XML_ERROR_NO_MEMORY;
|
||||||
|
return XML_STATUS_ERROR;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
ps_parsing = XML_PARSING;
|
ps_parsing = XML_PARSING;
|
||||||
}
|
}
|
||||||
|
@ -1488,11 +1534,13 @@ XML_Parse(XML_Parser parser, const char *s, int len, int isFinal)
|
||||||
break;
|
break;
|
||||||
case XML_INITIALIZED:
|
case XML_INITIALIZED:
|
||||||
case XML_PARSING:
|
case XML_PARSING:
|
||||||
result = XML_STATUS_OK;
|
|
||||||
if (isFinal) {
|
if (isFinal) {
|
||||||
ps_parsing = XML_FINISHED;
|
ps_parsing = XML_FINISHED;
|
||||||
return result;
|
return XML_STATUS_OK;
|
||||||
}
|
}
|
||||||
|
/* fall through */
|
||||||
|
default:
|
||||||
|
result = XML_STATUS_OK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1553,6 +1601,11 @@ XML_ParseBuffer(XML_Parser parser, int len, int isFinal)
|
||||||
case XML_FINISHED:
|
case XML_FINISHED:
|
||||||
errorCode = XML_ERROR_FINISHED;
|
errorCode = XML_ERROR_FINISHED;
|
||||||
return XML_STATUS_ERROR;
|
return XML_STATUS_ERROR;
|
||||||
|
case XML_INITIALIZED:
|
||||||
|
if (parentParser == NULL && !startParsing(parser)) {
|
||||||
|
errorCode = XML_ERROR_NO_MEMORY;
|
||||||
|
return XML_STATUS_ERROR;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
ps_parsing = XML_PARSING;
|
ps_parsing = XML_PARSING;
|
||||||
}
|
}
|
||||||
|
@ -2231,7 +2284,7 @@ doContent(XML_Parser parser,
|
||||||
next - enc->minBytesPerChar);
|
next - enc->minBytesPerChar);
|
||||||
if (!name)
|
if (!name)
|
||||||
return XML_ERROR_NO_MEMORY;
|
return XML_ERROR_NO_MEMORY;
|
||||||
entity = (ENTITY *)lookup(&dtd->generalEntities, name, 0);
|
entity = (ENTITY *)lookup(parser, &dtd->generalEntities, name, 0);
|
||||||
poolDiscard(&dtd->pool);
|
poolDiscard(&dtd->pool);
|
||||||
/* First, determine if a check for an existing declaration is needed;
|
/* First, determine if a check for an existing declaration is needed;
|
||||||
if yes, check that the entity exists, and that it is internal,
|
if yes, check that the entity exists, and that it is internal,
|
||||||
|
@ -2618,12 +2671,12 @@ storeAtts(XML_Parser parser, const ENCODING *enc,
|
||||||
const XML_Char *localPart;
|
const XML_Char *localPart;
|
||||||
|
|
||||||
/* lookup the element type name */
|
/* lookup the element type name */
|
||||||
elementType = (ELEMENT_TYPE *)lookup(&dtd->elementTypes, tagNamePtr->str,0);
|
elementType = (ELEMENT_TYPE *)lookup(parser, &dtd->elementTypes, tagNamePtr->str,0);
|
||||||
if (!elementType) {
|
if (!elementType) {
|
||||||
const XML_Char *name = poolCopyString(&dtd->pool, tagNamePtr->str);
|
const XML_Char *name = poolCopyString(&dtd->pool, tagNamePtr->str);
|
||||||
if (!name)
|
if (!name)
|
||||||
return XML_ERROR_NO_MEMORY;
|
return XML_ERROR_NO_MEMORY;
|
||||||
elementType = (ELEMENT_TYPE *)lookup(&dtd->elementTypes, name,
|
elementType = (ELEMENT_TYPE *)lookup(parser, &dtd->elementTypes, name,
|
||||||
sizeof(ELEMENT_TYPE));
|
sizeof(ELEMENT_TYPE));
|
||||||
if (!elementType)
|
if (!elementType)
|
||||||
return XML_ERROR_NO_MEMORY;
|
return XML_ERROR_NO_MEMORY;
|
||||||
|
@ -2792,9 +2845,9 @@ storeAtts(XML_Parser parser, const ENCODING *enc,
|
||||||
if (s[-1] == 2) { /* prefixed */
|
if (s[-1] == 2) { /* prefixed */
|
||||||
ATTRIBUTE_ID *id;
|
ATTRIBUTE_ID *id;
|
||||||
const BINDING *b;
|
const BINDING *b;
|
||||||
unsigned long uriHash = 0;
|
unsigned long uriHash = hash_secret_salt;
|
||||||
((XML_Char *)s)[-1] = 0; /* clear flag */
|
((XML_Char *)s)[-1] = 0; /* clear flag */
|
||||||
id = (ATTRIBUTE_ID *)lookup(&dtd->attributeIds, s, 0);
|
id = (ATTRIBUTE_ID *)lookup(parser, &dtd->attributeIds, s, 0);
|
||||||
if (!id)
|
if (!id)
|
||||||
return XML_ERROR_NO_MEMORY;
|
return XML_ERROR_NO_MEMORY;
|
||||||
b = id->prefix->binding;
|
b = id->prefix->binding;
|
||||||
|
@ -2818,7 +2871,7 @@ storeAtts(XML_Parser parser, const ENCODING *enc,
|
||||||
} while (*s++);
|
} while (*s++);
|
||||||
|
|
||||||
{ /* Check hash table for duplicate of expanded name (uriName).
|
{ /* Check hash table for duplicate of expanded name (uriName).
|
||||||
Derived from code in lookup(HASH_TABLE *table, ...).
|
Derived from code in lookup(parser, HASH_TABLE *table, ...).
|
||||||
*/
|
*/
|
||||||
unsigned char step = 0;
|
unsigned char step = 0;
|
||||||
unsigned long mask = nsAttsSize - 1;
|
unsigned long mask = nsAttsSize - 1;
|
||||||
|
@ -3756,7 +3809,8 @@ doProlog(XML_Parser parser,
|
||||||
case XML_ROLE_DOCTYPE_PUBLIC_ID:
|
case XML_ROLE_DOCTYPE_PUBLIC_ID:
|
||||||
#ifdef XML_DTD
|
#ifdef XML_DTD
|
||||||
useForeignDTD = XML_FALSE;
|
useForeignDTD = XML_FALSE;
|
||||||
declEntity = (ENTITY *)lookup(&dtd->paramEntities,
|
declEntity = (ENTITY *)lookup(parser,
|
||||||
|
&dtd->paramEntities,
|
||||||
externalSubsetName,
|
externalSubsetName,
|
||||||
sizeof(ENTITY));
|
sizeof(ENTITY));
|
||||||
if (!declEntity)
|
if (!declEntity)
|
||||||
|
@ -3811,7 +3865,8 @@ doProlog(XML_Parser parser,
|
||||||
XML_Bool hadParamEntityRefs = dtd->hasParamEntityRefs;
|
XML_Bool hadParamEntityRefs = dtd->hasParamEntityRefs;
|
||||||
dtd->hasParamEntityRefs = XML_TRUE;
|
dtd->hasParamEntityRefs = XML_TRUE;
|
||||||
if (paramEntityParsing && externalEntityRefHandler) {
|
if (paramEntityParsing && externalEntityRefHandler) {
|
||||||
ENTITY *entity = (ENTITY *)lookup(&dtd->paramEntities,
|
ENTITY *entity = (ENTITY *)lookup(parser,
|
||||||
|
&dtd->paramEntities,
|
||||||
externalSubsetName,
|
externalSubsetName,
|
||||||
sizeof(ENTITY));
|
sizeof(ENTITY));
|
||||||
if (!entity)
|
if (!entity)
|
||||||
|
@ -3855,7 +3910,7 @@ doProlog(XML_Parser parser,
|
||||||
XML_Bool hadParamEntityRefs = dtd->hasParamEntityRefs;
|
XML_Bool hadParamEntityRefs = dtd->hasParamEntityRefs;
|
||||||
dtd->hasParamEntityRefs = XML_TRUE;
|
dtd->hasParamEntityRefs = XML_TRUE;
|
||||||
if (paramEntityParsing && externalEntityRefHandler) {
|
if (paramEntityParsing && externalEntityRefHandler) {
|
||||||
ENTITY *entity = (ENTITY *)lookup(&dtd->paramEntities,
|
ENTITY *entity = (ENTITY *)lookup(parser, &dtd->paramEntities,
|
||||||
externalSubsetName,
|
externalSubsetName,
|
||||||
sizeof(ENTITY));
|
sizeof(ENTITY));
|
||||||
if (!entity)
|
if (!entity)
|
||||||
|
@ -4069,7 +4124,8 @@ doProlog(XML_Parser parser,
|
||||||
break;
|
break;
|
||||||
#else /* XML_DTD */
|
#else /* XML_DTD */
|
||||||
if (!declEntity) {
|
if (!declEntity) {
|
||||||
declEntity = (ENTITY *)lookup(&dtd->paramEntities,
|
declEntity = (ENTITY *)lookup(parser,
|
||||||
|
&dtd->paramEntities,
|
||||||
externalSubsetName,
|
externalSubsetName,
|
||||||
sizeof(ENTITY));
|
sizeof(ENTITY));
|
||||||
if (!declEntity)
|
if (!declEntity)
|
||||||
|
@ -4144,7 +4200,7 @@ doProlog(XML_Parser parser,
|
||||||
const XML_Char *name = poolStoreString(&dtd->pool, enc, s, next);
|
const XML_Char *name = poolStoreString(&dtd->pool, enc, s, next);
|
||||||
if (!name)
|
if (!name)
|
||||||
return XML_ERROR_NO_MEMORY;
|
return XML_ERROR_NO_MEMORY;
|
||||||
declEntity = (ENTITY *)lookup(&dtd->generalEntities, name,
|
declEntity = (ENTITY *)lookup(parser, &dtd->generalEntities, name,
|
||||||
sizeof(ENTITY));
|
sizeof(ENTITY));
|
||||||
if (!declEntity)
|
if (!declEntity)
|
||||||
return XML_ERROR_NO_MEMORY;
|
return XML_ERROR_NO_MEMORY;
|
||||||
|
@ -4176,7 +4232,7 @@ doProlog(XML_Parser parser,
|
||||||
const XML_Char *name = poolStoreString(&dtd->pool, enc, s, next);
|
const XML_Char *name = poolStoreString(&dtd->pool, enc, s, next);
|
||||||
if (!name)
|
if (!name)
|
||||||
return XML_ERROR_NO_MEMORY;
|
return XML_ERROR_NO_MEMORY;
|
||||||
declEntity = (ENTITY *)lookup(&dtd->paramEntities,
|
declEntity = (ENTITY *)lookup(parser, &dtd->paramEntities,
|
||||||
name, sizeof(ENTITY));
|
name, sizeof(ENTITY));
|
||||||
if (!declEntity)
|
if (!declEntity)
|
||||||
return XML_ERROR_NO_MEMORY;
|
return XML_ERROR_NO_MEMORY;
|
||||||
|
@ -4358,7 +4414,7 @@ doProlog(XML_Parser parser,
|
||||||
next - enc->minBytesPerChar);
|
next - enc->minBytesPerChar);
|
||||||
if (!name)
|
if (!name)
|
||||||
return XML_ERROR_NO_MEMORY;
|
return XML_ERROR_NO_MEMORY;
|
||||||
entity = (ENTITY *)lookup(&dtd->paramEntities, name, 0);
|
entity = (ENTITY *)lookup(parser, &dtd->paramEntities, name, 0);
|
||||||
poolDiscard(&dtd->pool);
|
poolDiscard(&dtd->pool);
|
||||||
/* first, determine if a check for an existing declaration is needed;
|
/* first, determine if a check for an existing declaration is needed;
|
||||||
if yes, check that the entity exists, and that it is internal,
|
if yes, check that the entity exists, and that it is internal,
|
||||||
|
@ -4882,7 +4938,7 @@ appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
|
||||||
next - enc->minBytesPerChar);
|
next - enc->minBytesPerChar);
|
||||||
if (!name)
|
if (!name)
|
||||||
return XML_ERROR_NO_MEMORY;
|
return XML_ERROR_NO_MEMORY;
|
||||||
entity = (ENTITY *)lookup(&dtd->generalEntities, name, 0);
|
entity = (ENTITY *)lookup(parser, &dtd->generalEntities, name, 0);
|
||||||
poolDiscard(&temp2Pool);
|
poolDiscard(&temp2Pool);
|
||||||
/* First, determine if a check for an existing declaration is needed;
|
/* First, determine if a check for an existing declaration is needed;
|
||||||
if yes, check that the entity exists, and that it is internal.
|
if yes, check that the entity exists, and that it is internal.
|
||||||
|
@ -4991,7 +5047,7 @@ storeEntityValue(XML_Parser parser,
|
||||||
result = XML_ERROR_NO_MEMORY;
|
result = XML_ERROR_NO_MEMORY;
|
||||||
goto endEntityValue;
|
goto endEntityValue;
|
||||||
}
|
}
|
||||||
entity = (ENTITY *)lookup(&dtd->paramEntities, name, 0);
|
entity = (ENTITY *)lookup(parser, &dtd->paramEntities, name, 0);
|
||||||
poolDiscard(&tempPool);
|
poolDiscard(&tempPool);
|
||||||
if (!entity) {
|
if (!entity) {
|
||||||
/* not a well-formedness error - see XML 1.0: WFC Entity Declared */
|
/* not a well-formedness error - see XML 1.0: WFC Entity Declared */
|
||||||
|
@ -5281,7 +5337,7 @@ setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *elementType)
|
||||||
}
|
}
|
||||||
if (!poolAppendChar(&dtd->pool, XML_T('\0')))
|
if (!poolAppendChar(&dtd->pool, XML_T('\0')))
|
||||||
return 0;
|
return 0;
|
||||||
prefix = (PREFIX *)lookup(&dtd->prefixes, poolStart(&dtd->pool),
|
prefix = (PREFIX *)lookup(parser, &dtd->prefixes, poolStart(&dtd->pool),
|
||||||
sizeof(PREFIX));
|
sizeof(PREFIX));
|
||||||
if (!prefix)
|
if (!prefix)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -5310,7 +5366,7 @@ getAttributeId(XML_Parser parser, const ENCODING *enc,
|
||||||
return NULL;
|
return NULL;
|
||||||
/* skip quotation mark - its storage will be re-used (like in name[-1]) */
|
/* skip quotation mark - its storage will be re-used (like in name[-1]) */
|
||||||
++name;
|
++name;
|
||||||
id = (ATTRIBUTE_ID *)lookup(&dtd->attributeIds, name, sizeof(ATTRIBUTE_ID));
|
id = (ATTRIBUTE_ID *)lookup(parser, &dtd->attributeIds, name, sizeof(ATTRIBUTE_ID));
|
||||||
if (!id)
|
if (!id)
|
||||||
return NULL;
|
return NULL;
|
||||||
if (id->name != name)
|
if (id->name != name)
|
||||||
|
@ -5328,7 +5384,7 @@ getAttributeId(XML_Parser parser, const ENCODING *enc,
|
||||||
if (name[5] == XML_T('\0'))
|
if (name[5] == XML_T('\0'))
|
||||||
id->prefix = &dtd->defaultPrefix;
|
id->prefix = &dtd->defaultPrefix;
|
||||||
else
|
else
|
||||||
id->prefix = (PREFIX *)lookup(&dtd->prefixes, name + 6, sizeof(PREFIX));
|
id->prefix = (PREFIX *)lookup(parser, &dtd->prefixes, name + 6, sizeof(PREFIX));
|
||||||
id->xmlns = XML_TRUE;
|
id->xmlns = XML_TRUE;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -5343,7 +5399,7 @@ getAttributeId(XML_Parser parser, const ENCODING *enc,
|
||||||
}
|
}
|
||||||
if (!poolAppendChar(&dtd->pool, XML_T('\0')))
|
if (!poolAppendChar(&dtd->pool, XML_T('\0')))
|
||||||
return NULL;
|
return NULL;
|
||||||
id->prefix = (PREFIX *)lookup(&dtd->prefixes, poolStart(&dtd->pool),
|
id->prefix = (PREFIX *)lookup(parser, &dtd->prefixes, poolStart(&dtd->pool),
|
||||||
sizeof(PREFIX));
|
sizeof(PREFIX));
|
||||||
if (!id->prefix)
|
if (!id->prefix)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -5441,7 +5497,7 @@ setContext(XML_Parser parser, const XML_Char *context)
|
||||||
ENTITY *e;
|
ENTITY *e;
|
||||||
if (!poolAppendChar(&tempPool, XML_T('\0')))
|
if (!poolAppendChar(&tempPool, XML_T('\0')))
|
||||||
return XML_FALSE;
|
return XML_FALSE;
|
||||||
e = (ENTITY *)lookup(&dtd->generalEntities, poolStart(&tempPool), 0);
|
e = (ENTITY *)lookup(parser, &dtd->generalEntities, poolStart(&tempPool), 0);
|
||||||
if (e)
|
if (e)
|
||||||
e->open = XML_TRUE;
|
e->open = XML_TRUE;
|
||||||
if (*s != XML_T('\0'))
|
if (*s != XML_T('\0'))
|
||||||
|
@ -5456,7 +5512,7 @@ setContext(XML_Parser parser, const XML_Char *context)
|
||||||
else {
|
else {
|
||||||
if (!poolAppendChar(&tempPool, XML_T('\0')))
|
if (!poolAppendChar(&tempPool, XML_T('\0')))
|
||||||
return XML_FALSE;
|
return XML_FALSE;
|
||||||
prefix = (PREFIX *)lookup(&dtd->prefixes, poolStart(&tempPool),
|
prefix = (PREFIX *)lookup(parser, &dtd->prefixes, poolStart(&tempPool),
|
||||||
sizeof(PREFIX));
|
sizeof(PREFIX));
|
||||||
if (!prefix)
|
if (!prefix)
|
||||||
return XML_FALSE;
|
return XML_FALSE;
|
||||||
|
@ -5620,7 +5676,7 @@ dtdDestroy(DTD *p, XML_Bool isDocEntity, const XML_Memory_Handling_Suite *ms)
|
||||||
The new DTD has already been initialized.
|
The new DTD has already been initialized.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
dtdCopy(DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms)
|
dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms)
|
||||||
{
|
{
|
||||||
HASH_TABLE_ITER iter;
|
HASH_TABLE_ITER iter;
|
||||||
|
|
||||||
|
@ -5635,7 +5691,7 @@ dtdCopy(DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms)
|
||||||
name = poolCopyString(&(newDtd->pool), oldP->name);
|
name = poolCopyString(&(newDtd->pool), oldP->name);
|
||||||
if (!name)
|
if (!name)
|
||||||
return 0;
|
return 0;
|
||||||
if (!lookup(&(newDtd->prefixes), name, sizeof(PREFIX)))
|
if (!lookup(oldParser, &(newDtd->prefixes), name, sizeof(PREFIX)))
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5657,7 +5713,7 @@ dtdCopy(DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms)
|
||||||
if (!name)
|
if (!name)
|
||||||
return 0;
|
return 0;
|
||||||
++name;
|
++name;
|
||||||
newA = (ATTRIBUTE_ID *)lookup(&(newDtd->attributeIds), name,
|
newA = (ATTRIBUTE_ID *)lookup(oldParser, &(newDtd->attributeIds), name,
|
||||||
sizeof(ATTRIBUTE_ID));
|
sizeof(ATTRIBUTE_ID));
|
||||||
if (!newA)
|
if (!newA)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -5667,7 +5723,7 @@ dtdCopy(DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms)
|
||||||
if (oldA->prefix == &oldDtd->defaultPrefix)
|
if (oldA->prefix == &oldDtd->defaultPrefix)
|
||||||
newA->prefix = &newDtd->defaultPrefix;
|
newA->prefix = &newDtd->defaultPrefix;
|
||||||
else
|
else
|
||||||
newA->prefix = (PREFIX *)lookup(&(newDtd->prefixes),
|
newA->prefix = (PREFIX *)lookup(oldParser, &(newDtd->prefixes),
|
||||||
oldA->prefix->name, 0);
|
oldA->prefix->name, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5686,7 +5742,7 @@ dtdCopy(DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms)
|
||||||
name = poolCopyString(&(newDtd->pool), oldE->name);
|
name = poolCopyString(&(newDtd->pool), oldE->name);
|
||||||
if (!name)
|
if (!name)
|
||||||
return 0;
|
return 0;
|
||||||
newE = (ELEMENT_TYPE *)lookup(&(newDtd->elementTypes), name,
|
newE = (ELEMENT_TYPE *)lookup(oldParser, &(newDtd->elementTypes), name,
|
||||||
sizeof(ELEMENT_TYPE));
|
sizeof(ELEMENT_TYPE));
|
||||||
if (!newE)
|
if (!newE)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -5700,14 +5756,14 @@ dtdCopy(DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms)
|
||||||
}
|
}
|
||||||
if (oldE->idAtt)
|
if (oldE->idAtt)
|
||||||
newE->idAtt = (ATTRIBUTE_ID *)
|
newE->idAtt = (ATTRIBUTE_ID *)
|
||||||
lookup(&(newDtd->attributeIds), oldE->idAtt->name, 0);
|
lookup(oldParser, &(newDtd->attributeIds), oldE->idAtt->name, 0);
|
||||||
newE->allocDefaultAtts = newE->nDefaultAtts = oldE->nDefaultAtts;
|
newE->allocDefaultAtts = newE->nDefaultAtts = oldE->nDefaultAtts;
|
||||||
if (oldE->prefix)
|
if (oldE->prefix)
|
||||||
newE->prefix = (PREFIX *)lookup(&(newDtd->prefixes),
|
newE->prefix = (PREFIX *)lookup(oldParser, &(newDtd->prefixes),
|
||||||
oldE->prefix->name, 0);
|
oldE->prefix->name, 0);
|
||||||
for (i = 0; i < newE->nDefaultAtts; i++) {
|
for (i = 0; i < newE->nDefaultAtts; i++) {
|
||||||
newE->defaultAtts[i].id = (ATTRIBUTE_ID *)
|
newE->defaultAtts[i].id = (ATTRIBUTE_ID *)
|
||||||
lookup(&(newDtd->attributeIds), oldE->defaultAtts[i].id->name, 0);
|
lookup(oldParser, &(newDtd->attributeIds), oldE->defaultAtts[i].id->name, 0);
|
||||||
newE->defaultAtts[i].isCdata = oldE->defaultAtts[i].isCdata;
|
newE->defaultAtts[i].isCdata = oldE->defaultAtts[i].isCdata;
|
||||||
if (oldE->defaultAtts[i].value) {
|
if (oldE->defaultAtts[i].value) {
|
||||||
newE->defaultAtts[i].value
|
newE->defaultAtts[i].value
|
||||||
|
@ -5721,13 +5777,15 @@ dtdCopy(DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Copy the entity tables. */
|
/* Copy the entity tables. */
|
||||||
if (!copyEntityTable(&(newDtd->generalEntities),
|
if (!copyEntityTable(oldParser,
|
||||||
|
&(newDtd->generalEntities),
|
||||||
&(newDtd->pool),
|
&(newDtd->pool),
|
||||||
&(oldDtd->generalEntities)))
|
&(oldDtd->generalEntities)))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
#ifdef XML_DTD
|
#ifdef XML_DTD
|
||||||
if (!copyEntityTable(&(newDtd->paramEntities),
|
if (!copyEntityTable(oldParser,
|
||||||
|
&(newDtd->paramEntities),
|
||||||
&(newDtd->pool),
|
&(newDtd->pool),
|
||||||
&(oldDtd->paramEntities)))
|
&(oldDtd->paramEntities)))
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -5750,7 +5808,8 @@ dtdCopy(DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms)
|
||||||
} /* End dtdCopy */
|
} /* End dtdCopy */
|
||||||
|
|
||||||
static int
|
static int
|
||||||
copyEntityTable(HASH_TABLE *newTable,
|
copyEntityTable(XML_Parser oldParser,
|
||||||
|
HASH_TABLE *newTable,
|
||||||
STRING_POOL *newPool,
|
STRING_POOL *newPool,
|
||||||
const HASH_TABLE *oldTable)
|
const HASH_TABLE *oldTable)
|
||||||
{
|
{
|
||||||
|
@ -5769,7 +5828,7 @@ copyEntityTable(HASH_TABLE *newTable,
|
||||||
name = poolCopyString(newPool, oldE->name);
|
name = poolCopyString(newPool, oldE->name);
|
||||||
if (!name)
|
if (!name)
|
||||||
return 0;
|
return 0;
|
||||||
newE = (ENTITY *)lookup(newTable, name, sizeof(ENTITY));
|
newE = (ENTITY *)lookup(oldParser, newTable, name, sizeof(ENTITY));
|
||||||
if (!newE)
|
if (!newE)
|
||||||
return 0;
|
return 0;
|
||||||
if (oldE->systemId) {
|
if (oldE->systemId) {
|
||||||
|
@ -5827,16 +5886,16 @@ keyeq(KEY s1, KEY s2)
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned long FASTCALL
|
static unsigned long FASTCALL
|
||||||
hash(KEY s)
|
hash(XML_Parser parser, KEY s)
|
||||||
{
|
{
|
||||||
unsigned long h = 0;
|
unsigned long h = hash_secret_salt;
|
||||||
while (*s)
|
while (*s)
|
||||||
h = CHAR_HASH(h, *s++);
|
h = CHAR_HASH(h, *s++);
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
static NAMED *
|
static NAMED *
|
||||||
lookup(HASH_TABLE *table, KEY name, size_t createSize)
|
lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize)
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
if (table->size == 0) {
|
if (table->size == 0) {
|
||||||
|
@ -5853,10 +5912,10 @@ lookup(HASH_TABLE *table, KEY name, size_t createSize)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
memset(table->v, 0, tsize);
|
memset(table->v, 0, tsize);
|
||||||
i = hash(name) & ((unsigned long)table->size - 1);
|
i = hash(parser, name) & ((unsigned long)table->size - 1);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
unsigned long h = hash(name);
|
unsigned long h = hash(parser, name);
|
||||||
unsigned long mask = (unsigned long)table->size - 1;
|
unsigned long mask = (unsigned long)table->size - 1;
|
||||||
unsigned char step = 0;
|
unsigned char step = 0;
|
||||||
i = h & mask;
|
i = h & mask;
|
||||||
|
@ -5882,7 +5941,7 @@ lookup(HASH_TABLE *table, KEY name, size_t createSize)
|
||||||
memset(newV, 0, tsize);
|
memset(newV, 0, tsize);
|
||||||
for (i = 0; i < table->size; i++)
|
for (i = 0; i < table->size; i++)
|
||||||
if (table->v[i]) {
|
if (table->v[i]) {
|
||||||
unsigned long newHash = hash(table->v[i]->name);
|
unsigned long newHash = hash(parser, table->v[i]->name);
|
||||||
size_t j = newHash & newMask;
|
size_t j = newHash & newMask;
|
||||||
step = 0;
|
step = 0;
|
||||||
while (newV[j]) {
|
while (newV[j]) {
|
||||||
|
@ -6257,7 +6316,7 @@ getElementType(XML_Parser parser,
|
||||||
|
|
||||||
if (!name)
|
if (!name)
|
||||||
return NULL;
|
return NULL;
|
||||||
ret = (ELEMENT_TYPE *) lookup(&dtd->elementTypes, name, sizeof(ELEMENT_TYPE));
|
ret = (ELEMENT_TYPE *) lookup(parser, &dtd->elementTypes, name, sizeof(ELEMENT_TYPE));
|
||||||
if (!ret)
|
if (!ret)
|
||||||
return NULL;
|
return NULL;
|
||||||
if (ret->name != name)
|
if (ret->name != name)
|
||||||
|
|
|
@ -1245,6 +1245,8 @@ newxmlparseobject(char *encoding, char *namespace_separator, PyObject *intern)
|
||||||
else {
|
else {
|
||||||
self->itself = XML_ParserCreate(encoding);
|
self->itself = XML_ParserCreate(encoding);
|
||||||
}
|
}
|
||||||
|
XML_SetHashSalt(self->itself,
|
||||||
|
(unsigned long)_Py_HashSecret.prefix);
|
||||||
self->intern = intern;
|
self->intern = intern;
|
||||||
Py_XINCREF(self->intern);
|
Py_XINCREF(self->intern);
|
||||||
#ifdef Py_TPFLAGS_HAVE_GC
|
#ifdef Py_TPFLAGS_HAVE_GC
|
||||||
|
|
Loading…
Reference in New Issue