mirror of
https://gitlab.gnome.org/GNOME/libxml2.git
synced 2025-07-20 16:43:05 +03:00
integrated the Out Of Memory test from Havoc Pennington #109368 a lot of
* Makefile.am testOOM.c testOOMlib.[ch] : integrated the Out Of Memory test from Havoc Pennington #109368 * SAX.c parser.c parserInternals.c tree.c uri.c valid.c xmlmemory.c xmlreader.c xmlregexp.c include/libxml/tree.h include/libxml/parser.h: a lot of memory allocation cleanups based on the results of the OOM testing * check-relaxng-test-suite2.py: seems I forgot to commit the script. Daniel
This commit is contained in:
165
xmlregexp.c
165
xmlregexp.c
@ -332,23 +332,19 @@ xmlRegEpxFromParse(xmlRegParserCtxtPtr ctxt) {
|
||||
xmlRegexpPtr ret;
|
||||
|
||||
ret = (xmlRegexpPtr) xmlMalloc(sizeof(xmlRegexp));
|
||||
if (ret == NULL)
|
||||
if (ret == NULL) {
|
||||
xmlGenericError(xmlGenericErrorContext,
|
||||
"out of memory compiling regexp\n");
|
||||
return(NULL);
|
||||
}
|
||||
memset(ret, 0, sizeof(xmlRegexp));
|
||||
ret->string = ctxt->string;
|
||||
ctxt->string = NULL;
|
||||
ret->nbStates = ctxt->nbStates;
|
||||
ctxt->nbStates = 0;
|
||||
ret->states = ctxt->states;
|
||||
ctxt->states = NULL;
|
||||
ret->nbAtoms = ctxt->nbAtoms;
|
||||
ctxt->nbAtoms = 0;
|
||||
ret->atoms = ctxt->atoms;
|
||||
ctxt->atoms = NULL;
|
||||
ret->nbCounters = ctxt->nbCounters;
|
||||
ctxt->nbCounters = 0;
|
||||
ret->counters = ctxt->counters;
|
||||
ctxt->counters = NULL;
|
||||
ret->determinist = ctxt->determinist;
|
||||
|
||||
if ((ret->determinist != 0) &&
|
||||
@ -373,6 +369,12 @@ xmlRegEpxFromParse(xmlRegParserCtxtPtr ctxt) {
|
||||
*/
|
||||
|
||||
stateRemap = xmlMalloc(ret->nbStates * sizeof(int));
|
||||
if (stateRemap == NULL) {
|
||||
xmlGenericError(xmlGenericErrorContext,
|
||||
"out of memory compiling regexp\n");
|
||||
xmlFree(ret);
|
||||
return(NULL);
|
||||
}
|
||||
for (i = 0;i < ret->nbStates;i++) {
|
||||
if (ret->states[i] != NULL) {
|
||||
stateRemap[i] = nbstates;
|
||||
@ -385,7 +387,22 @@ xmlRegEpxFromParse(xmlRegParserCtxtPtr ctxt) {
|
||||
printf("Final: %d states\n", nbstates);
|
||||
#endif
|
||||
stringMap = xmlMalloc(ret->nbAtoms * sizeof(char *));
|
||||
if (stringMap == NULL) {
|
||||
xmlGenericError(xmlGenericErrorContext,
|
||||
"out of memory compiling regexp\n");
|
||||
xmlFree(stateRemap);
|
||||
xmlFree(ret);
|
||||
return(NULL);
|
||||
}
|
||||
stringRemap = xmlMalloc(ret->nbAtoms * sizeof(int));
|
||||
if (stringRemap == NULL) {
|
||||
xmlGenericError(xmlGenericErrorContext,
|
||||
"out of memory compiling regexp\n");
|
||||
xmlFree(stringMap);
|
||||
xmlFree(stateRemap);
|
||||
xmlFree(ret);
|
||||
return(NULL);
|
||||
}
|
||||
for (i = 0;i < ret->nbAtoms;i++) {
|
||||
if ((ret->atoms[i]->type == XML_REGEXP_STRING) &&
|
||||
(ret->atoms[i]->quant == XML_REGEXP_QUANT_ONCE)) {
|
||||
@ -399,6 +416,15 @@ xmlRegEpxFromParse(xmlRegParserCtxtPtr ctxt) {
|
||||
if (j >= nbatoms) {
|
||||
stringRemap[i] = nbatoms;
|
||||
stringMap[nbatoms] = xmlStrdup(value);
|
||||
if (stringMap[nbatoms] == NULL) {
|
||||
for (i = 0;i < nbatoms;i++)
|
||||
xmlFree(stringMap[i]);
|
||||
xmlFree(stringRemap);
|
||||
xmlFree(stringMap);
|
||||
xmlFree(stateRemap);
|
||||
xmlFree(ret);
|
||||
return(NULL);
|
||||
}
|
||||
nbatoms++;
|
||||
}
|
||||
} else {
|
||||
@ -407,20 +433,29 @@ xmlRegEpxFromParse(xmlRegParserCtxtPtr ctxt) {
|
||||
for (i = 0;i < nbatoms;i++)
|
||||
xmlFree(stringMap[i]);
|
||||
xmlFree(stringMap);
|
||||
goto fail_compact;
|
||||
xmlFree(ret);
|
||||
return(NULL);
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG_COMPACTION
|
||||
printf("Final: %d atoms\n", nbatoms);
|
||||
#endif
|
||||
transitions = (int *) xmlMalloc((nbstates + 1) *
|
||||
(nbatoms + 1) * sizeof(int));
|
||||
if (transitions == NULL) {
|
||||
xmlFree(stateRemap);
|
||||
xmlFree(stringRemap);
|
||||
xmlFree(stringMap);
|
||||
xmlFree(ret);
|
||||
return(NULL);
|
||||
}
|
||||
memset(transitions, 0, (nbstates + 1) * (nbatoms + 1) * sizeof(int));
|
||||
|
||||
/*
|
||||
* Allocate the transition table. The first entry for each
|
||||
* state correspond to the state type.
|
||||
*/
|
||||
transitions = (int *) xmlMalloc(nbstates * (nbatoms + 1) * sizeof(int));
|
||||
transdata = NULL;
|
||||
memset(transitions, 0, nbstates * (nbatoms + 1) * sizeof(int));
|
||||
|
||||
for (i = 0;i < ret->nbStates;i++) {
|
||||
int stateno, atomno, targetno, prev;
|
||||
@ -445,6 +480,11 @@ xmlRegEpxFromParse(xmlRegParserCtxtPtr ctxt) {
|
||||
if (transdata != NULL)
|
||||
memset(transdata, 0,
|
||||
nbstates * nbatoms * sizeof(void *));
|
||||
else {
|
||||
xmlGenericError(xmlGenericErrorContext,
|
||||
"out of memory compiling regexp\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
targetno = stateRemap[trans->to];
|
||||
/*
|
||||
@ -470,7 +510,7 @@ xmlRegEpxFromParse(xmlRegParserCtxtPtr ctxt) {
|
||||
for (i = 0;i < nbatoms;i++)
|
||||
xmlFree(stringMap[i]);
|
||||
xmlFree(stringMap);
|
||||
goto fail_compact;
|
||||
goto not_determ;
|
||||
}
|
||||
} else {
|
||||
#if 0
|
||||
@ -524,7 +564,14 @@ xmlRegEpxFromParse(xmlRegParserCtxtPtr ctxt) {
|
||||
xmlFree(stateRemap);
|
||||
xmlFree(stringRemap);
|
||||
}
|
||||
fail_compact:
|
||||
not_determ:
|
||||
ctxt->string = NULL;
|
||||
ctxt->nbStates = 0;
|
||||
ctxt->states = NULL;
|
||||
ctxt->nbAtoms = 0;
|
||||
ctxt->atoms = NULL;
|
||||
ctxt->nbCounters = 0;
|
||||
ctxt->counters = NULL;
|
||||
return(ret);
|
||||
}
|
||||
|
||||
@ -1048,11 +1095,11 @@ xmlRegGetCounter(xmlRegParserCtxtPtr ctxt) {
|
||||
return(ctxt->nbCounters++);
|
||||
}
|
||||
|
||||
static void
|
||||
static int
|
||||
xmlRegAtomPush(xmlRegParserCtxtPtr ctxt, xmlRegAtomPtr atom) {
|
||||
if (atom == NULL) {
|
||||
ERROR("atom push: atom is NULL");
|
||||
return;
|
||||
return(-1);
|
||||
}
|
||||
if (ctxt->maxAtoms == 0) {
|
||||
ctxt->maxAtoms = 4;
|
||||
@ -1061,7 +1108,7 @@ xmlRegAtomPush(xmlRegParserCtxtPtr ctxt, xmlRegAtomPtr atom) {
|
||||
if (ctxt->atoms == NULL) {
|
||||
ERROR("atom push: allocation failed");
|
||||
ctxt->maxAtoms = 0;
|
||||
return;
|
||||
return(-1);
|
||||
}
|
||||
} else if (ctxt->nbAtoms >= ctxt->maxAtoms) {
|
||||
xmlRegAtomPtr *tmp;
|
||||
@ -1071,12 +1118,13 @@ xmlRegAtomPush(xmlRegParserCtxtPtr ctxt, xmlRegAtomPtr atom) {
|
||||
if (tmp == NULL) {
|
||||
ERROR("atom push: allocation failed");
|
||||
ctxt->maxAtoms /= 2;
|
||||
return;
|
||||
return(-1);
|
||||
}
|
||||
ctxt->atoms = tmp;
|
||||
}
|
||||
atom->no = ctxt->nbAtoms;
|
||||
ctxt->atoms[ctxt->nbAtoms++] = atom;
|
||||
return(0);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1132,8 +1180,9 @@ xmlRegStateAddTrans(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr state,
|
||||
state->nbTrans++;
|
||||
}
|
||||
|
||||
static void
|
||||
static int
|
||||
xmlRegStatePush(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr state) {
|
||||
if (state == NULL) return(-1);
|
||||
if (ctxt->maxStates == 0) {
|
||||
ctxt->maxStates = 4;
|
||||
ctxt->states = (xmlRegStatePtr *) xmlMalloc(ctxt->maxStates *
|
||||
@ -1141,7 +1190,7 @@ xmlRegStatePush(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr state) {
|
||||
if (ctxt->states == NULL) {
|
||||
ERROR("add range: allocation failed");
|
||||
ctxt->maxStates = 0;
|
||||
return;
|
||||
return(-1);
|
||||
}
|
||||
} else if (ctxt->nbStates >= ctxt->maxStates) {
|
||||
xmlRegStatePtr *tmp;
|
||||
@ -1151,12 +1200,13 @@ xmlRegStatePush(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr state) {
|
||||
if (tmp == NULL) {
|
||||
ERROR("add range: allocation failed");
|
||||
ctxt->maxStates /= 2;
|
||||
return;
|
||||
return(-1);
|
||||
}
|
||||
ctxt->states = tmp;
|
||||
}
|
||||
state->no = ctxt->nbStates;
|
||||
ctxt->states[ctxt->nbStates++] = state;
|
||||
return(0);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1245,20 +1295,23 @@ xmlFAGenerateCountedTransition(xmlRegParserCtxtPtr ctxt,
|
||||
* @to: the target state or NULL for building a new one
|
||||
* @atom: the atom generating the transition
|
||||
*
|
||||
* Returns 0 if succes and -1 in case of error.
|
||||
*/
|
||||
static void
|
||||
static int
|
||||
xmlFAGenerateTransitions(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr from,
|
||||
xmlRegStatePtr to, xmlRegAtomPtr atom) {
|
||||
if (atom == NULL) {
|
||||
ERROR("genrate transition: atom == NULL");
|
||||
return;
|
||||
return(-1);
|
||||
}
|
||||
if (atom->type == XML_REGEXP_SUBREG) {
|
||||
/*
|
||||
* this is a subexpression handling one should not need to
|
||||
* create a new node excep for XML_REGEXP_QUANT_RANGE.
|
||||
*/
|
||||
xmlRegAtomPush(ctxt, atom);
|
||||
if (xmlRegAtomPush(ctxt, atom) < 0) {
|
||||
return(-1);
|
||||
}
|
||||
if ((to != NULL) && (atom->stop != to) &&
|
||||
(atom->quant != XML_REGEXP_QUANT_RANGE)) {
|
||||
/*
|
||||
@ -1314,14 +1367,20 @@ xmlFAGenerateTransitions(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr from,
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return;
|
||||
return(0);
|
||||
} else {
|
||||
if (to == NULL) {
|
||||
to = xmlRegNewState(ctxt);
|
||||
xmlRegStatePush(ctxt, to);
|
||||
if (to != NULL)
|
||||
xmlRegStatePush(ctxt, to);
|
||||
else {
|
||||
return(-1);
|
||||
}
|
||||
}
|
||||
if (xmlRegAtomPush(ctxt, atom) < 0) {
|
||||
return(-1);
|
||||
}
|
||||
xmlRegStateAddTrans(ctxt, from, atom, to, -1, -1);
|
||||
xmlRegAtomPush(ctxt, atom);
|
||||
ctxt->state = to;
|
||||
}
|
||||
switch (atom->quant) {
|
||||
@ -1341,6 +1400,7 @@ xmlFAGenerateTransitions(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr from,
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1433,6 +1493,9 @@ xmlFAEliminateEpsilonTransitions(xmlRegParserCtxtPtr ctxt) {
|
||||
int statenr, transnr;
|
||||
xmlRegStatePtr state;
|
||||
|
||||
if (ctxt->states == NULL) return;
|
||||
|
||||
|
||||
/*
|
||||
* build the completed transitions bypassing the epsilons
|
||||
* Use a marking algorithm to avoid loops
|
||||
@ -2276,6 +2339,8 @@ xmlRegNewExecCtxt(xmlRegexpPtr comp, xmlRegExecCallbacks callback, void *data) {
|
||||
|
||||
if (comp == NULL)
|
||||
return(NULL);
|
||||
if ((comp->compact == NULL) && (comp->states == NULL))
|
||||
return(NULL);
|
||||
exec = (xmlRegExecCtxtPtr) xmlMalloc(sizeof(xmlRegExecCtxt));
|
||||
if (exec == NULL) {
|
||||
return(NULL);
|
||||
@ -3568,6 +3633,8 @@ xmlFAParseCharClass(xmlRegParserCtxtPtr ctxt) {
|
||||
* @ctxt: a regexp parser context
|
||||
*
|
||||
* [8] QuantExact ::= [0-9]+
|
||||
*
|
||||
* Returns 0 if success or -1 in case of error
|
||||
*/
|
||||
static int
|
||||
xmlFAParseQuantExact(xmlRegParserCtxtPtr ctxt) {
|
||||
@ -3723,8 +3790,9 @@ xmlFAParsePiece(xmlRegParserCtxtPtr ctxt) {
|
||||
* @first: is taht the first
|
||||
*
|
||||
* [2] branch ::= piece*
|
||||
8
|
||||
*/
|
||||
static void
|
||||
static int
|
||||
xmlFAParseBranch(xmlRegParserCtxtPtr ctxt, int first) {
|
||||
xmlRegStatePtr previous;
|
||||
xmlRegAtomPtr prevatom = NULL;
|
||||
@ -3734,7 +3802,8 @@ xmlFAParseBranch(xmlRegParserCtxtPtr ctxt, int first) {
|
||||
ret = xmlFAParsePiece(ctxt);
|
||||
if (ret != 0) {
|
||||
if (first) {
|
||||
xmlFAGenerateTransitions(ctxt, previous, NULL, ctxt->atom);
|
||||
if (xmlFAGenerateTransitions(ctxt, previous, NULL, ctxt->atom) < 0)
|
||||
return(-1);
|
||||
previous = ctxt->state;
|
||||
} else {
|
||||
prevatom = ctxt->atom;
|
||||
@ -3745,9 +3814,13 @@ xmlFAParseBranch(xmlRegParserCtxtPtr ctxt, int first) {
|
||||
ret = xmlFAParsePiece(ctxt);
|
||||
if (ret != 0) {
|
||||
if (first) {
|
||||
xmlFAGenerateTransitions(ctxt, previous, NULL, ctxt->atom);
|
||||
if (xmlFAGenerateTransitions(ctxt, previous, NULL,
|
||||
ctxt->atom) < 0)
|
||||
return(-1);
|
||||
} else {
|
||||
xmlFAGenerateTransitions(ctxt, previous, NULL, prevatom);
|
||||
if (xmlFAGenerateTransitions(ctxt, previous, NULL,
|
||||
prevatom) < 0)
|
||||
return(-1);
|
||||
prevatom = ctxt->atom;
|
||||
}
|
||||
previous = ctxt->state;
|
||||
@ -3755,8 +3828,10 @@ xmlFAParseBranch(xmlRegParserCtxtPtr ctxt, int first) {
|
||||
}
|
||||
}
|
||||
if (!first) {
|
||||
xmlFAGenerateTransitions(ctxt, previous, ctxt->end, prevatom);
|
||||
if (xmlFAGenerateTransitions(ctxt, previous, ctxt->end, prevatom) < 0)
|
||||
return(-1);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -3994,7 +4069,15 @@ xmlNewAutomata(void) {
|
||||
/* initialize the parser */
|
||||
ctxt->end = NULL;
|
||||
ctxt->start = ctxt->state = xmlRegNewState(ctxt);
|
||||
xmlRegStatePush(ctxt, ctxt->start);
|
||||
if (ctxt->start == NULL) {
|
||||
xmlFreeAutomata(ctxt);
|
||||
return(NULL);
|
||||
}
|
||||
if (xmlRegStatePush(ctxt, ctxt->start) < 0) {
|
||||
xmlRegFreeState(ctxt->start);
|
||||
xmlFreeAutomata(ctxt);
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
return(ctxt);
|
||||
}
|
||||
@ -4067,12 +4150,17 @@ xmlAutomataNewTransition(xmlAutomataPtr am, xmlAutomataStatePtr from,
|
||||
if ((am == NULL) || (from == NULL) || (token == NULL))
|
||||
return(NULL);
|
||||
atom = xmlRegNewAtom(am, XML_REGEXP_STRING);
|
||||
if (atom == NULL)
|
||||
return(NULL);
|
||||
atom->data = data;
|
||||
if (atom == NULL)
|
||||
return(NULL);
|
||||
atom->valuep = xmlStrdup(token);
|
||||
|
||||
xmlFAGenerateTransitions(am, from, to, atom);
|
||||
if (xmlFAGenerateTransitions(am, from, to, atom) < 0) {
|
||||
xmlRegFreeAtom(atom);
|
||||
return(NULL);
|
||||
}
|
||||
if (to == NULL)
|
||||
return(am->state);
|
||||
return(to);
|
||||
@ -4127,7 +4215,10 @@ xmlAutomataNewTransition2(xmlAutomataPtr am, xmlAutomataStatePtr from,
|
||||
atom->valuep = str;
|
||||
}
|
||||
|
||||
xmlFAGenerateTransitions(am, from, to, atom);
|
||||
if (xmlFAGenerateTransitions(am, from, to, atom) < 0) {
|
||||
xmlRegFreeAtom(atom);
|
||||
return(NULL);
|
||||
}
|
||||
if (to == NULL)
|
||||
return(am->state);
|
||||
return(to);
|
||||
@ -4173,7 +4264,10 @@ xmlAutomataNewCountTrans(xmlAutomataPtr am, xmlAutomataStatePtr from,
|
||||
atom->min = min;
|
||||
atom->max = max;
|
||||
|
||||
xmlFAGenerateTransitions(am, from, to, atom);
|
||||
if (xmlFAGenerateTransitions(am, from, to, atom) < 0) {
|
||||
xmlRegFreeAtom(atom);
|
||||
return(NULL);
|
||||
}
|
||||
if (to == NULL)
|
||||
to = am->state;
|
||||
if (to == NULL)
|
||||
@ -4400,6 +4494,7 @@ xmlRegexpPtr
|
||||
xmlAutomataCompile(xmlAutomataPtr am) {
|
||||
xmlRegexpPtr ret;
|
||||
|
||||
if ((am == NULL) || (am->error != 0)) return(NULL);
|
||||
xmlFAEliminateEpsilonTransitions(am);
|
||||
/* xmlFAComputesDeterminism(am); */
|
||||
ret = xmlRegEpxFromParse(am);
|
||||
|
Reference in New Issue
Block a user