Allow XML_GetBuffer() with len=0 on a fresh parser

len=0 was previously OK if there had previously been a non-zero call.
It makes sense to allow an application to work the same way on a
newly-created parser, and not have to care if its incoming buffer
happens to be 0.
This commit is contained in:
Snild Dolkow 2023-10-26 10:41:00 +02:00
parent f1eea784d0
commit 09957b8ced
2 changed files with 26 additions and 11 deletions

View file

@ -2115,7 +2115,8 @@ XML_GetBuffer(XML_Parser parser, int len) {
default:;
}
if (len > EXPAT_SAFE_PTR_DIFF(parser->m_bufferLim, parser->m_bufferEnd)) {
if (len > EXPAT_SAFE_PTR_DIFF(parser->m_bufferLim, parser->m_bufferEnd)
|| parser->m_buffer == NULL) {
#if XML_CONTEXT_BYTES > 0
int keep;
#endif /* XML_CONTEXT_BYTES > 0 */
@ -2138,8 +2139,9 @@ XML_GetBuffer(XML_Parser parser, int len) {
}
neededSize += keep;
#endif /* XML_CONTEXT_BYTES > 0 */
if (neededSize
<= EXPAT_SAFE_PTR_DIFF(parser->m_bufferLim, parser->m_buffer)) {
if (parser->m_buffer && parser->m_bufferPtr
&& neededSize
<= EXPAT_SAFE_PTR_DIFF(parser->m_bufferLim, parser->m_buffer)) {
#if XML_CONTEXT_BYTES > 0
if (keep < EXPAT_SAFE_PTR_DIFF(parser->m_bufferPtr, parser->m_buffer)) {
int offset
@ -2153,14 +2155,12 @@ XML_GetBuffer(XML_Parser parser, int len) {
parser->m_bufferPtr -= offset;
}
#else
if (parser->m_buffer && parser->m_bufferPtr) {
memmove(parser->m_buffer, parser->m_bufferPtr,
EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr));
parser->m_bufferEnd
= parser->m_buffer
+ EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr);
parser->m_bufferPtr = parser->m_buffer;
}
memmove(parser->m_buffer, parser->m_bufferPtr,
EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr));
parser->m_bufferEnd
= parser->m_buffer
+ EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr);
parser->m_bufferPtr = parser->m_buffer;
#endif /* XML_CONTEXT_BYTES > 0 */
} else {
char *newBuf;

View file

@ -2911,6 +2911,20 @@ START_TEST(test_buffer_can_grow_to_max) {
}
END_TEST
START_TEST(test_getbuffer_allocates_on_zero_len) {
for (int first_len = 1; first_len >= 0; first_len--) {
set_subtest("with len=%d first", first_len);
XML_Parser parser = XML_ParserCreate(NULL);
assert_true(parser != NULL);
assert_true(XML_GetBuffer(parser, first_len) != NULL);
assert_true(XML_GetBuffer(parser, 0) != NULL);
if (XML_ParseBuffer(parser, 0, XML_FALSE) != XML_STATUS_OK)
xml_failure(parser);
XML_ParserFree(parser);
}
}
END_TEST
/* Test position information macros */
START_TEST(test_byte_info_at_end) {
const char *text = "<doc></doc>";
@ -5411,6 +5425,7 @@ make_basic_test_case(Suite *s) {
tcase_add_test(tc_basic, test_get_buffer_3_overflow);
#endif
tcase_add_test(tc_basic, test_buffer_can_grow_to_max);
tcase_add_test(tc_basic, test_getbuffer_allocates_on_zero_len);
tcase_add_test(tc_basic, test_byte_info_at_end);
tcase_add_test(tc_basic, test_byte_info_at_error);
tcase_add_test(tc_basic, test_byte_info_at_cdata);