buf: Fix possible infinite loop in EscapeString, VSnprintf
The current code will go into an infinite loop if the printf generated
string is >= 1000, AND exactly 1 character smaller than the amount of free
space in the buffer. When this happens, we are dropped into the loop body,
but nothing will actually change, because count == (buf->size - buf->use - 1),
and virBufferGrow returns unchanged if count < (buf->size - buf->use)
Fix this by removing the '- 1' bit from 'size'. The *nprintf functions handle
the NULL byte for us anyways, so we shouldn't need to manually accommodate
for it.
Here's a bug where we are actually hitting this issue:
https://bugzilla.redhat.com/show_bug.cgi?id=602772
v2: Eric's improvements: while -> if (), remove extra va_list variable,
make sure we report buffer error if snprintf fails
v3: Add tests/virbuftest which reproduces the infinite loop before this
patch, works correctly after
2010-09-01 17:51:35 +00:00
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
|
|
|
|
#include "internal.h"
|
|
|
|
#include "testutils.h"
|
2012-12-04 12:04:07 +00:00
|
|
|
#include "virbuffer.h"
|
2012-12-12 18:06:53 +00:00
|
|
|
#include "viralloc.h"
|
2013-04-03 10:36:23 +00:00
|
|
|
#include "virstring.h"
|
buf: Fix possible infinite loop in EscapeString, VSnprintf
The current code will go into an infinite loop if the printf generated
string is >= 1000, AND exactly 1 character smaller than the amount of free
space in the buffer. When this happens, we are dropped into the loop body,
but nothing will actually change, because count == (buf->size - buf->use - 1),
and virBufferGrow returns unchanged if count < (buf->size - buf->use)
Fix this by removing the '- 1' bit from 'size'. The *nprintf functions handle
the NULL byte for us anyways, so we shouldn't need to manually accommodate
for it.
Here's a bug where we are actually hitting this issue:
https://bugzilla.redhat.com/show_bug.cgi?id=602772
v2: Eric's improvements: while -> if (), remove extra va_list variable,
make sure we report buffer error if snprintf fails
v3: Add tests/virbuftest which reproduces the infinite loop before this
patch, works correctly after
2010-09-01 17:51:35 +00:00
|
|
|
|
2013-06-07 15:10:28 +00:00
|
|
|
#define VIR_FROM_THIS VIR_FROM_NONE
|
|
|
|
|
2020-01-14 07:04:29 +00:00
|
|
|
struct testBufAddStrData {
|
|
|
|
const char *data;
|
|
|
|
const char *expect;
|
2020-01-14 07:04:14 +00:00
|
|
|
const char *arg;
|
2020-01-14 07:04:29 +00:00
|
|
|
};
|
|
|
|
|
2019-10-14 12:45:03 +00:00
|
|
|
static int testBufAutoIndent(const void *data G_GNUC_UNUSED)
|
2011-10-20 21:48:47 +00:00
|
|
|
{
|
2020-07-02 23:35:41 +00:00
|
|
|
g_auto(virBuffer) bufinit = VIR_BUFFER_INITIALIZER;
|
2021-03-11 07:16:13 +00:00
|
|
|
virBuffer *buf = &bufinit;
|
2011-10-20 21:48:47 +00:00
|
|
|
const char expected[] =
|
2022-02-11 14:48:02 +00:00
|
|
|
" 1\n 2\n 3\n 4\n 5\n 6\n 7\n &\n 8\n 9\n 10\n"
|
|
|
|
" ' 11'\n ''\\''12'\n '\"13'\n ''\n";
|
2020-01-14 07:04:54 +00:00
|
|
|
g_autofree char *result = NULL;
|
2011-10-20 21:48:47 +00:00
|
|
|
int ret = 0;
|
|
|
|
|
2019-10-24 10:51:24 +00:00
|
|
|
if (virBufferGetIndent(buf) != 0 ||
|
2019-10-24 10:29:12 +00:00
|
|
|
virBufferGetEffectiveIndent(buf) != 0) {
|
2015-04-23 17:38:00 +00:00
|
|
|
VIR_TEST_DEBUG("Wrong indentation");
|
2011-10-20 21:48:47 +00:00
|
|
|
ret = -1;
|
|
|
|
}
|
|
|
|
virBufferAdjustIndent(buf, 3);
|
2012-06-08 19:50:23 +00:00
|
|
|
if (STRNEQ(virBufferCurrentContent(buf), "")) {
|
2015-04-23 17:38:00 +00:00
|
|
|
VIR_TEST_DEBUG("Wrong content");
|
2012-06-08 19:50:23 +00:00
|
|
|
ret = -1;
|
|
|
|
}
|
2019-10-24 10:51:24 +00:00
|
|
|
if (virBufferGetIndent(buf) != 3 ||
|
2019-10-24 12:25:59 +00:00
|
|
|
virBufferGetEffectiveIndent(buf) != 3) {
|
2015-04-23 17:38:00 +00:00
|
|
|
VIR_TEST_DEBUG("Wrong indentation");
|
2011-10-20 21:48:47 +00:00
|
|
|
ret = -1;
|
|
|
|
}
|
|
|
|
virBufferAdjustIndent(buf, -2);
|
2019-10-24 10:51:24 +00:00
|
|
|
if (virBufferGetIndent(buf) != 1 ||
|
2019-10-24 12:25:59 +00:00
|
|
|
virBufferGetEffectiveIndent(buf) != 1) {
|
2015-04-23 17:38:00 +00:00
|
|
|
VIR_TEST_DEBUG("Wrong indentation");
|
2011-10-20 21:48:47 +00:00
|
|
|
ret = -1;
|
|
|
|
}
|
|
|
|
virBufferAdjustIndent(buf, -3);
|
2019-10-24 10:51:24 +00:00
|
|
|
if (virBufferGetIndent(buf) != 0 ||
|
2019-10-24 10:29:12 +00:00
|
|
|
virBufferGetEffectiveIndent(buf) != 0) {
|
2019-10-24 07:25:20 +00:00
|
|
|
VIR_TEST_DEBUG("Indentation level not truncated");
|
2011-10-20 21:48:47 +00:00
|
|
|
ret = -1;
|
|
|
|
}
|
2019-10-24 07:25:20 +00:00
|
|
|
virBufferAdjustIndent(buf, 3);
|
2011-10-20 21:48:47 +00:00
|
|
|
virBufferFreeAndReset(buf);
|
2019-10-24 10:51:24 +00:00
|
|
|
if (virBufferGetIndent(buf) != 0 ||
|
2019-10-24 12:25:59 +00:00
|
|
|
virBufferGetEffectiveIndent(buf) != 0) {
|
2015-04-23 17:38:00 +00:00
|
|
|
VIR_TEST_DEBUG("Reset didn't clear indentation");
|
2011-10-20 21:48:47 +00:00
|
|
|
ret = -1;
|
|
|
|
}
|
|
|
|
virBufferAdjustIndent(buf, 2);
|
|
|
|
virBufferAddLit(buf, "1");
|
2012-06-08 19:50:23 +00:00
|
|
|
if (STRNEQ(virBufferCurrentContent(buf), " 1")) {
|
2015-04-23 17:38:00 +00:00
|
|
|
VIR_TEST_DEBUG("Wrong content");
|
2012-06-08 19:50:23 +00:00
|
|
|
ret = -1;
|
|
|
|
}
|
2019-10-24 10:51:24 +00:00
|
|
|
if (virBufferGetIndent(buf) != 2 ||
|
2019-10-24 10:29:12 +00:00
|
|
|
virBufferGetEffectiveIndent(buf) != 0) {
|
2015-04-23 17:38:00 +00:00
|
|
|
VIR_TEST_DEBUG("Wrong indentation");
|
2011-10-20 21:48:47 +00:00
|
|
|
ret = -1;
|
|
|
|
}
|
|
|
|
virBufferAddLit(buf, "\n");
|
|
|
|
virBufferAdd(buf, "" "2\n", -1); /* Extra "" appeases syntax-check */
|
|
|
|
virBufferAddChar(buf, '3');
|
|
|
|
virBufferAddChar(buf, '\n');
|
|
|
|
virBufferAsprintf(buf, "%d", 4);
|
|
|
|
virBufferAsprintf(buf, "%c", '\n');
|
|
|
|
virBufferStrcat(buf, "5", "\n", "6\n", NULL);
|
|
|
|
virBufferEscapeString(buf, "%s\n", "7");
|
|
|
|
virBufferEscapeString(buf, "%s\n", "&");
|
|
|
|
virBufferEscapeSexpr(buf, "%s", "8\n");
|
|
|
|
virBufferURIEncodeString(buf, "9");
|
|
|
|
virBufferAddChar(buf, '\n');
|
|
|
|
virBufferEscapeShell(buf, "10");
|
|
|
|
virBufferAddChar(buf, '\n');
|
|
|
|
virBufferEscapeShell(buf, " 11");
|
|
|
|
virBufferAddChar(buf, '\n');
|
2022-02-11 14:48:02 +00:00
|
|
|
virBufferEscapeShell(buf, "'12");
|
|
|
|
virBufferAddChar(buf, '\n');
|
|
|
|
virBufferEscapeShell(buf, "\"13");
|
|
|
|
virBufferAddChar(buf, '\n');
|
|
|
|
virBufferEscapeShell(buf, "");
|
|
|
|
virBufferAddChar(buf, '\n');
|
2011-10-20 21:48:47 +00:00
|
|
|
|
|
|
|
result = virBufferContentAndReset(buf);
|
|
|
|
if (!result || STRNEQ(result, expected)) {
|
2016-05-26 15:01:51 +00:00
|
|
|
virTestDifference(stderr, expected, result);
|
2011-10-20 21:48:47 +00:00
|
|
|
ret = -1;
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2019-10-14 12:45:03 +00:00
|
|
|
static int testBufTrim(const void *data G_GNUC_UNUSED)
|
virBuffer: add way to trim back extra text
I'm tired of writing:
bool sep = false;
while (...) {
if (sep)
virBufferAddChar(buf, ',');
sep = true;
virBufferAdd(buf, str);
}
This makes it easier, allowing one to write:
while (...)
virBufferAsprintf(buf, "%s,", str);
virBufferTrim(buf, ",", -1);
to trim any remaining comma.
* src/util/buf.h (virBufferTrim): Declare.
* src/util/buf.c (virBufferTrim): New function.
* tests/virbuftest.c (testBufTrim): Test it.
2012-05-18 22:36:59 +00:00
|
|
|
{
|
2020-07-02 23:35:41 +00:00
|
|
|
g_auto(virBuffer) bufinit = VIR_BUFFER_INITIALIZER;
|
2021-03-11 07:16:13 +00:00
|
|
|
virBuffer *buf = NULL;
|
2020-01-14 07:04:54 +00:00
|
|
|
g_autofree char *result = NULL;
|
virBuffer: add way to trim back extra text
I'm tired of writing:
bool sep = false;
while (...) {
if (sep)
virBufferAddChar(buf, ',');
sep = true;
virBufferAdd(buf, str);
}
This makes it easier, allowing one to write:
while (...)
virBufferAsprintf(buf, "%s,", str);
virBufferTrim(buf, ",", -1);
to trim any remaining comma.
* src/util/buf.h (virBufferTrim): Declare.
* src/util/buf.c (virBufferTrim): New function.
* tests/virbuftest.c (testBufTrim): Test it.
2012-05-18 22:36:59 +00:00
|
|
|
const char *expected = "a,b";
|
2013-06-18 15:52:00 +00:00
|
|
|
|
2020-02-02 19:26:38 +00:00
|
|
|
virBufferTrim(buf, "");
|
virBuffer: add way to trim back extra text
I'm tired of writing:
bool sep = false;
while (...) {
if (sep)
virBufferAddChar(buf, ',');
sep = true;
virBufferAdd(buf, str);
}
This makes it easier, allowing one to write:
while (...)
virBufferAsprintf(buf, "%s,", str);
virBufferTrim(buf, ",", -1);
to trim any remaining comma.
* src/util/buf.h (virBufferTrim): Declare.
* src/util/buf.c (virBufferTrim): New function.
* tests/virbuftest.c (testBufTrim): Test it.
2012-05-18 22:36:59 +00:00
|
|
|
buf = &bufinit;
|
|
|
|
|
|
|
|
virBufferAddLit(buf, "a;");
|
2020-02-02 19:26:38 +00:00
|
|
|
virBufferTrim(buf, "");
|
|
|
|
virBufferTrim(buf, "");
|
2020-02-02 19:17:20 +00:00
|
|
|
virBufferTrimLen(buf, 1);
|
|
|
|
virBufferTrimLen(buf, 5);
|
|
|
|
virBufferTrimLen(buf, 2);
|
virBuffer: add way to trim back extra text
I'm tired of writing:
bool sep = false;
while (...) {
if (sep)
virBufferAddChar(buf, ',');
sep = true;
virBufferAdd(buf, str);
}
This makes it easier, allowing one to write:
while (...)
virBufferAsprintf(buf, "%s,", str);
virBufferTrim(buf, ",", -1);
to trim any remaining comma.
* src/util/buf.h (virBufferTrim): Declare.
* src/util/buf.c (virBufferTrim): New function.
* tests/virbuftest.c (testBufTrim): Test it.
2012-05-18 22:36:59 +00:00
|
|
|
|
|
|
|
virBufferAddLit(buf, ",b,,");
|
2020-02-02 19:26:38 +00:00
|
|
|
virBufferTrim(buf, NULL);
|
|
|
|
virBufferTrim(buf, "b");
|
|
|
|
virBufferTrim(buf, ",,");
|
virBuffer: add way to trim back extra text
I'm tired of writing:
bool sep = false;
while (...) {
if (sep)
virBufferAddChar(buf, ',');
sep = true;
virBufferAdd(buf, str);
}
This makes it easier, allowing one to write:
while (...)
virBufferAsprintf(buf, "%s,", str);
virBufferTrim(buf, ",", -1);
to trim any remaining comma.
* src/util/buf.h (virBufferTrim): Declare.
* src/util/buf.c (virBufferTrim): New function.
* tests/virbuftest.c (testBufTrim): Test it.
2012-05-18 22:36:59 +00:00
|
|
|
|
|
|
|
result = virBufferContentAndReset(buf);
|
|
|
|
if (!result || STRNEQ(result, expected)) {
|
2016-05-26 15:01:51 +00:00
|
|
|
virTestDifference(stderr, expected, result);
|
2020-07-03 03:20:17 +00:00
|
|
|
return -1;
|
virBuffer: add way to trim back extra text
I'm tired of writing:
bool sep = false;
while (...) {
if (sep)
virBufferAddChar(buf, ',');
sep = true;
virBufferAdd(buf, str);
}
This makes it easier, allowing one to write:
while (...)
virBufferAsprintf(buf, "%s,", str);
virBufferTrim(buf, ",", -1);
to trim any remaining comma.
* src/util/buf.h (virBufferTrim): Declare.
* src/util/buf.c (virBufferTrim): New function.
* tests/virbuftest.c (testBufTrim): Test it.
2012-05-18 22:36:59 +00:00
|
|
|
}
|
|
|
|
|
2020-07-03 03:20:17 +00:00
|
|
|
return 0;
|
virBuffer: add way to trim back extra text
I'm tired of writing:
bool sep = false;
while (...) {
if (sep)
virBufferAddChar(buf, ',');
sep = true;
virBufferAdd(buf, str);
}
This makes it easier, allowing one to write:
while (...)
virBufferAsprintf(buf, "%s,", str);
virBufferTrim(buf, ",", -1);
to trim any remaining comma.
* src/util/buf.h (virBufferTrim): Declare.
* src/util/buf.c (virBufferTrim): New function.
* tests/virbuftest.c (testBufTrim): Test it.
2012-05-18 22:36:59 +00:00
|
|
|
}
|
|
|
|
|
2020-01-14 07:04:14 +00:00
|
|
|
static int
|
|
|
|
testBufTrimChars(const void *opaque)
|
|
|
|
{
|
|
|
|
const struct testBufAddStrData *data = opaque;
|
2020-07-02 23:35:41 +00:00
|
|
|
g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
|
2020-01-14 07:04:14 +00:00
|
|
|
g_autofree char *actual = NULL;
|
|
|
|
|
|
|
|
virBufferAddStr(&buf, data->data);
|
|
|
|
virBufferTrimChars(&buf, data->arg);
|
|
|
|
|
|
|
|
if (!(actual = virBufferContentAndReset(&buf))) {
|
|
|
|
VIR_TEST_DEBUG("buf is empty");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (STRNEQ_NULLABLE(actual, data->expect)) {
|
|
|
|
VIR_TEST_DEBUG("testBufEscapeStr(): Strings don't match:");
|
|
|
|
virTestDifference(stderr, data->expect, actual);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-10-14 12:45:03 +00:00
|
|
|
static int testBufAddBuffer(const void *data G_GNUC_UNUSED)
|
2015-02-19 09:56:58 +00:00
|
|
|
{
|
2020-07-02 23:35:41 +00:00
|
|
|
g_auto(virBuffer) buf1 = VIR_BUFFER_INITIALIZER;
|
|
|
|
g_auto(virBuffer) buf2 = VIR_BUFFER_INITIALIZER;
|
|
|
|
g_auto(virBuffer) buf3 = VIR_BUFFER_INITIALIZER;
|
2020-01-14 07:04:54 +00:00
|
|
|
g_autofree char *result = NULL;
|
2015-02-19 09:56:58 +00:00
|
|
|
const char *expected = \
|
|
|
|
" A long time ago, in a galaxy far,\n" \
|
2017-11-03 12:09:47 +00:00
|
|
|
" far away...\n" \
|
|
|
|
" It is a period of civil war.\n" \
|
|
|
|
" Rebel spaceships, striking\n" \
|
|
|
|
" from a hidden base, have won\n" \
|
|
|
|
" their first victory against\n" \
|
|
|
|
" the evil Galactic Empire.\n" \
|
|
|
|
" During the battle, rebel\n" \
|
|
|
|
" spies managed to steal secret\n" \
|
|
|
|
" plans to the Empire's\n" \
|
|
|
|
" ultimate weapon, the DEATH\n" \
|
|
|
|
" STAR, an armored space\n" \
|
|
|
|
" station with enough power to\n" \
|
2015-02-19 09:56:58 +00:00
|
|
|
" destroy an entire planet.\n";
|
|
|
|
|
|
|
|
if (virBufferUse(&buf1)) {
|
2015-04-23 17:38:00 +00:00
|
|
|
VIR_TEST_DEBUG("buf1 already in use");
|
2020-07-03 03:20:17 +00:00
|
|
|
return -1;
|
2015-02-19 09:56:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (virBufferUse(&buf2)) {
|
2015-04-23 17:38:00 +00:00
|
|
|
VIR_TEST_DEBUG("buf2 already in use");
|
2020-07-03 03:20:17 +00:00
|
|
|
return -1;
|
2015-02-19 09:56:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (virBufferUse(&buf3)) {
|
2015-04-23 17:38:00 +00:00
|
|
|
VIR_TEST_DEBUG("buf3 already in use");
|
2020-07-03 03:20:17 +00:00
|
|
|
return -1;
|
2015-02-19 09:56:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virBufferAdjustIndent(&buf1, 2);
|
|
|
|
virBufferAddLit(&buf1, "A long time ago, in a galaxy far,\n");
|
|
|
|
virBufferAddLit(&buf1, "far away...\n");
|
|
|
|
|
|
|
|
virBufferAdjustIndent(&buf2, 4);
|
|
|
|
virBufferAddLit(&buf2, "It is a period of civil war.\n");
|
|
|
|
virBufferAddLit(&buf2, "Rebel spaceships, striking\n");
|
|
|
|
virBufferAddLit(&buf2, "from a hidden base, have won\n");
|
|
|
|
virBufferAddLit(&buf2, "their first victory against\n");
|
|
|
|
virBufferAddLit(&buf2, "the evil Galactic Empire.\n");
|
|
|
|
|
|
|
|
virBufferAdjustIndent(&buf3, 2);
|
|
|
|
virBufferAddLit(&buf3, "During the battle, rebel\n");
|
|
|
|
virBufferAddLit(&buf3, "spies managed to steal secret\n");
|
|
|
|
virBufferAddLit(&buf3, "plans to the Empire's\n");
|
|
|
|
virBufferAddLit(&buf3, "ultimate weapon, the DEATH\n");
|
|
|
|
virBufferAddLit(&buf3, "STAR, an armored space\n");
|
|
|
|
virBufferAddLit(&buf3, "station with enough power to\n");
|
|
|
|
virBufferAddLit(&buf3, "destroy an entire planet.\n");
|
|
|
|
|
|
|
|
if (!virBufferUse(&buf1)) {
|
2015-04-23 17:38:00 +00:00
|
|
|
VIR_TEST_DEBUG("Error adding to buf1");
|
2020-07-03 03:20:17 +00:00
|
|
|
return -1;
|
2015-02-19 09:56:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!virBufferUse(&buf2)) {
|
2015-04-23 17:38:00 +00:00
|
|
|
VIR_TEST_DEBUG("Error adding to buf2");
|
2020-07-03 03:20:17 +00:00
|
|
|
return -1;
|
2015-02-19 09:56:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!virBufferUse(&buf3)) {
|
2015-04-23 17:38:00 +00:00
|
|
|
VIR_TEST_DEBUG("Error adding to buf3");
|
2020-07-03 03:20:17 +00:00
|
|
|
return -1;
|
2015-02-19 09:56:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virBufferAddBuffer(&buf2, &buf3);
|
|
|
|
|
|
|
|
if (!virBufferUse(&buf2)) {
|
2015-04-23 17:38:00 +00:00
|
|
|
VIR_TEST_DEBUG("buf2 cleared mistakenly");
|
2020-07-03 03:20:17 +00:00
|
|
|
return -1;
|
2015-02-19 09:56:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (virBufferUse(&buf3)) {
|
2015-04-23 17:38:00 +00:00
|
|
|
VIR_TEST_DEBUG("buf3 is not clear even though it should be");
|
2020-07-03 03:20:17 +00:00
|
|
|
return -1;
|
2015-02-19 09:56:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virBufferAddBuffer(&buf1, &buf2);
|
|
|
|
|
|
|
|
if (!virBufferUse(&buf1)) {
|
2015-04-23 17:38:00 +00:00
|
|
|
VIR_TEST_DEBUG("buf1 cleared mistakenly");
|
2020-07-03 03:20:17 +00:00
|
|
|
return -1;
|
2015-02-19 09:56:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (virBufferUse(&buf2)) {
|
2015-04-23 17:38:00 +00:00
|
|
|
VIR_TEST_DEBUG("buf2 is not clear even though it should be");
|
2020-07-03 03:20:17 +00:00
|
|
|
return -1;
|
2015-02-19 09:56:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
result = virBufferContentAndReset(&buf1);
|
|
|
|
if (STRNEQ_NULLABLE(result, expected)) {
|
2016-05-26 15:01:51 +00:00
|
|
|
virTestDifference(stderr, expected, result);
|
2020-07-03 03:20:17 +00:00
|
|
|
return -1;
|
2015-02-19 09:56:58 +00:00
|
|
|
}
|
|
|
|
|
2020-07-03 03:20:17 +00:00
|
|
|
return 0;
|
2015-02-19 09:56:58 +00:00
|
|
|
}
|
|
|
|
|
2015-03-24 09:53:29 +00:00
|
|
|
static int
|
2020-01-14 07:05:56 +00:00
|
|
|
testBufAddStr(const void *opaque)
|
2015-03-24 09:53:29 +00:00
|
|
|
{
|
|
|
|
const struct testBufAddStrData *data = opaque;
|
2020-07-02 23:35:41 +00:00
|
|
|
g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
|
2020-01-14 07:04:54 +00:00
|
|
|
g_autofree char *actual = NULL;
|
2015-03-24 09:53:29 +00:00
|
|
|
|
|
|
|
virBufferAddLit(&buf, "<c>\n");
|
|
|
|
virBufferAdjustIndent(&buf, 2);
|
|
|
|
virBufferAddStr(&buf, data->data);
|
|
|
|
virBufferAdjustIndent(&buf, -2);
|
|
|
|
virBufferAddLit(&buf, "</c>");
|
|
|
|
|
|
|
|
if (!(actual = virBufferContentAndReset(&buf))) {
|
2015-04-23 17:38:00 +00:00
|
|
|
VIR_TEST_DEBUG("buf is empty");
|
2020-01-14 07:10:25 +00:00
|
|
|
return -1;
|
2015-03-24 09:53:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (STRNEQ_NULLABLE(actual, data->expect)) {
|
2019-05-03 08:31:02 +00:00
|
|
|
VIR_TEST_DEBUG("testBufAddStr(): Strings don't match:");
|
2016-05-26 15:01:51 +00:00
|
|
|
virTestDifference(stderr, data->expect, actual);
|
2020-01-14 07:10:25 +00:00
|
|
|
return -1;
|
2015-03-24 09:53:29 +00:00
|
|
|
}
|
|
|
|
|
2020-01-14 07:10:25 +00:00
|
|
|
return 0;
|
2015-03-24 09:53:29 +00:00
|
|
|
}
|
|
|
|
|
virBuffer: add way to trim back extra text
I'm tired of writing:
bool sep = false;
while (...) {
if (sep)
virBufferAddChar(buf, ',');
sep = true;
virBufferAdd(buf, str);
}
This makes it easier, allowing one to write:
while (...)
virBufferAsprintf(buf, "%s,", str);
virBufferTrim(buf, ",", -1);
to trim any remaining comma.
* src/util/buf.h (virBufferTrim): Declare.
* src/util/buf.c (virBufferTrim): New function.
* tests/virbuftest.c (testBufTrim): Test it.
2012-05-18 22:36:59 +00:00
|
|
|
|
2015-03-30 10:41:40 +00:00
|
|
|
static int
|
2020-01-14 07:05:56 +00:00
|
|
|
testBufEscapeStr(const void *opaque)
|
2015-03-30 10:41:40 +00:00
|
|
|
{
|
|
|
|
const struct testBufAddStrData *data = opaque;
|
2020-07-02 23:35:41 +00:00
|
|
|
g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
|
2020-01-14 07:04:54 +00:00
|
|
|
g_autofree char *actual = NULL;
|
2015-03-30 10:41:40 +00:00
|
|
|
|
|
|
|
virBufferAddLit(&buf, "<c>\n");
|
|
|
|
virBufferAdjustIndent(&buf, 2);
|
|
|
|
virBufferEscapeString(&buf, "<el>%s</el>\n", data->data);
|
|
|
|
virBufferAdjustIndent(&buf, -2);
|
|
|
|
virBufferAddLit(&buf, "</c>");
|
|
|
|
|
|
|
|
if (!(actual = virBufferContentAndReset(&buf))) {
|
2015-04-23 17:38:00 +00:00
|
|
|
VIR_TEST_DEBUG("buf is empty");
|
2020-01-14 07:10:25 +00:00
|
|
|
return -1;
|
2015-03-30 10:41:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (STRNEQ_NULLABLE(actual, data->expect)) {
|
2019-05-03 08:31:02 +00:00
|
|
|
VIR_TEST_DEBUG("testBufEscapeStr(): Strings don't match:");
|
2016-05-26 15:01:51 +00:00
|
|
|
virTestDifference(stderr, data->expect, actual);
|
2020-01-14 07:10:25 +00:00
|
|
|
return -1;
|
2015-03-30 10:41:40 +00:00
|
|
|
}
|
|
|
|
|
2020-01-14 07:10:25 +00:00
|
|
|
return 0;
|
2015-03-30 10:41:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-05-12 12:26:09 +00:00
|
|
|
static int
|
|
|
|
testBufEscapeRegex(const void *opaque)
|
|
|
|
{
|
|
|
|
const struct testBufAddStrData *data = opaque;
|
2020-07-02 23:35:41 +00:00
|
|
|
g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
|
2020-01-14 07:04:54 +00:00
|
|
|
g_autofree char *actual = NULL;
|
2017-05-12 12:26:09 +00:00
|
|
|
|
|
|
|
virBufferEscapeRegex(&buf, "%s", data->data);
|
|
|
|
|
|
|
|
if (!(actual = virBufferContentAndReset(&buf))) {
|
2019-02-21 15:26:44 +00:00
|
|
|
VIR_TEST_DEBUG("testBufEscapeRegex: buf is empty");
|
2020-01-14 07:10:25 +00:00
|
|
|
return -1;
|
2017-05-12 12:26:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (STRNEQ_NULLABLE(actual, data->expect)) {
|
2019-05-03 08:31:02 +00:00
|
|
|
VIR_TEST_DEBUG("testBufEscapeRegex: Strings don't match:");
|
2017-05-12 12:26:09 +00:00
|
|
|
virTestDifference(stderr, data->expect, actual);
|
2020-01-14 07:10:25 +00:00
|
|
|
return -1;
|
2017-05-12 12:26:09 +00:00
|
|
|
}
|
|
|
|
|
2020-01-14 07:10:25 +00:00
|
|
|
return 0;
|
2017-05-12 12:26:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-03-09 16:02:19 +00:00
|
|
|
static int
|
2019-10-14 12:45:03 +00:00
|
|
|
testBufSetIndent(const void *opaque G_GNUC_UNUSED)
|
2017-03-09 16:02:19 +00:00
|
|
|
{
|
2020-07-02 23:35:41 +00:00
|
|
|
g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
|
2020-01-14 07:04:54 +00:00
|
|
|
g_autofree char *actual = NULL;
|
2017-03-09 16:02:19 +00:00
|
|
|
|
|
|
|
virBufferSetIndent(&buf, 11);
|
|
|
|
virBufferAddLit(&buf, "test\n");
|
|
|
|
virBufferSetIndent(&buf, 2);
|
|
|
|
virBufferAddLit(&buf, "test2\n");
|
|
|
|
|
|
|
|
if (!(actual = virBufferContentAndReset(&buf)))
|
2020-01-14 07:10:25 +00:00
|
|
|
return -1;
|
2017-03-09 16:02:19 +00:00
|
|
|
|
|
|
|
if (STRNEQ(actual, " test\n test2\n")) {
|
2019-05-03 08:31:02 +00:00
|
|
|
VIR_TEST_DEBUG("testBufSetIndent: expected indent not set");
|
2020-01-14 07:10:25 +00:00
|
|
|
return -1;
|
2017-03-09 16:02:19 +00:00
|
|
|
}
|
|
|
|
|
2020-01-14 07:10:25 +00:00
|
|
|
return 0;
|
2017-03-09 16:02:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-02-21 15:37:50 +00:00
|
|
|
/* Result of this shows up only in valgrind or similar */
|
|
|
|
static int
|
2019-10-14 12:45:03 +00:00
|
|
|
testBufferAutoclean(const void *opaque G_GNUC_UNUSED)
|
2019-02-21 15:37:50 +00:00
|
|
|
{
|
2019-10-15 12:47:50 +00:00
|
|
|
g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
|
2019-02-21 15:37:50 +00:00
|
|
|
|
|
|
|
virBufferAddLit(&buf, "test test test\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
buf: Fix possible infinite loop in EscapeString, VSnprintf
The current code will go into an infinite loop if the printf generated
string is >= 1000, AND exactly 1 character smaller than the amount of free
space in the buffer. When this happens, we are dropped into the loop body,
but nothing will actually change, because count == (buf->size - buf->use - 1),
and virBufferGrow returns unchanged if count < (buf->size - buf->use)
Fix this by removing the '- 1' bit from 'size'. The *nprintf functions handle
the NULL byte for us anyways, so we shouldn't need to manually accommodate
for it.
Here's a bug where we are actually hitting this issue:
https://bugzilla.redhat.com/show_bug.cgi?id=602772
v2: Eric's improvements: while -> if (), remove extra va_list variable,
make sure we report buffer error if snprintf fails
v3: Add tests/virbuftest which reproduces the infinite loop before this
patch, works correctly after
2010-09-01 17:51:35 +00:00
|
|
|
static int
|
2011-04-29 16:21:20 +00:00
|
|
|
mymain(void)
|
buf: Fix possible infinite loop in EscapeString, VSnprintf
The current code will go into an infinite loop if the printf generated
string is >= 1000, AND exactly 1 character smaller than the amount of free
space in the buffer. When this happens, we are dropped into the loop body,
but nothing will actually change, because count == (buf->size - buf->use - 1),
and virBufferGrow returns unchanged if count < (buf->size - buf->use)
Fix this by removing the '- 1' bit from 'size'. The *nprintf functions handle
the NULL byte for us anyways, so we shouldn't need to manually accommodate
for it.
Here's a bug where we are actually hitting this issue:
https://bugzilla.redhat.com/show_bug.cgi?id=602772
v2: Eric's improvements: while -> if (), remove extra va_list variable,
make sure we report buffer error if snprintf fails
v3: Add tests/virbuftest which reproduces the infinite loop before this
patch, works correctly after
2010-09-01 17:51:35 +00:00
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
|
2019-10-24 10:18:13 +00:00
|
|
|
#define DO_TEST(msg, cb) \
|
2017-11-03 12:09:47 +00:00
|
|
|
do { \
|
2019-10-24 10:18:13 +00:00
|
|
|
if (virTestRun("Buf: " msg, cb, NULL) < 0) \
|
2017-11-03 12:09:47 +00:00
|
|
|
ret = -1; \
|
buf: Fix possible infinite loop in EscapeString, VSnprintf
The current code will go into an infinite loop if the printf generated
string is >= 1000, AND exactly 1 character smaller than the amount of free
space in the buffer. When this happens, we are dropped into the loop body,
but nothing will actually change, because count == (buf->size - buf->use - 1),
and virBufferGrow returns unchanged if count < (buf->size - buf->use)
Fix this by removing the '- 1' bit from 'size'. The *nprintf functions handle
the NULL byte for us anyways, so we shouldn't need to manually accommodate
for it.
Here's a bug where we are actually hitting this issue:
https://bugzilla.redhat.com/show_bug.cgi?id=602772
v2: Eric's improvements: while -> if (), remove extra va_list variable,
make sure we report buffer error if snprintf fails
v3: Add tests/virbuftest which reproduces the infinite loop before this
patch, works correctly after
2010-09-01 17:51:35 +00:00
|
|
|
} while (0)
|
|
|
|
|
2019-10-24 10:18:13 +00:00
|
|
|
DO_TEST("Auto-indentation", testBufAutoIndent);
|
|
|
|
DO_TEST("Trim", testBufTrim);
|
|
|
|
DO_TEST("AddBuffer", testBufAddBuffer);
|
|
|
|
DO_TEST("set indent", testBufSetIndent);
|
|
|
|
DO_TEST("autoclean", testBufferAutoclean);
|
buf: Fix possible infinite loop in EscapeString, VSnprintf
The current code will go into an infinite loop if the printf generated
string is >= 1000, AND exactly 1 character smaller than the amount of free
space in the buffer. When this happens, we are dropped into the loop body,
but nothing will actually change, because count == (buf->size - buf->use - 1),
and virBufferGrow returns unchanged if count < (buf->size - buf->use)
Fix this by removing the '- 1' bit from 'size'. The *nprintf functions handle
the NULL byte for us anyways, so we shouldn't need to manually accommodate
for it.
Here's a bug where we are actually hitting this issue:
https://bugzilla.redhat.com/show_bug.cgi?id=602772
v2: Eric's improvements: while -> if (), remove extra va_list variable,
make sure we report buffer error if snprintf fails
v3: Add tests/virbuftest which reproduces the infinite loop before this
patch, works correctly after
2010-09-01 17:51:35 +00:00
|
|
|
|
2020-01-14 07:06:34 +00:00
|
|
|
#define DO_TEST_ADD_STR(_data, _expect) \
|
2017-11-03 12:09:47 +00:00
|
|
|
do { \
|
2020-01-14 07:06:34 +00:00
|
|
|
struct testBufAddStrData info = { .data = _data, .expect = _expect }; \
|
2017-11-03 12:09:47 +00:00
|
|
|
if (virTestRun("Buf: AddStr", testBufAddStr, &info) < 0) \
|
|
|
|
ret = -1; \
|
2015-03-24 09:53:29 +00:00
|
|
|
} while (0)
|
|
|
|
|
|
|
|
DO_TEST_ADD_STR("", "<c>\n</c>");
|
|
|
|
DO_TEST_ADD_STR("<a/>", "<c>\n <a/></c>");
|
|
|
|
DO_TEST_ADD_STR("<a/>\n", "<c>\n <a/>\n</c>");
|
|
|
|
DO_TEST_ADD_STR("<b>\n <a/>\n</b>\n", "<c>\n <b>\n <a/>\n </b>\n</c>");
|
|
|
|
|
2020-01-14 07:06:34 +00:00
|
|
|
#define DO_TEST_ESCAPE(_data, _expect) \
|
2017-11-03 12:09:47 +00:00
|
|
|
do { \
|
2020-01-14 07:06:34 +00:00
|
|
|
struct testBufAddStrData info = { .data = _data, .expect = _expect }; \
|
2016-05-26 15:01:50 +00:00
|
|
|
if (virTestRun("Buf: EscapeStr", testBufEscapeStr, &info) < 0) \
|
2017-11-03 12:09:47 +00:00
|
|
|
ret = -1; \
|
2015-03-30 10:41:40 +00:00
|
|
|
} while (0)
|
|
|
|
|
|
|
|
DO_TEST_ESCAPE("<td></td><td></td>",
|
|
|
|
"<c>\n <el><td></td><td></td></el>\n</c>");
|
|
|
|
DO_TEST_ESCAPE("\007\"&&\"\x15",
|
|
|
|
"<c>\n <el>"&&"</el>\n</c>");
|
|
|
|
DO_TEST_ESCAPE(",,'..',,",
|
|
|
|
"<c>\n <el>,,'..',,</el>\n</c>");
|
|
|
|
DO_TEST_ESCAPE("\x01\x01\x02\x03\x05\x08",
|
|
|
|
"<c>\n <el></el>\n</c>");
|
|
|
|
|
2020-01-14 07:06:34 +00:00
|
|
|
#define DO_TEST_ESCAPE_REGEX(_data, _expect) \
|
2017-11-03 12:09:47 +00:00
|
|
|
do { \
|
2020-01-14 07:06:34 +00:00
|
|
|
struct testBufAddStrData info = { .data = _data, .expect = _expect }; \
|
2017-11-03 12:09:47 +00:00
|
|
|
if (virTestRun("Buf: EscapeRegex", testBufEscapeRegex, &info) < 0) \
|
|
|
|
ret = -1; \
|
2017-05-12 12:26:09 +00:00
|
|
|
} while (0)
|
|
|
|
|
|
|
|
DO_TEST_ESCAPE_REGEX("noescape", "noescape");
|
|
|
|
DO_TEST_ESCAPE_REGEX("^$.|?*+()[]{}\\",
|
|
|
|
"\\^\\$\\.\\|\\?\\*\\+\\(\\)\\[\\]\\{\\}\\\\");
|
|
|
|
|
2020-01-14 07:04:14 +00:00
|
|
|
#define DO_TEST_TRIM_CHARS(_data, _arg, _expect) \
|
|
|
|
do { \
|
|
|
|
struct testBufAddStrData info = { .data = _data, .expect = _expect, .arg = _arg }; \
|
|
|
|
if (virTestRun("Buf: Trim: " #_data, testBufTrimChars, &info) < 0) \
|
|
|
|
ret = -1; \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
DO_TEST_TRIM_CHARS("Trimmm", "m", "Tri");
|
|
|
|
DO_TEST_TRIM_CHARS("-abcd-efgh--", "-", "-abcd-efgh");
|
|
|
|
DO_TEST_TRIM_CHARS("-hABC-efgh--", "-h", "-hABC-efg");
|
|
|
|
|
2014-03-17 09:38:38 +00:00
|
|
|
return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
|
buf: Fix possible infinite loop in EscapeString, VSnprintf
The current code will go into an infinite loop if the printf generated
string is >= 1000, AND exactly 1 character smaller than the amount of free
space in the buffer. When this happens, we are dropped into the loop body,
but nothing will actually change, because count == (buf->size - buf->use - 1),
and virBufferGrow returns unchanged if count < (buf->size - buf->use)
Fix this by removing the '- 1' bit from 'size'. The *nprintf functions handle
the NULL byte for us anyways, so we shouldn't need to manually accommodate
for it.
Here's a bug where we are actually hitting this issue:
https://bugzilla.redhat.com/show_bug.cgi?id=602772
v2: Eric's improvements: while -> if (), remove extra va_list variable,
make sure we report buffer error if snprintf fails
v3: Add tests/virbuftest which reproduces the infinite loop before this
patch, works correctly after
2010-09-01 17:51:35 +00:00
|
|
|
}
|
|
|
|
|
2017-03-29 14:45:42 +00:00
|
|
|
VIR_TEST_MAIN(mymain)
|