libqtest: escape strings in QMP commands, fix leak
libqtest is using g_strdup_printf to format QMP commands, but this does not work if the argument strings need to be escaped. Instead, use the fancy %-formatting functionality of QObject. The only change required in tests is that strings have to be formatted as %s, not '%s' or \"%s\". Luckily this usage of parameterized QMP commands is not that frequent. The leak is in socket_sendf. Since we are extracting the send loop to a new function, fix it now. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
8ffad850ef
commit
563890c7c7
@ -291,7 +291,7 @@ static void test_media_insert(void)
|
||||
/* Insert media in drive. DSKCHK should not be reset until a step pulse
|
||||
* is sent. */
|
||||
qmp_discard_response("{'execute':'change', 'arguments':{"
|
||||
" 'device':'floppy0', 'target': '%s' }}",
|
||||
" 'device':'floppy0', 'target': %s }}",
|
||||
test_image);
|
||||
qmp_discard_response(""); /* ignore event
|
||||
(FIXME open -> open transition?!) */
|
||||
|
@ -30,8 +30,9 @@
|
||||
|
||||
#include "qemu/compiler.h"
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/qmp/json-streamer.h"
|
||||
#include "qapi/qmp/json-parser.h"
|
||||
#include "qapi/qmp/json-streamer.h"
|
||||
#include "qapi/qmp/qjson.h"
|
||||
|
||||
#define MAX_IRQ 256
|
||||
#define SOCKET_TIMEOUT 5
|
||||
@ -220,19 +221,15 @@ void qtest_quit(QTestState *s)
|
||||
g_free(s);
|
||||
}
|
||||
|
||||
static void socket_sendf(int fd, const char *fmt, va_list ap)
|
||||
static void socket_send(int fd, const char *buf, size_t size)
|
||||
{
|
||||
gchar *str;
|
||||
size_t size, offset;
|
||||
|
||||
str = g_strdup_vprintf(fmt, ap);
|
||||
size = strlen(str);
|
||||
size_t offset;
|
||||
|
||||
offset = 0;
|
||||
while (offset < size) {
|
||||
ssize_t len;
|
||||
|
||||
len = write(fd, str + offset, size - offset);
|
||||
len = write(fd, buf + offset, size - offset);
|
||||
if (len == -1 && errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
@ -244,6 +241,15 @@ static void socket_sendf(int fd, const char *fmt, va_list ap)
|
||||
}
|
||||
}
|
||||
|
||||
static void socket_sendf(int fd, const char *fmt, va_list ap)
|
||||
{
|
||||
gchar *str = g_strdup_vprintf(fmt, ap);
|
||||
size_t size = strlen(str);
|
||||
|
||||
socket_send(fd, str, size);
|
||||
g_free(str);
|
||||
}
|
||||
|
||||
static void GCC_FMT_ATTR(2, 3) qtest_sendf(QTestState *s, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
@ -378,8 +384,29 @@ QDict *qtest_qmp_receive(QTestState *s)
|
||||
|
||||
QDict *qtest_qmpv(QTestState *s, const char *fmt, va_list ap)
|
||||
{
|
||||
/* Send QMP request */
|
||||
socket_sendf(s->qmp_fd, fmt, ap);
|
||||
va_list ap_copy;
|
||||
QObject *qobj;
|
||||
|
||||
/* Going through qobject ensures we escape strings properly.
|
||||
* This seemingly unnecessary copy is required in case va_list
|
||||
* is an array type.
|
||||
*/
|
||||
va_copy(ap_copy, ap);
|
||||
qobj = qobject_from_jsonv(fmt, &ap_copy);
|
||||
va_end(ap_copy);
|
||||
|
||||
/* No need to send anything for an empty QObject. */
|
||||
if (qobj) {
|
||||
QString *qstr = qobject_to_json(qobj);
|
||||
const char *str = qstring_get_str(qstr);
|
||||
size_t size = qstring_get_length(qstr);
|
||||
|
||||
/* Send QMP request */
|
||||
socket_send(s->qmp_fd, str, size);
|
||||
|
||||
QDECREF(qstr);
|
||||
qobject_decref(qobj);
|
||||
}
|
||||
|
||||
/* Receive reply */
|
||||
return qtest_qmp_receive(s);
|
||||
|
@ -53,7 +53,7 @@ static void test_properties(const char *path, bool recurse)
|
||||
|
||||
g_test_message("Obtaining properties of %s", path);
|
||||
response = qmp("{ 'execute': 'qom-list',"
|
||||
" 'arguments': { 'path': '%s' } }", path);
|
||||
" 'arguments': { 'path': %s } }", path);
|
||||
g_assert(response);
|
||||
|
||||
if (!recurse) {
|
||||
@ -76,8 +76,8 @@ static void test_properties(const char *path, bool recurse)
|
||||
const char *prop = qdict_get_str(tuple, "name");
|
||||
g_test_message("Testing property %s.%s", path, prop);
|
||||
response = qmp("{ 'execute': 'qom-get',"
|
||||
" 'arguments': { 'path': '%s',"
|
||||
" 'property': '%s' } }",
|
||||
" 'arguments': { 'path': %s,"
|
||||
" 'property': %s } }",
|
||||
path, prop);
|
||||
/* qom-get may fail but should not, e.g., segfault. */
|
||||
g_assert(response);
|
||||
|
@ -69,7 +69,7 @@ static int qmp_tmp105_get_temperature(const char *id)
|
||||
QDict *response;
|
||||
int ret;
|
||||
|
||||
response = qmp("{ 'execute': 'qom-get', 'arguments': { 'path': '%s', "
|
||||
response = qmp("{ 'execute': 'qom-get', 'arguments': { 'path': %s, "
|
||||
"'property': 'temperature' } }", id);
|
||||
g_assert(qdict_haskey(response, "return"));
|
||||
ret = qdict_get_int(response, "return");
|
||||
@ -81,7 +81,7 @@ static void qmp_tmp105_set_temperature(const char *id, int value)
|
||||
{
|
||||
QDict *response;
|
||||
|
||||
response = qmp("{ 'execute': 'qom-set', 'arguments': { 'path': '%s', "
|
||||
response = qmp("{ 'execute': 'qom-set', 'arguments': { 'path': %s, "
|
||||
"'property': 'temperature', 'value': %d } }", id, value);
|
||||
g_assert(qdict_haskey(response, "return"));
|
||||
QDECREF(response);
|
||||
|
Loading…
Reference in New Issue
Block a user