1
0
mirror of https://gitlab.gnome.org/GNOME/libxml2.git synced 2024-10-26 12:25:09 +03:00

parser: Improve handling of encoding and IO errors

Make sure that xmlCharEncInput, xmlParserInputBufferPush and
xmlParserInputBufferGrow set the correct error code in the
xmlParserInputBuffer. Handle errors when calling these functions.
This commit is contained in:
Nick Wellnhofer 2023-04-30 18:25:09 +02:00
parent fc69cf568b
commit 320f5084cd
6 changed files with 116 additions and 39 deletions

View File

@ -3858,9 +3858,10 @@ htmlCheckEncodingDirect(htmlParserCtxtPtr ctxt, const xmlChar *encoding) {
nbchars = xmlCharEncInput(ctxt->input->buf, 1);
xmlBufResetInput(ctxt->input->buf->buffer, ctxt->input);
if (nbchars < 0) {
htmlParseErr(ctxt, XML_ERR_INVALID_ENCODING,
htmlParseErr(ctxt, ctxt->input->buf->error,
"htmlCheckEncoding: encoder error\n",
NULL, NULL);
xmlHaltParser(ctxt);
}
}
}
@ -6279,7 +6280,9 @@ htmlParseChunk(htmlParserCtxtPtr ctxt, const char *chunk, int size,
res = xmlParserInputBufferPush(ctxt->input->buf, size, chunk);
xmlBufSetInputBaseCur(ctxt->input->buf->buffer, ctxt->input, base, cur);
if (res < 0) {
htmlErrMemory(ctxt, NULL);
htmlParseErr(ctxt, ctxt->input->buf->error,
"xmlParserInputBufferPush failed", NULL, NULL);
xmlHaltParser(ctxt);
return (ctxt->errNo);
}
#ifdef DEBUG_PUSH
@ -6302,8 +6305,9 @@ htmlParseChunk(htmlParserCtxtPtr ctxt, const char *chunk, int size,
nbchars = xmlCharEncInput(in, terminate);
xmlBufSetInputBaseCur(in->buffer, ctxt->input, base, current);
if (nbchars < 0) {
htmlParseErr(ctxt, XML_ERR_INVALID_ENCODING,
htmlParseErr(ctxt, in->error,
"encoder error\n", NULL, NULL);
xmlHaltParser(ctxt);
return(XML_ERR_INVALID_ENCODING);
}
}
@ -6394,10 +6398,15 @@ htmlCreatePushParserCtxt(htmlSAXHandlerPtr sax, void *user_data,
(ctxt->input->buf != NULL)) {
size_t base = xmlBufGetInputBase(ctxt->input->buf->buffer, ctxt->input);
size_t cur = ctxt->input->cur - ctxt->input->base;
int res;
xmlParserInputBufferPush(ctxt->input->buf, size, chunk);
res = xmlParserInputBufferPush(ctxt->input->buf, size, chunk);
xmlBufSetInputBaseCur(ctxt->input->buf->buffer, ctxt->input, base, cur);
if (res < 0) {
htmlParseErr(ctxt, ctxt->input->buf->error,
"xmlParserInputBufferPush failed\n", NULL, NULL);
xmlHaltParser(ctxt);
}
#ifdef DEBUG_PUSH
xmlGenericError(xmlGenericErrorContext, "HPP: pushed %d\n", size);
#endif

View File

@ -2006,6 +2006,34 @@ xmlUconvWrapper(uconv_t *cd, int toUnicode, unsigned char *out, int *outlen,
* *
************************************************************************/
/**
* xmlEncConvertError:
* @code: XML_ENC_ERR code
*
* Convert XML_ENC_ERR to libxml2 error codes.
*/
static int
xmlEncConvertError(int code) {
int ret;
switch (code) {
case XML_ENC_ERR_SUCCESS:
ret = XML_ERR_OK;
break;
case XML_ENC_ERR_INPUT:
ret = XML_ERR_INVALID_ENCODING;
break;
case XML_ENC_ERR_MEMORY:
ret = XML_ERR_NO_MEMORY;
break;
default:
ret = XML_ERR_INTERNAL_ERROR;
break;
}
return(ret);
}
/**
* xmlEncInputChunk:
* @handler: encoding handler
@ -2165,7 +2193,13 @@ xmlCharEncInput(xmlParserInputBufferPtr input, int flush)
xmlBufShrink(in, c_in);
xmlBufAddLen(out, c_out);
return (c_out? c_out : ret);
if ((c_out == 0) && (ret != 0)) {
if (input->error == 0)
input->error = xmlEncConvertError(ret);
return(ret);
}
return (c_out);
}
/**
@ -2301,7 +2335,7 @@ retry:
cur = xmlGetUTF8Char(content, &len);
if (cur <= 0)
return(ret);
goto error;
#ifdef DEBUG_ENCODING
xmlGenericError(xmlGenericErrorContext,
@ -2324,14 +2358,24 @@ retry:
c_in = charrefLen;
ret = xmlEncOutputChunk(output->encoder, xmlBufEnd(out), &c_out,
charref, &c_in);
if ((ret < 0) || (c_in != charrefLen))
return(XML_ENC_ERR_INTERNAL);
if ((ret < 0) || (c_in != charrefLen)) {
ret = XML_ENC_ERR_INTERNAL;
goto error;
}
xmlBufAddLen(out, c_out);
writtentot += c_out;
goto retry;
}
return(writtentot ? writtentot : ret);
error:
if ((writtentot <= 0) && (ret != 0)) {
if (output->error == 0)
output->error = xmlEncConvertError(ret);
return(ret);
}
return(writtentot);
}
#endif

View File

@ -11144,10 +11144,16 @@ xmlParseTryOrFinish(xmlParserCtxtPtr ctxt, int terminate) {
size_t base = xmlBufGetInputBase(ctxt->input->buf->buffer,
ctxt->input);
size_t current = ctxt->input->cur - ctxt->input->base;
int res;
xmlParserInputBufferPush(ctxt->input->buf, 0, "");
res = xmlParserInputBufferPush(ctxt->input->buf, 0, "");
xmlBufSetInputBaseCur(ctxt->input->buf->buffer, ctxt->input,
base, current);
if (res < 0) {
xmlFatalErr(ctxt, ctxt->input->buf->error, NULL);
xmlHaltParser(ctxt);
return(0);
}
}
}
avail = ctxt->input->end - ctxt->input->cur;
@ -11822,9 +11828,9 @@ xmlParseChunk(xmlParserCtxtPtr ctxt, const char *chunk, int size,
res = xmlParserInputBufferPush(ctxt->input->buf, size, chunk);
xmlBufSetInputBaseCur(ctxt->input->buf->buffer, ctxt->input, base, cur);
if (res < 0) {
ctxt->errNo = XML_PARSER_EOF;
xmlFatalErr(ctxt, ctxt->input->buf->error, NULL);
xmlHaltParser(ctxt);
return (XML_PARSER_EOF);
return(ctxt->errNo);
}
#ifdef DEBUG_PUSH
xmlGenericError(xmlGenericErrorContext, "PP: pushed %d\n", size);
@ -11842,11 +11848,9 @@ xmlParseChunk(xmlParserCtxtPtr ctxt, const char *chunk, int size,
nbchars = xmlCharEncInput(in, terminate);
xmlBufSetInputBaseCur(in->buffer, ctxt->input, base, current);
if (nbchars < 0) {
/* TODO 2.6.0 */
xmlGenericError(xmlGenericErrorContext,
"xmlParseChunk: encoder error\n");
xmlFatalErr(ctxt, in->error, NULL);
xmlHaltParser(ctxt);
return(XML_ERR_INVALID_ENCODING);
return(ctxt->errNo);
}
}
}
@ -11871,11 +11875,16 @@ xmlParseChunk(xmlParserCtxtPtr ctxt, const char *chunk, int size,
size_t base = xmlBufGetInputBase(ctxt->input->buf->buffer,
ctxt->input);
size_t current = ctxt->input->cur - ctxt->input->base;
int res;
xmlParserInputBufferPush(ctxt->input->buf, 1, "\r");
res = xmlParserInputBufferPush(ctxt->input->buf, 1, "\r");
xmlBufSetInputBaseCur(ctxt->input->buf->buffer, ctxt->input,
base, current);
if (res < 0) {
xmlFatalErr(ctxt, ctxt->input->buf->error, NULL);
xmlHaltParser(ctxt);
return(ctxt->errNo);
}
}
if (terminate) {
/*
@ -11983,10 +11992,14 @@ xmlCreatePushParserCtxt(xmlSAXHandlerPtr sax, void *user_data,
(ctxt->input != NULL) && (ctxt->input->buf != NULL)) {
size_t base = xmlBufGetInputBase(ctxt->input->buf->buffer, ctxt->input);
size_t cur = ctxt->input->cur - ctxt->input->base;
int res;
xmlParserInputBufferPush(ctxt->input->buf, size, chunk);
res = xmlParserInputBufferPush(ctxt->input->buf, size, chunk);
xmlBufSetInputBaseCur(ctxt->input->buf->buffer, ctxt->input, base, cur);
if (res < 0) {
xmlFatalErr(ctxt, ctxt->input->buf->error, NULL);
xmlHaltParser(ctxt);
}
#ifdef DEBUG_PUSH
xmlGenericError(xmlGenericErrorContext, "PP: pushed %d\n", size);
#endif
@ -14351,10 +14364,15 @@ xmlCtxtResetPush(xmlParserCtxtPtr ctxt, const char *chunk,
(ctxt->input->buf != NULL)) {
size_t base = xmlBufGetInputBase(ctxt->input->buf->buffer, ctxt->input);
size_t cur = ctxt->input->cur - ctxt->input->base;
int res;
xmlParserInputBufferPush(ctxt->input->buf, size, chunk);
res = xmlParserInputBufferPush(ctxt->input->buf, size, chunk);
xmlBufSetInputBaseCur(ctxt->input->buf->buffer, ctxt->input, base, cur);
if (res < 0) {
xmlFatalErr(ctxt, ctxt->input->buf->error, NULL);
xmlHaltParser(ctxt);
return(1);
}
#ifdef DEBUG_PUSH
xmlGenericError(xmlGenericErrorContext, "PP: pushed %d\n", size);
#endif

View File

@ -553,7 +553,7 @@ xmlParserGrow(xmlParserCtxtPtr ctxt) {
if (((curEnd > XML_MAX_LOOKUP_LIMIT) ||
(curBase > XML_MAX_LOOKUP_LIMIT)) &&
((ctxt->options & XML_PARSE_HUGE) == 0)) {
xmlErrInternal(ctxt, "Huge input lookup", NULL);
xmlErrMemory(ctxt, "Huge input lookup");
xmlHaltParser(ctxt);
return(-1);
}
@ -564,9 +564,8 @@ xmlParserGrow(xmlParserCtxtPtr ctxt) {
ret = xmlParserInputBufferGrow(buf, INPUT_CHUNK);
xmlBufSetInputBaseCur(buf->buffer, in, 0, curBase);
/* TODO: Get error code from xmlParserInputBufferGrow */
if (ret < 0) {
xmlErrInternal(ctxt, "Growing input buffer", NULL);
xmlFatalErr(ctxt, buf->error, NULL);
xmlHaltParser(ctxt);
}

31
xmlIO.c
View File

@ -3119,21 +3119,24 @@ xmlParserInputBufferPush(xmlParserInputBufferPtr in,
*/
if (in->raw == NULL) {
in->raw = xmlBufCreate();
if (in->raw == NULL) {
in->error = XML_ERR_NO_MEMORY;
return(-1);
}
}
ret = xmlBufAdd(in->raw, (const xmlChar *) buf, len);
if (ret != 0)
if (ret != 0) {
in->error = XML_ERR_NO_MEMORY;
return(-1);
}
/*
* convert as much as possible to the parser reading buffer.
*/
use = xmlBufUse(in->raw);
nbchars = xmlCharEncInput(in, 1);
if (nbchars < 0) {
xmlIOErr(XML_IO_ENCODER, NULL);
in->error = XML_IO_ENCODER;
if (nbchars < 0)
return(-1);
}
consumed = use - xmlBufUse(in->raw);
if ((consumed > ULONG_MAX) ||
(in->rawconsumed > ULONG_MAX - (unsigned long)consumed))
@ -3143,8 +3146,10 @@ xmlParserInputBufferPush(xmlParserInputBufferPtr in,
} else {
nbchars = len;
ret = xmlBufAdd(in->buffer, (xmlChar *) buf, nbchars);
if (ret != 0)
if (ret != 0) {
in->error = XML_ERR_NO_MEMORY;
return(-1);
}
}
#ifdef DEBUG_INPUT
xmlGenericError(xmlGenericErrorContext,
@ -3207,7 +3212,6 @@ xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
*/
if (in->readcallback != NULL) {
if (xmlBufGrow(buf, len + 1) < 0) {
xmlIOErrMemory("growing input buffer");
in->error = XML_ERR_NO_MEMORY;
return(-1);
}
@ -3215,11 +3219,15 @@ xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
res = in->readcallback(in->context, (char *)xmlBufEnd(buf), len);
if (res <= 0)
in->readcallback = endOfInput;
if (res < 0)
if (res < 0) {
in->error = XML_IO_UNKNOWN;
return(-1);
}
if (xmlBufAddLen(buf, res) < 0)
if (xmlBufAddLen(buf, res) < 0) {
in->error = XML_ERR_NO_MEMORY;
return(-1);
}
}
/*
@ -3240,11 +3248,8 @@ xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
*/
use = xmlBufUse(buf);
res = xmlCharEncInput(in, 1);
if (res < 0) {
xmlIOErr(XML_IO_ENCODER, NULL);
in->error = XML_IO_ENCODER;
if (res < 0)
return(-1);
}
consumed = use - xmlBufUse(buf);
if ((consumed > ULONG_MAX) ||
(in->rawconsumed > ULONG_MAX - (unsigned long)consumed))

View File

@ -788,6 +788,8 @@ xmlTextReaderPushData(xmlTextReaderPtr reader) {
reader->state = oldstate;
}
} else if (val < 0) {
xmlGenericError(xmlGenericErrorContext,
"xmlParserInputBufferRead failed\n");
reader->mode = XML_TEXTREADER_MODE_EOF;
reader->state = oldstate;
if ((oldstate != XML_TEXTREADER_START) ||