1
0
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:
Daniel Veillard
2003-04-24 16:06:47 +00:00
parent 18f113da8c
commit a76fe5ca11
17 changed files with 1289 additions and 95 deletions

View File

@ -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);