1
0
mirror of https://gitlab.gnome.org/GNOME/libxml2.git synced 2025-03-21 22:50:08 +03:00

io: Fix memory lifetime issue with input buffers

xmlParserInputBufferCreateMem must make a copy of the buffer.

This fixes a regression from 2.11 which could cause reads from freed
memory depending on the use case.

Undeprecate xmlParserInputBufferCreateStatic which can avoid copying
the whole buffer.
This commit is contained in:
Nick Wellnhofer 2023-12-12 23:51:32 +01:00
parent 0e4a11bb30
commit c2bbeed1fd
5 changed files with 70 additions and 31 deletions

View File

@ -6719,7 +6719,8 @@ htmlCtxtReadMemory(htmlParserCtxtPtr ctxt, const char *buffer, int size,
htmlCtxtReset(ctxt);
input = xmlParserInputBufferCreateMem(buffer, size, XML_CHAR_ENCODING_NONE);
input = xmlParserInputBufferCreateStatic(buffer, size,
XML_CHAR_ENCODING_NONE);
if (input == NULL) {
htmlErrMemory(ctxt, NULL);
return(NULL);

View File

@ -216,7 +216,6 @@ XMLPUBFUN xmlParserInputBufferPtr
XMLPUBFUN xmlParserInputBufferPtr
xmlParserInputBufferCreateMem (const char *mem, int size,
xmlCharEncoding enc);
XML_DEPRECATED
XMLPUBFUN xmlParserInputBufferPtr
xmlParserInputBufferCreateStatic (const char *mem, int size,
xmlCharEncoding enc);

View File

@ -14871,7 +14871,8 @@ xmlCtxtReadMemory(xmlParserCtxtPtr ctxt, const char *buffer, int size,
xmlCtxtReset(ctxt);
input = xmlParserInputBufferCreateMem(buffer, size, XML_CHAR_ENCODING_NONE);
input = xmlParserInputBufferCreateStatic(buffer, size,
XML_CHAR_ENCODING_NONE);
if (input == NULL) {
xmlErrMemory(ctxt, NULL);
return(NULL);

View File

@ -648,8 +648,8 @@ static int testCharRanges(void) {
fprintf(stderr, "Failed to allocate parser context\n");
return(1);
}
buf = xmlParserInputBufferCreateMem(data, sizeof(data),
XML_CHAR_ENCODING_NONE);
buf = xmlParserInputBufferCreateStatic(data, sizeof(data),
XML_CHAR_ENCODING_NONE);
if (buf == NULL) {
fprintf(stderr, "Failed to allocate input buffer\n");
test_ret = 1;

90
xmlIO.c
View File

@ -2833,7 +2833,8 @@ xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
}
typedef struct {
const char *mem;
char *mem;
const char *cur;
size_t size;
} xmlMemIOCtxt;
@ -2844,8 +2845,8 @@ xmlMemRead(void *vctxt, char *buf, int size) {
if ((size_t) size > ctxt->size)
size = ctxt->size;
memcpy(buf, ctxt->mem, size);
ctxt->mem += size;
memcpy(buf, ctxt->cur, size);
ctxt->cur += size;
ctxt->size -= size;
return size;
@ -2853,7 +2854,11 @@ xmlMemRead(void *vctxt, char *buf, int size) {
static int
xmlMemClose(void *vctxt) {
xmlFree(vctxt);
xmlMemIOCtxt *ctxt = vctxt;
if (ctxt->mem != 0)
xmlFree(ctxt->mem);
xmlFree(ctxt);
return(0);
}
@ -2863,22 +2868,70 @@ xmlMemClose(void *vctxt) {
* @size: the length of the memory block
* @enc: the charset encoding if known (deprecated)
*
* Create a buffered parser input for the progressive parsing for the input
* from a memory area.
* Create a parser input buffer for parsing from a memory area.
*
* This function makes a copy of the whole input buffer. If you are sure
* that the contents of the buffer will remain valid until the document
* was parsed, you can avoid the copy by using
* xmlParserInputBufferCreateStatic.
*
* The encoding argument is deprecated and should be set to
* XML_CHAR_ENCODING_NONE. The encoding can be changed with
* xmlSwitchEncoding or xmlSwitchEncodingName later on.
*
* Returns the new parser input or NULL
* Returns the new parser input or NULL in case of error.
*/
xmlParserInputBufferPtr
xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
xmlParserInputBufferPtr buf;
xmlMemIOCtxt *ctxt;
char *copy;
if ((size < 0) || (mem == NULL))
return(NULL);
copy = (char *) xmlStrndup((const xmlChar *) mem, size);
if (copy == NULL)
return(NULL);
buf = xmlParserInputBufferCreateStatic(copy, size, enc);
if (buf == NULL) {
xmlFree(copy);
return(NULL);
}
ctxt = buf->context;
ctxt->mem = copy;
return(buf);
}
/**
* xmlParserInputBufferCreateStatic:
* @mem: the memory input
* @size: the length of the memory block
* @enc: the charset encoding if known
*
* Create a parser input buffer for parsing from a memory area.
*
* This functions assumes that the contents of the input buffer remain
* valid until the document was parsed. Use xmlParserInputBufferCreateMem
* otherwise.
*
* The encoding argument is deprecated and should be set to
* XML_CHAR_ENCODING_NONE. The encoding can be changed with
* xmlSwitchEncoding or xmlSwitchEncodingName later on.
*
* Returns the new parser input or NULL in case of error.
*/
xmlParserInputBufferPtr
xmlParserInputBufferCreateStatic(const char *mem, int size,
xmlCharEncoding enc) {
xmlParserInputBufferPtr ret;
xmlMemIOCtxt *ctxt;
if (size < 0) return(NULL);
if (mem == NULL) return(NULL);
if ((size < 0) || (mem == NULL))
return(NULL);
ret = xmlAllocParserInputBuffer(enc);
if (ret == NULL)
@ -2889,7 +2942,8 @@ xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
xmlFreeParserInputBuffer(ret);
return(NULL);
}
ctxt->mem = mem;
ctxt->mem = NULL;
ctxt->cur = mem;
ctxt->size = size;
ret->context = ctxt;
@ -2899,22 +2953,6 @@ xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
return(ret);
}
/**
* xmlParserInputBufferCreateStatic:
* @mem: the memory input
* @size: the length of the memory block
* @enc: the charset encoding if known
*
* DEPRECATED: Use xmlParserInputBufferCreateMem.
*
* Returns the new parser input or NULL
*/
xmlParserInputBufferPtr
xmlParserInputBufferCreateStatic(const char *mem, int size,
xmlCharEncoding enc) {
return(xmlParserInputBufferCreateMem(mem, size, enc));
}
typedef struct {
const xmlChar *str;
} xmlStringIOCtxt;