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
diff --git a/xmlregexp.c b/xmlregexp.c
index 8f1e9c1..6ea1bfe 100644
--- a/xmlregexp.c
+++ b/xmlregexp.c
@@ -332,23 +332,19 @@
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 @@
*/
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 @@
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 @@
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 @@
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 @@
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 @@
for (i = 0;i < nbatoms;i++)
xmlFree(stringMap[i]);
xmlFree(stringMap);
- goto fail_compact;
+ goto not_determ;
}
} else {
#if 0
@@ -524,7 +564,14 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
* @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 @@
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 @@
default:
break;
}
+ return(0);
}
/**
@@ -1433,6 +1493,9 @@
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 @@
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 @@
* @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 @@
* @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 @@
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 @@
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 @@
}
}
if (!first) {
- xmlFAGenerateTransitions(ctxt, previous, ctxt->end, prevatom);
+ if (xmlFAGenerateTransitions(ctxt, previous, ctxt->end, prevatom) < 0)
+ return(-1);
}
+ return(0);
}
/**
@@ -3994,7 +4069,15 @@
/* 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 @@
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 @@
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 @@
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 @@
xmlAutomataCompile(xmlAutomataPtr am) {
xmlRegexpPtr ret;
+ if ((am == NULL) || (am->error != 0)) return(NULL);
xmlFAEliminateEpsilonTransitions(am);
/* xmlFAComputesDeterminism(am); */
ret = xmlRegEpxFromParse(am);