qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH] libqtest: escape strings in QMP commands, fix l


From: Amos Kong
Subject: Re: [Qemu-devel] [PATCH] libqtest: escape strings in QMP commands, fix leak
Date: Wed, 18 Jun 2014 15:41:58 +0800
User-agent: Mutt/1.5.23 (2014-03-12)

- Fixed Andreas's mail address

On Fri, Jun 13, 2014 at 10:15:00AM +0200, Paolo Bonzini wrote:
> 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.

I got this error when I apply this patch (it works without this
patch):

  {"error": {"class": "GenericError", "desc": "Parameter 'id' expects an 
identifier"}}

Code:
|    QDict *response;
|    int i, j;
|
|    /* start with no network/block device, slots 3 to 0x1f are free */
|    qtest_start("-net none");
|
|    for (i = 3; i <= 0x1f; i++) {
|        for (j = 7; j >= 0; j--) {
|            response = qmp("{ 'execute': 'blockdev-add',"
|                           " 'arguments': {"
|                           "   'options': {"
|                           "     'driver': 'file',"
|                           "     'filename': '/dev/null',"
|                           "     'id': 'drv-%x.%x'"
                                         ^^^^^^^^^
|                           "} } }", i, j);
|            g_assert(response);
|            g_assert(!qdict_haskey(response, "error"));
|            QDECREF(response);



Then I have to fix it by :

     /* start with no network/block device, slots 3 to 0x1f are free */
     qtest_start("-net none");
 
     for (i = 3; i <= 0x1f; i++) {
         for (j = 7; j >= 0; j--) {
+            sprintf(drive_id, "drv-%x.%x", i, j);
             response = qmp("{ 'execute': 'blockdev-add',"
                            " 'arguments': {"
                            "   'options': {"
                            "     'driver': 'file',"
                            "     'filename': '/dev/null',"
-                           "     'id': 'drv-%x.%x'"
-                           "} } }", i, j);
+                           "     'id': %s"
+                           "} } }", drive_id);


Is it the expected result?


Thanks, Amos
 
> 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 <address@hidden>
> ---
>  tests/fdc-test.c    |  2 +-
>  tests/libqtest.c    | 47 +++++++++++++++++++++++++++++++++++++----------
>  tests/qom-test.c    |  6 +++---
>  tests/tmp105-test.c |  4 ++--
>  4 files changed, 43 insertions(+), 16 deletions(-)
> 
> diff --git a/tests/fdc-test.c b/tests/fdc-test.c
> index 37096dc..c8e1e7b 100644
> --- a/tests/fdc-test.c
> +++ b/tests/fdc-test.c
> @@ -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?!) */
> diff --git a/tests/libqtest.c b/tests/libqtest.c
> index 71468ac..98e8f4b 100644
> --- a/tests/libqtest.c
> +++ b/tests/libqtest.c
> @@ -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);
> diff --git a/tests/qom-test.c b/tests/qom-test.c
> index d8d1d8d..4246382 100644
> --- a/tests/qom-test.c
> +++ b/tests/qom-test.c
> @@ -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);
> diff --git a/tests/tmp105-test.c b/tests/tmp105-test.c
> index 15ddaf3..99db538 100644
> --- a/tests/tmp105-test.c
> +++ b/tests/tmp105-test.c
> @@ -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);
> -- 
> 1.8.3.1
> 

-- 
                        Amos.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]