255e5e
From 0b97bae6cad6c7da8cd0f489249f140615b0b07e Mon Sep 17 00:00:00 2001
255e5e
From: jmaloy <jmaloy@redhat.com>
255e5e
Date: Thu, 7 May 2020 21:51:48 +0100
255e5e
Subject: [PATCH 2/2] vnc: fix memory leak when vnc disconnect
255e5e
MIME-Version: 1.0
255e5e
Content-Type: text/plain; charset=UTF-8
255e5e
Content-Transfer-Encoding: 8bit
255e5e
255e5e
RH-Author: jmaloy <jmaloy@redhat.com>
255e5e
Message-id: <20200507215148.1201876-3-jmaloy@redhat.com>
255e5e
Patchwork-id: 96345
255e5e
O-Subject: [RHEL-8.2.0 qemu-kvm PATCH 2/2] vnc: fix memory leak when vnc disconnect
255e5e
Bugzilla: 1816763
255e5e
RH-Acked-by: Gerd Hoffmann <kraxel@redhat.com>
255e5e
RH-Acked-by: Danilo de Paula <ddepaula@redhat.com>
255e5e
RH-Acked-by: Philippe Mathieu-Daudé <philmd@redhat.com>
255e5e
RH-Acked-by: Daniel P. Berrange <berrange@redhat.com>
255e5e
255e5e
From: Li Qiang <liq3ea@163.com>
255e5e
255e5e
Currently when qemu receives a vnc connect, it creates a 'VncState' to
255e5e
represent this connection. In 'vnc_worker_thread_loop' it creates a
255e5e
local 'VncState'. The connection 'VcnState' and local 'VncState' exchange
255e5e
data in 'vnc_async_encoding_start' and 'vnc_async_encoding_end'.
255e5e
In 'zrle_compress_data' it calls 'deflateInit2' to allocate the libz library
255e5e
opaque data. The 'VncState' used in 'zrle_compress_data' is the local
255e5e
'VncState'. In 'vnc_zrle_clear' it calls 'deflateEnd' to free the libz
255e5e
library opaque data. The 'VncState' used in 'vnc_zrle_clear' is the connection
255e5e
'VncState'. In currently implementation there will be a memory leak when the
255e5e
vnc disconnect. Following is the asan output backtrack:
255e5e
255e5e
Direct leak of 29760 byte(s) in 5 object(s) allocated from:
255e5e
    0 0xffffa67ef3c3 in __interceptor_calloc (/lib64/libasan.so.4+0xd33c3)
255e5e
    1 0xffffa65071cb in g_malloc0 (/lib64/libglib-2.0.so.0+0x571cb)
255e5e
    2 0xffffa5e968f7 in deflateInit2_ (/lib64/libz.so.1+0x78f7)
255e5e
    3 0xaaaacec58613 in zrle_compress_data ui/vnc-enc-zrle.c:87
255e5e
    4 0xaaaacec58613 in zrle_send_framebuffer_update ui/vnc-enc-zrle.c:344
255e5e
    5 0xaaaacec34e77 in vnc_send_framebuffer_update ui/vnc.c:919
255e5e
    6 0xaaaacec5e023 in vnc_worker_thread_loop ui/vnc-jobs.c:271
255e5e
    7 0xaaaacec5e5e7 in vnc_worker_thread ui/vnc-jobs.c:340
255e5e
    8 0xaaaacee4d3c3 in qemu_thread_start util/qemu-thread-posix.c:502
255e5e
    9 0xffffa544e8bb in start_thread (/lib64/libpthread.so.0+0x78bb)
255e5e
    10 0xffffa53965cb in thread_start (/lib64/libc.so.6+0xd55cb)
255e5e
255e5e
This is because the opaque allocated in 'deflateInit2' is not freed in
255e5e
'deflateEnd'. The reason is that the 'deflateEnd' calls 'deflateStateCheck'
255e5e
and in the latter will check whether 's->strm != strm'(libz's data structure).
255e5e
This check will be true so in 'deflateEnd' it just return 'Z_STREAM_ERROR' and
255e5e
not free the data allocated in 'deflateInit2'.
255e5e
255e5e
The reason this happens is that the 'VncState' contains the whole 'VncZrle',
255e5e
so when calling 'deflateInit2', the 's->strm' will be the local address.
255e5e
So 's->strm != strm' will be true.
255e5e
255e5e
To fix this issue, we need to make 'zrle' of 'VncState' to be a pointer.
255e5e
Then the connection 'VncState' and local 'VncState' exchange mechanism will
255e5e
work as expection. The 'tight' of 'VncState' has the same issue, let's also turn
255e5e
it to a pointer.
255e5e
255e5e
Reported-by: Ying Fang <fangying1@huawei.com>
255e5e
Signed-off-by: Li Qiang <liq3ea@163.com>
255e5e
Message-id: 20190831153922.121308-1-liq3ea@163.com
255e5e
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
255e5e
255e5e
(cherry picked from commit 6bf21f3d83e95bcc4ba35a7a07cc6655e8b010b0)
255e5e
Signed-off-by: Jon Maloy <jmaloy@redhat.com>
255e5e
Signed-off-by: Danilo C. L. de Paula <ddepaula@redhat.com>
255e5e
---
255e5e
 ui/vnc-enc-tight.c         | 219 +++++++++++++++++++++++----------------------
255e5e
 ui/vnc-enc-zlib.c          |  11 +--
255e5e
 ui/vnc-enc-zrle-template.c |   2 +-
255e5e
 ui/vnc-enc-zrle.c          |  68 +++++++-------
255e5e
 ui/vnc.c                   |  28 +++---
255e5e
 ui/vnc.h                   |   4 +-
255e5e
 6 files changed, 170 insertions(+), 162 deletions(-)
255e5e
255e5e
diff --git a/ui/vnc-enc-tight.c b/ui/vnc-enc-tight.c
255e5e
index f38aceb..9ce2b42 100644
255e5e
--- a/ui/vnc-enc-tight.c
255e5e
+++ b/ui/vnc-enc-tight.c
255e5e
@@ -117,7 +117,7 @@ static int send_png_rect(VncState *vs, int x, int y, int w, int h,
255e5e
 
255e5e
 static bool tight_can_send_png_rect(VncState *vs, int w, int h)
255e5e
 {
255e5e
-    if (vs->tight.type != VNC_ENCODING_TIGHT_PNG) {
255e5e
+    if (vs->tight->type != VNC_ENCODING_TIGHT_PNG) {
255e5e
         return false;
255e5e
     }
255e5e
 
255e5e
@@ -145,7 +145,7 @@ tight_detect_smooth_image24(VncState *vs, int w, int h)
255e5e
     int pixels = 0;
255e5e
     int pix, left[3];
255e5e
     unsigned int errors;
255e5e
-    unsigned char *buf = vs->tight.tight.buffer;
255e5e
+    unsigned char *buf = vs->tight->tight.buffer;
255e5e
 
255e5e
     /*
255e5e
      * If client is big-endian, color samples begin from the second
255e5e
@@ -216,7 +216,7 @@ tight_detect_smooth_image24(VncState *vs, int w, int h)
255e5e
         int pixels = 0;                                                 \
255e5e
         int sample, sum, left[3];                                       \
255e5e
         unsigned int errors;                                            \
255e5e
-        unsigned char *buf = vs->tight.tight.buffer;                    \
255e5e
+        unsigned char *buf = vs->tight->tight.buffer;                    \
255e5e
                                                                         \
255e5e
         endian = 0; /* FIXME */                                         \
255e5e
                                                                         \
255e5e
@@ -297,8 +297,8 @@ static int
255e5e
 tight_detect_smooth_image(VncState *vs, int w, int h)
255e5e
 {
255e5e
     unsigned int errors;
255e5e
-    int compression = vs->tight.compression;
255e5e
-    int quality = vs->tight.quality;
255e5e
+    int compression = vs->tight->compression;
255e5e
+    int quality = vs->tight->quality;
255e5e
 
255e5e
     if (!vs->vd->lossy) {
255e5e
         return 0;
255e5e
@@ -310,7 +310,7 @@ tight_detect_smooth_image(VncState *vs, int w, int h)
255e5e
         return 0;
255e5e
     }
255e5e
 
255e5e
-    if (vs->tight.quality != (uint8_t)-1) {
255e5e
+    if (vs->tight->quality != (uint8_t)-1) {
255e5e
         if (w * h < VNC_TIGHT_JPEG_MIN_RECT_SIZE) {
255e5e
             return 0;
255e5e
         }
255e5e
@@ -321,9 +321,9 @@ tight_detect_smooth_image(VncState *vs, int w, int h)
255e5e
     }
255e5e
 
255e5e
     if (vs->client_pf.bytes_per_pixel == 4) {
255e5e
-        if (vs->tight.pixel24) {
255e5e
+        if (vs->tight->pixel24) {
255e5e
             errors = tight_detect_smooth_image24(vs, w, h);
255e5e
-            if (vs->tight.quality != (uint8_t)-1) {
255e5e
+            if (vs->tight->quality != (uint8_t)-1) {
255e5e
                 return (errors < tight_conf[quality].jpeg_threshold24);
255e5e
             }
255e5e
             return (errors < tight_conf[compression].gradient_threshold24);
255e5e
@@ -353,7 +353,7 @@ tight_detect_smooth_image(VncState *vs, int w, int h)
255e5e
         uint##bpp##_t c0, c1, ci;                                       \
255e5e
         int i, n0, n1;                                                  \
255e5e
                                                                         \
255e5e
-        data = (uint##bpp##_t *)vs->tight.tight.buffer;                 \
255e5e
+        data = (uint##bpp##_t *)vs->tight->tight.buffer;                \
255e5e
                                                                         \
255e5e
         c0 = data[0];                                                   \
255e5e
         i = 1;                                                          \
255e5e
@@ -424,9 +424,9 @@ static int tight_fill_palette(VncState *vs, int x, int y,
255e5e
 {
255e5e
     int max;
255e5e
 
255e5e
-    max = count / tight_conf[vs->tight.compression].idx_max_colors_divisor;
255e5e
+    max = count / tight_conf[vs->tight->compression].idx_max_colors_divisor;
255e5e
     if (max < 2 &&
255e5e
-        count >= tight_conf[vs->tight.compression].mono_min_rect_size) {
255e5e
+        count >= tight_conf[vs->tight->compression].mono_min_rect_size) {
255e5e
         max = 2;
255e5e
     }
255e5e
     if (max >= 256) {
255e5e
@@ -559,7 +559,7 @@ tight_filter_gradient24(VncState *vs, uint8_t *buf, int w, int h)
255e5e
     int x, y, c;
255e5e
 
255e5e
     buf32 = (uint32_t *)buf;
255e5e
-    memset(vs->tight.gradient.buffer, 0, w * 3 * sizeof(int));
255e5e
+    memset(vs->tight->gradient.buffer, 0, w * 3 * sizeof(int));
255e5e
 
255e5e
     if (1 /* FIXME */) {
255e5e
         shift[0] = vs->client_pf.rshift;
255e5e
@@ -576,7 +576,7 @@ tight_filter_gradient24(VncState *vs, uint8_t *buf, int w, int h)
255e5e
             upper[c] = 0;
255e5e
             here[c] = 0;
255e5e
         }
255e5e
-        prev = (int *)vs->tight.gradient.buffer;
255e5e
+        prev = (int *)vs->tight->gradient.buffer;
255e5e
         for (x = 0; x < w; x++) {
255e5e
             pix32 = *buf32++;
255e5e
             for (c = 0; c < 3; c++) {
255e5e
@@ -616,7 +616,7 @@ tight_filter_gradient24(VncState *vs, uint8_t *buf, int w, int h)
255e5e
         int prediction;                                                 \
255e5e
         int x, y, c;                                                    \
255e5e
                                                                         \
255e5e
-        memset (vs->tight.gradient.buffer, 0, w * 3 * sizeof(int));     \
255e5e
+        memset(vs->tight->gradient.buffer, 0, w * 3 * sizeof(int));     \
255e5e
                                                                         \
255e5e
         endian = 0; /* FIXME */                                         \
255e5e
                                                                         \
255e5e
@@ -632,7 +632,7 @@ tight_filter_gradient24(VncState *vs, uint8_t *buf, int w, int h)
255e5e
                 upper[c] = 0;                                           \
255e5e
                 here[c] = 0;                                            \
255e5e
             }                                                           \
255e5e
-            prev = (int *)vs->tight.gradient.buffer;                    \
255e5e
+            prev = (int *)vs->tight->gradient.buffer;                    \
255e5e
             for (x = 0; x < w; x++) {                                   \
255e5e
                 pix = *buf;                                             \
255e5e
                 if (endian) {                                           \
255e5e
@@ -786,7 +786,7 @@ static void extend_solid_area(VncState *vs, int x, int y, int w, int h,
255e5e
 static int tight_init_stream(VncState *vs, int stream_id,
255e5e
                              int level, int strategy)
255e5e
 {
255e5e
-    z_streamp zstream = &vs->tight.stream[stream_id];
255e5e
+    z_streamp zstream = &vs->tight->stream[stream_id];
255e5e
 
255e5e
     if (zstream->opaque == NULL) {
255e5e
         int err;
255e5e
@@ -804,15 +804,15 @@ static int tight_init_stream(VncState *vs, int stream_id,
255e5e
             return -1;
255e5e
         }
255e5e
 
255e5e
-        vs->tight.levels[stream_id] = level;
255e5e
+        vs->tight->levels[stream_id] = level;
255e5e
         zstream->opaque = vs;
255e5e
     }
255e5e
 
255e5e
-    if (vs->tight.levels[stream_id] != level) {
255e5e
+    if (vs->tight->levels[stream_id] != level) {
255e5e
         if (deflateParams(zstream, level, strategy) != Z_OK) {
255e5e
             return -1;
255e5e
         }
255e5e
-        vs->tight.levels[stream_id] = level;
255e5e
+        vs->tight->levels[stream_id] = level;
255e5e
     }
255e5e
     return 0;
255e5e
 }
255e5e
@@ -840,11 +840,11 @@ static void tight_send_compact_size(VncState *vs, size_t len)
255e5e
 static int tight_compress_data(VncState *vs, int stream_id, size_t bytes,
255e5e
                                int level, int strategy)
255e5e
 {
255e5e
-    z_streamp zstream = &vs->tight.stream[stream_id];
255e5e
+    z_streamp zstream = &vs->tight->stream[stream_id];
255e5e
     int previous_out;
255e5e
 
255e5e
     if (bytes < VNC_TIGHT_MIN_TO_COMPRESS) {
255e5e
-        vnc_write(vs, vs->tight.tight.buffer, vs->tight.tight.offset);
255e5e
+        vnc_write(vs, vs->tight->tight.buffer, vs->tight->tight.offset);
255e5e
         return bytes;
255e5e
     }
255e5e
 
255e5e
@@ -853,13 +853,13 @@ static int tight_compress_data(VncState *vs, int stream_id, size_t bytes,
255e5e
     }
255e5e
 
255e5e
     /* reserve memory in output buffer */
255e5e
-    buffer_reserve(&vs->tight.zlib, bytes + 64);
255e5e
+    buffer_reserve(&vs->tight->zlib, bytes + 64);
255e5e
 
255e5e
     /* set pointers */
255e5e
-    zstream->next_in = vs->tight.tight.buffer;
255e5e
-    zstream->avail_in = vs->tight.tight.offset;
255e5e
-    zstream->next_out = vs->tight.zlib.buffer + vs->tight.zlib.offset;
255e5e
-    zstream->avail_out = vs->tight.zlib.capacity - vs->tight.zlib.offset;
255e5e
+    zstream->next_in = vs->tight->tight.buffer;
255e5e
+    zstream->avail_in = vs->tight->tight.offset;
255e5e
+    zstream->next_out = vs->tight->zlib.buffer + vs->tight->zlib.offset;
255e5e
+    zstream->avail_out = vs->tight->zlib.capacity - vs->tight->zlib.offset;
255e5e
     previous_out = zstream->avail_out;
255e5e
     zstream->data_type = Z_BINARY;
255e5e
 
255e5e
@@ -869,14 +869,14 @@ static int tight_compress_data(VncState *vs, int stream_id, size_t bytes,
255e5e
         return -1;
255e5e
     }
255e5e
 
255e5e
-    vs->tight.zlib.offset = vs->tight.zlib.capacity - zstream->avail_out;
255e5e
+    vs->tight->zlib.offset = vs->tight->zlib.capacity - zstream->avail_out;
255e5e
     /* ...how much data has actually been produced by deflate() */
255e5e
     bytes = previous_out - zstream->avail_out;
255e5e
 
255e5e
     tight_send_compact_size(vs, bytes);
255e5e
-    vnc_write(vs, vs->tight.zlib.buffer, bytes);
255e5e
+    vnc_write(vs, vs->tight->zlib.buffer, bytes);
255e5e
 
255e5e
-    buffer_reset(&vs->tight.zlib);
255e5e
+    buffer_reset(&vs->tight->zlib);
255e5e
 
255e5e
     return bytes;
255e5e
 }
255e5e
@@ -927,16 +927,17 @@ static int send_full_color_rect(VncState *vs, int x, int y, int w, int h)
255e5e
 
255e5e
     vnc_write_u8(vs, stream << 4); /* no flushing, no filter */
255e5e
 
255e5e
-    if (vs->tight.pixel24) {
255e5e
-        tight_pack24(vs, vs->tight.tight.buffer, w * h, &vs->tight.tight.offset);
255e5e
+    if (vs->tight->pixel24) {
255e5e
+        tight_pack24(vs, vs->tight->tight.buffer, w * h,
255e5e
+                     &vs->tight->tight.offset);
255e5e
         bytes = 3;
255e5e
     } else {
255e5e
         bytes = vs->client_pf.bytes_per_pixel;
255e5e
     }
255e5e
 
255e5e
     bytes = tight_compress_data(vs, stream, w * h * bytes,
255e5e
-                                tight_conf[vs->tight.compression].raw_zlib_level,
255e5e
-                                Z_DEFAULT_STRATEGY);
255e5e
+                            tight_conf[vs->tight->compression].raw_zlib_level,
255e5e
+                            Z_DEFAULT_STRATEGY);
255e5e
 
255e5e
     return (bytes >= 0);
255e5e
 }
255e5e
@@ -947,14 +948,14 @@ static int send_solid_rect(VncState *vs)
255e5e
 
255e5e
     vnc_write_u8(vs, VNC_TIGHT_FILL << 4); /* no flushing, no filter */
255e5e
 
255e5e
-    if (vs->tight.pixel24) {
255e5e
-        tight_pack24(vs, vs->tight.tight.buffer, 1, &vs->tight.tight.offset);
255e5e
+    if (vs->tight->pixel24) {
255e5e
+        tight_pack24(vs, vs->tight->tight.buffer, 1, &vs->tight->tight.offset);
255e5e
         bytes = 3;
255e5e
     } else {
255e5e
         bytes = vs->client_pf.bytes_per_pixel;
255e5e
     }
255e5e
 
255e5e
-    vnc_write(vs, vs->tight.tight.buffer, bytes);
255e5e
+    vnc_write(vs, vs->tight->tight.buffer, bytes);
255e5e
     return 1;
255e5e
 }
255e5e
 
255e5e
@@ -963,7 +964,7 @@ static int send_mono_rect(VncState *vs, int x, int y,
255e5e
 {
255e5e
     ssize_t bytes;
255e5e
     int stream = 1;
255e5e
-    int level = tight_conf[vs->tight.compression].mono_zlib_level;
255e5e
+    int level = tight_conf[vs->tight->compression].mono_zlib_level;
255e5e
 
255e5e
 #ifdef CONFIG_VNC_PNG
255e5e
     if (tight_can_send_png_rect(vs, w, h)) {
255e5e
@@ -991,26 +992,26 @@ static int send_mono_rect(VncState *vs, int x, int y,
255e5e
         uint32_t buf[2] = {bg, fg};
255e5e
         size_t ret = sizeof (buf);
255e5e
 
255e5e
-        if (vs->tight.pixel24) {
255e5e
+        if (vs->tight->pixel24) {
255e5e
             tight_pack24(vs, (unsigned char*)buf, 2, &ret;;
255e5e
         }
255e5e
         vnc_write(vs, buf, ret);
255e5e
 
255e5e
-        tight_encode_mono_rect32(vs->tight.tight.buffer, w, h, bg, fg);
255e5e
+        tight_encode_mono_rect32(vs->tight->tight.buffer, w, h, bg, fg);
255e5e
         break;
255e5e
     }
255e5e
     case 2:
255e5e
         vnc_write(vs, &bg, 2);
255e5e
         vnc_write(vs, &fg, 2);
255e5e
-        tight_encode_mono_rect16(vs->tight.tight.buffer, w, h, bg, fg);
255e5e
+        tight_encode_mono_rect16(vs->tight->tight.buffer, w, h, bg, fg);
255e5e
         break;
255e5e
     default:
255e5e
         vnc_write_u8(vs, bg);
255e5e
         vnc_write_u8(vs, fg);
255e5e
-        tight_encode_mono_rect8(vs->tight.tight.buffer, w, h, bg, fg);
255e5e
+        tight_encode_mono_rect8(vs->tight->tight.buffer, w, h, bg, fg);
255e5e
         break;
255e5e
     }
255e5e
-    vs->tight.tight.offset = bytes;
255e5e
+    vs->tight->tight.offset = bytes;
255e5e
 
255e5e
     bytes = tight_compress_data(vs, stream, bytes, level, Z_DEFAULT_STRATEGY);
255e5e
     return (bytes >= 0);
255e5e
@@ -1040,7 +1041,7 @@ static void write_palette(int idx, uint32_t color, void *opaque)
255e5e
 static bool send_gradient_rect(VncState *vs, int x, int y, int w, int h)
255e5e
 {
255e5e
     int stream = 3;
255e5e
-    int level = tight_conf[vs->tight.compression].gradient_zlib_level;
255e5e
+    int level = tight_conf[vs->tight->compression].gradient_zlib_level;
255e5e
     ssize_t bytes;
255e5e
 
255e5e
     if (vs->client_pf.bytes_per_pixel == 1) {
255e5e
@@ -1050,23 +1051,23 @@ static bool send_gradient_rect(VncState *vs, int x, int y, int w, int h)
255e5e
     vnc_write_u8(vs, (stream | VNC_TIGHT_EXPLICIT_FILTER) << 4);
255e5e
     vnc_write_u8(vs, VNC_TIGHT_FILTER_GRADIENT);
255e5e
 
255e5e
-    buffer_reserve(&vs->tight.gradient, w * 3 * sizeof (int));
255e5e
+    buffer_reserve(&vs->tight->gradient, w * 3 * sizeof(int));
255e5e
 
255e5e
-    if (vs->tight.pixel24) {
255e5e
-        tight_filter_gradient24(vs, vs->tight.tight.buffer, w, h);
255e5e
+    if (vs->tight->pixel24) {
255e5e
+        tight_filter_gradient24(vs, vs->tight->tight.buffer, w, h);
255e5e
         bytes = 3;
255e5e
     } else if (vs->client_pf.bytes_per_pixel == 4) {
255e5e
-        tight_filter_gradient32(vs, (uint32_t *)vs->tight.tight.buffer, w, h);
255e5e
+        tight_filter_gradient32(vs, (uint32_t *)vs->tight->tight.buffer, w, h);
255e5e
         bytes = 4;
255e5e
     } else {
255e5e
-        tight_filter_gradient16(vs, (uint16_t *)vs->tight.tight.buffer, w, h);
255e5e
+        tight_filter_gradient16(vs, (uint16_t *)vs->tight->tight.buffer, w, h);
255e5e
         bytes = 2;
255e5e
     }
255e5e
 
255e5e
-    buffer_reset(&vs->tight.gradient);
255e5e
+    buffer_reset(&vs->tight->gradient);
255e5e
 
255e5e
     bytes = w * h * bytes;
255e5e
-    vs->tight.tight.offset = bytes;
255e5e
+    vs->tight->tight.offset = bytes;
255e5e
 
255e5e
     bytes = tight_compress_data(vs, stream, bytes,
255e5e
                                 level, Z_FILTERED);
255e5e
@@ -1077,7 +1078,7 @@ static int send_palette_rect(VncState *vs, int x, int y,
255e5e
                              int w, int h, VncPalette *palette)
255e5e
 {
255e5e
     int stream = 2;
255e5e
-    int level = tight_conf[vs->tight.compression].idx_zlib_level;
255e5e
+    int level = tight_conf[vs->tight->compression].idx_zlib_level;
255e5e
     int colors;
255e5e
     ssize_t bytes;
255e5e
 
255e5e
@@ -1104,12 +1105,12 @@ static int send_palette_rect(VncState *vs, int x, int y,
255e5e
         palette_iter(palette, write_palette, &priv;;
255e5e
         vnc_write(vs, header, sizeof(header));
255e5e
 
255e5e
-        if (vs->tight.pixel24) {
255e5e
+        if (vs->tight->pixel24) {
255e5e
             tight_pack24(vs, vs->output.buffer + old_offset, colors, &offset);
255e5e
             vs->output.offset = old_offset + offset;
255e5e
         }
255e5e
 
255e5e
-        tight_encode_indexed_rect32(vs->tight.tight.buffer, w * h, palette);
255e5e
+        tight_encode_indexed_rect32(vs->tight->tight.buffer, w * h, palette);
255e5e
         break;
255e5e
     }
255e5e
     case 2:
255e5e
@@ -1119,7 +1120,7 @@ static int send_palette_rect(VncState *vs, int x, int y,
255e5e
 
255e5e
         palette_iter(palette, write_palette, &priv;;
255e5e
         vnc_write(vs, header, sizeof(header));
255e5e
-        tight_encode_indexed_rect16(vs->tight.tight.buffer, w * h, palette);
255e5e
+        tight_encode_indexed_rect16(vs->tight->tight.buffer, w * h, palette);
255e5e
         break;
255e5e
     }
255e5e
     default:
255e5e
@@ -1127,7 +1128,7 @@ static int send_palette_rect(VncState *vs, int x, int y,
255e5e
         break;
255e5e
     }
255e5e
     bytes = w * h;
255e5e
-    vs->tight.tight.offset = bytes;
255e5e
+    vs->tight->tight.offset = bytes;
255e5e
 
255e5e
     bytes = tight_compress_data(vs, stream, bytes,
255e5e
                                 level, Z_DEFAULT_STRATEGY);
255e5e
@@ -1146,7 +1147,7 @@ static int send_palette_rect(VncState *vs, int x, int y,
255e5e
 static void jpeg_init_destination(j_compress_ptr cinfo)
255e5e
 {
255e5e
     VncState *vs = cinfo->client_data;
255e5e
-    Buffer *buffer = &vs->tight.jpeg;
255e5e
+    Buffer *buffer = &vs->tight->jpeg;
255e5e
 
255e5e
     cinfo->dest->next_output_byte = (JOCTET *)buffer->buffer + buffer->offset;
255e5e
     cinfo->dest->free_in_buffer = (size_t)(buffer->capacity - buffer->offset);
255e5e
@@ -1156,7 +1157,7 @@ static void jpeg_init_destination(j_compress_ptr cinfo)
255e5e
 static boolean jpeg_empty_output_buffer(j_compress_ptr cinfo)
255e5e
 {
255e5e
     VncState *vs = cinfo->client_data;
255e5e
-    Buffer *buffer = &vs->tight.jpeg;
255e5e
+    Buffer *buffer = &vs->tight->jpeg;
255e5e
 
255e5e
     buffer->offset = buffer->capacity;
255e5e
     buffer_reserve(buffer, 2048);
255e5e
@@ -1168,7 +1169,7 @@ static boolean jpeg_empty_output_buffer(j_compress_ptr cinfo)
255e5e
 static void jpeg_term_destination(j_compress_ptr cinfo)
255e5e
 {
255e5e
     VncState *vs = cinfo->client_data;
255e5e
-    Buffer *buffer = &vs->tight.jpeg;
255e5e
+    Buffer *buffer = &vs->tight->jpeg;
255e5e
 
255e5e
     buffer->offset = buffer->capacity - cinfo->dest->free_in_buffer;
255e5e
 }
255e5e
@@ -1187,7 +1188,7 @@ static int send_jpeg_rect(VncState *vs, int x, int y, int w, int h, int quality)
255e5e
         return send_full_color_rect(vs, x, y, w, h);
255e5e
     }
255e5e
 
255e5e
-    buffer_reserve(&vs->tight.jpeg, 2048);
255e5e
+    buffer_reserve(&vs->tight->jpeg, 2048);
255e5e
 
255e5e
     cinfo.err = jpeg_std_error(&jerr);
255e5e
     jpeg_create_compress(&cinfo);
255e5e
@@ -1222,9 +1223,9 @@ static int send_jpeg_rect(VncState *vs, int x, int y, int w, int h, int quality)
255e5e
 
255e5e
     vnc_write_u8(vs, VNC_TIGHT_JPEG << 4);
255e5e
 
255e5e
-    tight_send_compact_size(vs, vs->tight.jpeg.offset);
255e5e
-    vnc_write(vs, vs->tight.jpeg.buffer, vs->tight.jpeg.offset);
255e5e
-    buffer_reset(&vs->tight.jpeg);
255e5e
+    tight_send_compact_size(vs, vs->tight->jpeg.offset);
255e5e
+    vnc_write(vs, vs->tight->jpeg.buffer, vs->tight->jpeg.offset);
255e5e
+    buffer_reset(&vs->tight->jpeg);
255e5e
 
255e5e
     return 1;
255e5e
 }
255e5e
@@ -1240,7 +1241,7 @@ static void write_png_palette(int idx, uint32_t pix, void *opaque)
255e5e
     VncState *vs = priv->vs;
255e5e
     png_colorp color = &priv->png_palette[idx];
255e5e
 
255e5e
-    if (vs->tight.pixel24)
255e5e
+    if (vs->tight->pixel24)
255e5e
     {
255e5e
         color->red = (pix >> vs->client_pf.rshift) & vs->client_pf.rmax;
255e5e
         color->green = (pix >> vs->client_pf.gshift) & vs->client_pf.gmax;
255e5e
@@ -1267,10 +1268,10 @@ static void png_write_data(png_structp png_ptr, png_bytep data,
255e5e
 {
255e5e
     VncState *vs = png_get_io_ptr(png_ptr);
255e5e
 
255e5e
-    buffer_reserve(&vs->tight.png, vs->tight.png.offset + length);
255e5e
-    memcpy(vs->tight.png.buffer + vs->tight.png.offset, data, length);
255e5e
+    buffer_reserve(&vs->tight->png, vs->tight->png.offset + length);
255e5e
+    memcpy(vs->tight->png.buffer + vs->tight->png.offset, data, length);
255e5e
 
255e5e
-    vs->tight.png.offset += length;
255e5e
+    vs->tight->png.offset += length;
255e5e
 }
255e5e
 
255e5e
 static void png_flush_data(png_structp png_ptr)
255e5e
@@ -1295,8 +1296,8 @@ static int send_png_rect(VncState *vs, int x, int y, int w, int h,
255e5e
     png_infop info_ptr;
255e5e
     png_colorp png_palette = NULL;
255e5e
     pixman_image_t *linebuf;
255e5e
-    int level = tight_png_conf[vs->tight.compression].png_zlib_level;
255e5e
-    int filters = tight_png_conf[vs->tight.compression].png_filters;
255e5e
+    int level = tight_png_conf[vs->tight->compression].png_zlib_level;
255e5e
+    int filters = tight_png_conf[vs->tight->compression].png_filters;
255e5e
     uint8_t *buf;
255e5e
     int dy;
255e5e
 
255e5e
@@ -1340,21 +1341,23 @@ static int send_png_rect(VncState *vs, int x, int y, int w, int h,
255e5e
         png_set_PLTE(png_ptr, info_ptr, png_palette, palette_size(palette));
255e5e
 
255e5e
         if (vs->client_pf.bytes_per_pixel == 4) {
255e5e
-            tight_encode_indexed_rect32(vs->tight.tight.buffer, w * h, palette);
255e5e
+            tight_encode_indexed_rect32(vs->tight->tight.buffer, w * h,
255e5e
+                                        palette);
255e5e
         } else {
255e5e
-            tight_encode_indexed_rect16(vs->tight.tight.buffer, w * h, palette);
255e5e
+            tight_encode_indexed_rect16(vs->tight->tight.buffer, w * h,
255e5e
+                                        palette);
255e5e
         }
255e5e
     }
255e5e
 
255e5e
     png_write_info(png_ptr, info_ptr);
255e5e
 
255e5e
-    buffer_reserve(&vs->tight.png, 2048);
255e5e
+    buffer_reserve(&vs->tight->png, 2048);
255e5e
     linebuf = qemu_pixman_linebuf_create(PIXMAN_BE_r8g8b8, w);
255e5e
     buf = (uint8_t *)pixman_image_get_data(linebuf);
255e5e
     for (dy = 0; dy < h; dy++)
255e5e
     {
255e5e
         if (color_type == PNG_COLOR_TYPE_PALETTE) {
255e5e
-            memcpy(buf, vs->tight.tight.buffer + (dy * w), w);
255e5e
+            memcpy(buf, vs->tight->tight.buffer + (dy * w), w);
255e5e
         } else {
255e5e
             qemu_pixman_linebuf_fill(linebuf, vs->vd->server, w, x, y + dy);
255e5e
         }
255e5e
@@ -1372,27 +1375,27 @@ static int send_png_rect(VncState *vs, int x, int y, int w, int h,
255e5e
 
255e5e
     vnc_write_u8(vs, VNC_TIGHT_PNG << 4);
255e5e
 
255e5e
-    tight_send_compact_size(vs, vs->tight.png.offset);
255e5e
-    vnc_write(vs, vs->tight.png.buffer, vs->tight.png.offset);
255e5e
-    buffer_reset(&vs->tight.png);
255e5e
+    tight_send_compact_size(vs, vs->tight->png.offset);
255e5e
+    vnc_write(vs, vs->tight->png.buffer, vs->tight->png.offset);
255e5e
+    buffer_reset(&vs->tight->png);
255e5e
     return 1;
255e5e
 }
255e5e
 #endif /* CONFIG_VNC_PNG */
255e5e
 
255e5e
 static void vnc_tight_start(VncState *vs)
255e5e
 {
255e5e
-    buffer_reset(&vs->tight.tight);
255e5e
+    buffer_reset(&vs->tight->tight);
255e5e
 
255e5e
     // make the output buffer be the zlib buffer, so we can compress it later
255e5e
-    vs->tight.tmp = vs->output;
255e5e
-    vs->output = vs->tight.tight;
255e5e
+    vs->tight->tmp = vs->output;
255e5e
+    vs->output = vs->tight->tight;
255e5e
 }
255e5e
 
255e5e
 static void vnc_tight_stop(VncState *vs)
255e5e
 {
255e5e
     // switch back to normal output/zlib buffers
255e5e
-    vs->tight.tight = vs->output;
255e5e
-    vs->output = vs->tight.tmp;
255e5e
+    vs->tight->tight = vs->output;
255e5e
+    vs->output = vs->tight->tmp;
255e5e
 }
255e5e
 
255e5e
 static int send_sub_rect_nojpeg(VncState *vs, int x, int y, int w, int h,
255e5e
@@ -1426,9 +1429,9 @@ static int send_sub_rect_jpeg(VncState *vs, int x, int y, int w, int h,
255e5e
     int ret;
255e5e
 
255e5e
     if (colors == 0) {
255e5e
-        if (force || (tight_jpeg_conf[vs->tight.quality].jpeg_full &&
255e5e
+        if (force || (tight_jpeg_conf[vs->tight->quality].jpeg_full &&
255e5e
                       tight_detect_smooth_image(vs, w, h))) {
255e5e
-            int quality = tight_conf[vs->tight.quality].jpeg_quality;
255e5e
+            int quality = tight_conf[vs->tight->quality].jpeg_quality;
255e5e
 
255e5e
             ret = send_jpeg_rect(vs, x, y, w, h, quality);
255e5e
         } else {
255e5e
@@ -1440,9 +1443,9 @@ static int send_sub_rect_jpeg(VncState *vs, int x, int y, int w, int h,
255e5e
         ret = send_mono_rect(vs, x, y, w, h, bg, fg);
255e5e
     } else if (colors <= 256) {
255e5e
         if (force || (colors > 96 &&
255e5e
-                      tight_jpeg_conf[vs->tight.quality].jpeg_idx &&
255e5e
+                      tight_jpeg_conf[vs->tight->quality].jpeg_idx &&
255e5e
                       tight_detect_smooth_image(vs, w, h))) {
255e5e
-            int quality = tight_conf[vs->tight.quality].jpeg_quality;
255e5e
+            int quality = tight_conf[vs->tight->quality].jpeg_quality;
255e5e
 
255e5e
             ret = send_jpeg_rect(vs, x, y, w, h, quality);
255e5e
         } else {
255e5e
@@ -1480,20 +1483,20 @@ static int send_sub_rect(VncState *vs, int x, int y, int w, int h)
255e5e
         qemu_thread_atexit_add(&vnc_tight_cleanup_notifier);
255e5e
     }
255e5e
 
255e5e
-    vnc_framebuffer_update(vs, x, y, w, h, vs->tight.type);
255e5e
+    vnc_framebuffer_update(vs, x, y, w, h, vs->tight->type);
255e5e
 
255e5e
     vnc_tight_start(vs);
255e5e
     vnc_raw_send_framebuffer_update(vs, x, y, w, h);
255e5e
     vnc_tight_stop(vs);
255e5e
 
255e5e
 #ifdef CONFIG_VNC_JPEG
255e5e
-    if (!vs->vd->non_adaptive && vs->tight.quality != (uint8_t)-1) {
255e5e
+    if (!vs->vd->non_adaptive && vs->tight->quality != (uint8_t)-1) {
255e5e
         double freq = vnc_update_freq(vs, x, y, w, h);
255e5e
 
255e5e
-        if (freq < tight_jpeg_conf[vs->tight.quality].jpeg_freq_min) {
255e5e
+        if (freq < tight_jpeg_conf[vs->tight->quality].jpeg_freq_min) {
255e5e
             allow_jpeg = false;
255e5e
         }
255e5e
-        if (freq >= tight_jpeg_conf[vs->tight.quality].jpeg_freq_threshold) {
255e5e
+        if (freq >= tight_jpeg_conf[vs->tight->quality].jpeg_freq_threshold) {
255e5e
             force_jpeg = true;
255e5e
             vnc_sent_lossy_rect(vs, x, y, w, h);
255e5e
         }
255e5e
@@ -1503,7 +1506,7 @@ static int send_sub_rect(VncState *vs, int x, int y, int w, int h)
255e5e
     colors = tight_fill_palette(vs, x, y, w * h, &bg, &fg, color_count_palette);
255e5e
 
255e5e
 #ifdef CONFIG_VNC_JPEG
255e5e
-    if (allow_jpeg && vs->tight.quality != (uint8_t)-1) {
255e5e
+    if (allow_jpeg && vs->tight->quality != (uint8_t)-1) {
255e5e
         ret = send_sub_rect_jpeg(vs, x, y, w, h, bg, fg, colors,
255e5e
                                  color_count_palette, force_jpeg);
255e5e
     } else {
255e5e
@@ -1520,7 +1523,7 @@ static int send_sub_rect(VncState *vs, int x, int y, int w, int h)
255e5e
 
255e5e
 static int send_sub_rect_solid(VncState *vs, int x, int y, int w, int h)
255e5e
 {
255e5e
-    vnc_framebuffer_update(vs, x, y, w, h, vs->tight.type);
255e5e
+    vnc_framebuffer_update(vs, x, y, w, h, vs->tight->type);
255e5e
 
255e5e
     vnc_tight_start(vs);
255e5e
     vnc_raw_send_framebuffer_update(vs, x, y, w, h);
255e5e
@@ -1538,8 +1541,8 @@ static int send_rect_simple(VncState *vs, int x, int y, int w, int h,
255e5e
     int rw, rh;
255e5e
     int n = 0;
255e5e
 
255e5e
-    max_size = tight_conf[vs->tight.compression].max_rect_size;
255e5e
-    max_width = tight_conf[vs->tight.compression].max_rect_width;
255e5e
+    max_size = tight_conf[vs->tight->compression].max_rect_size;
255e5e
+    max_width = tight_conf[vs->tight->compression].max_rect_width;
255e5e
 
255e5e
     if (split && (w > max_width || w * h > max_size)) {
255e5e
         max_sub_width = (w > max_width) ? max_width : w;
255e5e
@@ -1648,16 +1651,16 @@ static int tight_send_framebuffer_update(VncState *vs, int x, int y,
255e5e
 
255e5e
     if (vs->client_pf.bytes_per_pixel == 4 && vs->client_pf.rmax == 0xFF &&
255e5e
         vs->client_pf.bmax == 0xFF && vs->client_pf.gmax == 0xFF) {
255e5e
-        vs->tight.pixel24 = true;
255e5e
+        vs->tight->pixel24 = true;
255e5e
     } else {
255e5e
-        vs->tight.pixel24 = false;
255e5e
+        vs->tight->pixel24 = false;
255e5e
     }
255e5e
 
255e5e
 #ifdef CONFIG_VNC_JPEG
255e5e
-    if (vs->tight.quality != (uint8_t)-1) {
255e5e
+    if (vs->tight->quality != (uint8_t)-1) {
255e5e
         double freq = vnc_update_freq(vs, x, y, w, h);
255e5e
 
255e5e
-        if (freq > tight_jpeg_conf[vs->tight.quality].jpeg_freq_threshold) {
255e5e
+        if (freq > tight_jpeg_conf[vs->tight->quality].jpeg_freq_threshold) {
255e5e
             return send_rect_simple(vs, x, y, w, h, false);
255e5e
         }
255e5e
     }
255e5e
@@ -1669,8 +1672,8 @@ static int tight_send_framebuffer_update(VncState *vs, int x, int y,
255e5e
 
255e5e
     /* Calculate maximum number of rows in one non-solid rectangle. */
255e5e
 
255e5e
-    max_rows = tight_conf[vs->tight.compression].max_rect_size;
255e5e
-    max_rows /= MIN(tight_conf[vs->tight.compression].max_rect_width, w);
255e5e
+    max_rows = tight_conf[vs->tight->compression].max_rect_size;
255e5e
+    max_rows /= MIN(tight_conf[vs->tight->compression].max_rect_width, w);
255e5e
 
255e5e
     return find_large_solid_color_rect(vs, x, y, w, h, max_rows);
255e5e
 }
255e5e
@@ -1678,33 +1681,33 @@ static int tight_send_framebuffer_update(VncState *vs, int x, int y,
255e5e
 int vnc_tight_send_framebuffer_update(VncState *vs, int x, int y,
255e5e
                                       int w, int h)
255e5e
 {
255e5e
-    vs->tight.type = VNC_ENCODING_TIGHT;
255e5e
+    vs->tight->type = VNC_ENCODING_TIGHT;
255e5e
     return tight_send_framebuffer_update(vs, x, y, w, h);
255e5e
 }
255e5e
 
255e5e
 int vnc_tight_png_send_framebuffer_update(VncState *vs, int x, int y,
255e5e
                                           int w, int h)
255e5e
 {
255e5e
-    vs->tight.type = VNC_ENCODING_TIGHT_PNG;
255e5e
+    vs->tight->type = VNC_ENCODING_TIGHT_PNG;
255e5e
     return tight_send_framebuffer_update(vs, x, y, w, h);
255e5e
 }
255e5e
 
255e5e
 void vnc_tight_clear(VncState *vs)
255e5e
 {
255e5e
     int i;
255e5e
-    for (i=0; i<ARRAY_SIZE(vs->tight.stream); i++) {
255e5e
-        if (vs->tight.stream[i].opaque) {
255e5e
-            deflateEnd(&vs->tight.stream[i]);
255e5e
+    for (i = 0; i < ARRAY_SIZE(vs->tight->stream); i++) {
255e5e
+        if (vs->tight->stream[i].opaque) {
255e5e
+            deflateEnd(&vs->tight->stream[i]);
255e5e
         }
255e5e
     }
255e5e
 
255e5e
-    buffer_free(&vs->tight.tight);
255e5e
-    buffer_free(&vs->tight.zlib);
255e5e
-    buffer_free(&vs->tight.gradient);
255e5e
+    buffer_free(&vs->tight->tight);
255e5e
+    buffer_free(&vs->tight->zlib);
255e5e
+    buffer_free(&vs->tight->gradient);
255e5e
 #ifdef CONFIG_VNC_JPEG
255e5e
-    buffer_free(&vs->tight.jpeg);
255e5e
+    buffer_free(&vs->tight->jpeg);
255e5e
 #endif
255e5e
 #ifdef CONFIG_VNC_PNG
255e5e
-    buffer_free(&vs->tight.png);
255e5e
+    buffer_free(&vs->tight->png);
255e5e
 #endif
255e5e
 }
255e5e
diff --git a/ui/vnc-enc-zlib.c b/ui/vnc-enc-zlib.c
255e5e
index 33e9df2..900ae5b 100644
255e5e
--- a/ui/vnc-enc-zlib.c
255e5e
+++ b/ui/vnc-enc-zlib.c
255e5e
@@ -76,7 +76,8 @@ static int vnc_zlib_stop(VncState *vs)
255e5e
         zstream->zalloc = vnc_zlib_zalloc;
255e5e
         zstream->zfree = vnc_zlib_zfree;
255e5e
 
255e5e
-        err = deflateInit2(zstream, vs->tight.compression, Z_DEFLATED, MAX_WBITS,
255e5e
+        err = deflateInit2(zstream, vs->tight->compression, Z_DEFLATED,
255e5e
+                           MAX_WBITS,
255e5e
                            MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY);
255e5e
 
255e5e
         if (err != Z_OK) {
255e5e
@@ -84,16 +85,16 @@ static int vnc_zlib_stop(VncState *vs)
255e5e
             return -1;
255e5e
         }
255e5e
 
255e5e
-        vs->zlib.level = vs->tight.compression;
255e5e
+        vs->zlib.level = vs->tight->compression;
255e5e
         zstream->opaque = vs;
255e5e
     }
255e5e
 
255e5e
-    if (vs->tight.compression != vs->zlib.level) {
255e5e
-        if (deflateParams(zstream, vs->tight.compression,
255e5e
+    if (vs->tight->compression != vs->zlib.level) {
255e5e
+        if (deflateParams(zstream, vs->tight->compression,
255e5e
                           Z_DEFAULT_STRATEGY) != Z_OK) {
255e5e
             return -1;
255e5e
         }
255e5e
-        vs->zlib.level = vs->tight.compression;
255e5e
+        vs->zlib.level = vs->tight->compression;
255e5e
     }
255e5e
 
255e5e
     // reserve memory in output buffer
255e5e
diff --git a/ui/vnc-enc-zrle-template.c b/ui/vnc-enc-zrle-template.c
255e5e
index abf6b86..c107d8a 100644
255e5e
--- a/ui/vnc-enc-zrle-template.c
255e5e
+++ b/ui/vnc-enc-zrle-template.c
255e5e
@@ -96,7 +96,7 @@ static void ZRLE_ENCODE(VncState *vs, int x, int y, int w, int h,
255e5e
 static void ZRLE_ENCODE_TILE(VncState *vs, ZRLE_PIXEL *data, int w, int h,
255e5e
                              int zywrle_level)
255e5e
 {
255e5e
-    VncPalette *palette = &vs->zrle.palette;
255e5e
+    VncPalette *palette = &vs->zrle->palette;
255e5e
 
255e5e
     int runs = 0;
255e5e
     int single_pixels = 0;
255e5e
diff --git a/ui/vnc-enc-zrle.c b/ui/vnc-enc-zrle.c
255e5e
index fd63d4f..3d259ed 100644
255e5e
--- a/ui/vnc-enc-zrle.c
255e5e
+++ b/ui/vnc-enc-zrle.c
255e5e
@@ -37,18 +37,18 @@ static const int bits_per_packed_pixel[] = {
255e5e
 
255e5e
 static void vnc_zrle_start(VncState *vs)
255e5e
 {
255e5e
-    buffer_reset(&vs->zrle.zrle);
255e5e
+    buffer_reset(&vs->zrle->zrle);
255e5e
 
255e5e
     /* make the output buffer be the zlib buffer, so we can compress it later */
255e5e
-    vs->zrle.tmp = vs->output;
255e5e
-    vs->output = vs->zrle.zrle;
255e5e
+    vs->zrle->tmp = vs->output;
255e5e
+    vs->output = vs->zrle->zrle;
255e5e
 }
255e5e
 
255e5e
 static void vnc_zrle_stop(VncState *vs)
255e5e
 {
255e5e
     /* switch back to normal output/zlib buffers */
255e5e
-    vs->zrle.zrle = vs->output;
255e5e
-    vs->output = vs->zrle.tmp;
255e5e
+    vs->zrle->zrle = vs->output;
255e5e
+    vs->output = vs->zrle->tmp;
255e5e
 }
255e5e
 
255e5e
 static void *zrle_convert_fb(VncState *vs, int x, int y, int w, int h,
255e5e
@@ -56,24 +56,24 @@ static void *zrle_convert_fb(VncState *vs, int x, int y, int w, int h,
255e5e
 {
255e5e
     Buffer tmp;
255e5e
 
255e5e
-    buffer_reset(&vs->zrle.fb);
255e5e
-    buffer_reserve(&vs->zrle.fb, w * h * bpp + bpp);
255e5e
+    buffer_reset(&vs->zrle->fb);
255e5e
+    buffer_reserve(&vs->zrle->fb, w * h * bpp + bpp);
255e5e
 
255e5e
     tmp = vs->output;
255e5e
-    vs->output = vs->zrle.fb;
255e5e
+    vs->output = vs->zrle->fb;
255e5e
 
255e5e
     vnc_raw_send_framebuffer_update(vs, x, y, w, h);
255e5e
 
255e5e
-    vs->zrle.fb = vs->output;
255e5e
+    vs->zrle->fb = vs->output;
255e5e
     vs->output = tmp;
255e5e
-    return vs->zrle.fb.buffer;
255e5e
+    return vs->zrle->fb.buffer;
255e5e
 }
255e5e
 
255e5e
 static int zrle_compress_data(VncState *vs, int level)
255e5e
 {
255e5e
-    z_streamp zstream = &vs->zrle.stream;
255e5e
+    z_streamp zstream = &vs->zrle->stream;
255e5e
 
255e5e
-    buffer_reset(&vs->zrle.zlib);
255e5e
+    buffer_reset(&vs->zrle->zlib);
255e5e
 
255e5e
     if (zstream->opaque != vs) {
255e5e
         int err;
255e5e
@@ -93,13 +93,13 @@ static int zrle_compress_data(VncState *vs, int level)
255e5e
     }
255e5e
 
255e5e
     /* reserve memory in output buffer */
255e5e
-    buffer_reserve(&vs->zrle.zlib, vs->zrle.zrle.offset + 64);
255e5e
+    buffer_reserve(&vs->zrle->zlib, vs->zrle->zrle.offset + 64);
255e5e
 
255e5e
     /* set pointers */
255e5e
-    zstream->next_in = vs->zrle.zrle.buffer;
255e5e
-    zstream->avail_in = vs->zrle.zrle.offset;
255e5e
-    zstream->next_out = vs->zrle.zlib.buffer + vs->zrle.zlib.offset;
255e5e
-    zstream->avail_out = vs->zrle.zlib.capacity - vs->zrle.zlib.offset;
255e5e
+    zstream->next_in = vs->zrle->zrle.buffer;
255e5e
+    zstream->avail_in = vs->zrle->zrle.offset;
255e5e
+    zstream->next_out = vs->zrle->zlib.buffer + vs->zrle->zlib.offset;
255e5e
+    zstream->avail_out = vs->zrle->zlib.capacity - vs->zrle->zlib.offset;
255e5e
     zstream->data_type = Z_BINARY;
255e5e
 
255e5e
     /* start encoding */
255e5e
@@ -108,8 +108,8 @@ static int zrle_compress_data(VncState *vs, int level)
255e5e
         return -1;
255e5e
     }
255e5e
 
255e5e
-    vs->zrle.zlib.offset = vs->zrle.zlib.capacity - zstream->avail_out;
255e5e
-    return vs->zrle.zlib.offset;
255e5e
+    vs->zrle->zlib.offset = vs->zrle->zlib.capacity - zstream->avail_out;
255e5e
+    return vs->zrle->zlib.offset;
255e5e
 }
255e5e
 
255e5e
 /* Try to work out whether to use RLE and/or a palette.  We do this by
255e5e
@@ -259,14 +259,14 @@ static int zrle_send_framebuffer_update(VncState *vs, int x, int y,
255e5e
     size_t bytes;
255e5e
     int zywrle_level;
255e5e
 
255e5e
-    if (vs->zrle.type == VNC_ENCODING_ZYWRLE) {
255e5e
-        if (!vs->vd->lossy || vs->tight.quality == (uint8_t)-1
255e5e
-            || vs->tight.quality == 9) {
255e5e
+    if (vs->zrle->type == VNC_ENCODING_ZYWRLE) {
255e5e
+        if (!vs->vd->lossy || vs->tight->quality == (uint8_t)-1
255e5e
+            || vs->tight->quality == 9) {
255e5e
             zywrle_level = 0;
255e5e
-            vs->zrle.type = VNC_ENCODING_ZRLE;
255e5e
-        } else if (vs->tight.quality < 3) {
255e5e
+            vs->zrle->type = VNC_ENCODING_ZRLE;
255e5e
+        } else if (vs->tight->quality < 3) {
255e5e
             zywrle_level = 3;
255e5e
-        } else if (vs->tight.quality < 6) {
255e5e
+        } else if (vs->tight->quality < 6) {
255e5e
             zywrle_level = 2;
255e5e
         } else {
255e5e
             zywrle_level = 1;
255e5e
@@ -337,30 +337,30 @@ static int zrle_send_framebuffer_update(VncState *vs, int x, int y,
255e5e
 
255e5e
     vnc_zrle_stop(vs);
255e5e
     bytes = zrle_compress_data(vs, Z_DEFAULT_COMPRESSION);
255e5e
-    vnc_framebuffer_update(vs, x, y, w, h, vs->zrle.type);
255e5e
+    vnc_framebuffer_update(vs, x, y, w, h, vs->zrle->type);
255e5e
     vnc_write_u32(vs, bytes);
255e5e
-    vnc_write(vs, vs->zrle.zlib.buffer, vs->zrle.zlib.offset);
255e5e
+    vnc_write(vs, vs->zrle->zlib.buffer, vs->zrle->zlib.offset);
255e5e
     return 1;
255e5e
 }
255e5e
 
255e5e
 int vnc_zrle_send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
255e5e
 {
255e5e
-    vs->zrle.type = VNC_ENCODING_ZRLE;
255e5e
+    vs->zrle->type = VNC_ENCODING_ZRLE;
255e5e
     return zrle_send_framebuffer_update(vs, x, y, w, h);
255e5e
 }
255e5e
 
255e5e
 int vnc_zywrle_send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
255e5e
 {
255e5e
-    vs->zrle.type = VNC_ENCODING_ZYWRLE;
255e5e
+    vs->zrle->type = VNC_ENCODING_ZYWRLE;
255e5e
     return zrle_send_framebuffer_update(vs, x, y, w, h);
255e5e
 }
255e5e
 
255e5e
 void vnc_zrle_clear(VncState *vs)
255e5e
 {
255e5e
-    if (vs->zrle.stream.opaque) {
255e5e
-        deflateEnd(&vs->zrle.stream);
255e5e
+    if (vs->zrle->stream.opaque) {
255e5e
+        deflateEnd(&vs->zrle->stream);
255e5e
     }
255e5e
-    buffer_free(&vs->zrle.zrle);
255e5e
-    buffer_free(&vs->zrle.fb);
255e5e
-    buffer_free(&vs->zrle.zlib);
255e5e
+    buffer_free(&vs->zrle->zrle);
255e5e
+    buffer_free(&vs->zrle->fb);
255e5e
+    buffer_free(&vs->zrle->zlib);
255e5e
 }
255e5e
diff --git a/ui/vnc.c b/ui/vnc.c
255e5e
index dbbc76e..d13e7e2 100644
255e5e
--- a/ui/vnc.c
255e5e
+++ b/ui/vnc.c
255e5e
@@ -1297,6 +1297,8 @@ void vnc_disconnect_finish(VncState *vs)
255e5e
     object_unref(OBJECT(vs->sioc));
255e5e
     vs->sioc = NULL;
255e5e
     vs->magic = 0;
255e5e
+    g_free(vs->zrle);
255e5e
+    g_free(vs->tight);
255e5e
     g_free(vs);
255e5e
 }
255e5e
 
255e5e
@@ -2106,8 +2108,8 @@ static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
255e5e
 
255e5e
     vs->features = 0;
255e5e
     vs->vnc_encoding = 0;
255e5e
-    vs->tight.compression = 9;
255e5e
-    vs->tight.quality = -1; /* Lossless by default */
255e5e
+    vs->tight->compression = 9;
255e5e
+    vs->tight->quality = -1; /* Lossless by default */
255e5e
     vs->absolute = -1;
255e5e
 
255e5e
     /*
255e5e
@@ -2175,11 +2177,11 @@ static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
255e5e
             vs->features |= VNC_FEATURE_LED_STATE_MASK;
255e5e
             break;
255e5e
         case VNC_ENCODING_COMPRESSLEVEL0 ... VNC_ENCODING_COMPRESSLEVEL0 + 9:
255e5e
-            vs->tight.compression = (enc & 0x0F);
255e5e
+            vs->tight->compression = (enc & 0x0F);
255e5e
             break;
255e5e
         case VNC_ENCODING_QUALITYLEVEL0 ... VNC_ENCODING_QUALITYLEVEL0 + 9:
255e5e
             if (vs->vd->lossy) {
255e5e
-                vs->tight.quality = (enc & 0x0F);
255e5e
+                vs->tight->quality = (enc & 0x0F);
255e5e
             }
255e5e
             break;
255e5e
         default:
255e5e
@@ -3089,6 +3091,8 @@ static void vnc_connect(VncDisplay *vd, QIOChannelSocket *sioc,
255e5e
     int i;
255e5e
 
255e5e
     trace_vnc_client_connect(vs, sioc);
255e5e
+    vs->zrle = g_new0(VncZrle, 1);
255e5e
+    vs->tight = g_new0(VncTight, 1);
255e5e
     vs->magic = VNC_MAGIC;
255e5e
     vs->sioc = sioc;
255e5e
     object_ref(OBJECT(vs->sioc));
255e5e
@@ -3100,19 +3104,19 @@ static void vnc_connect(VncDisplay *vd, QIOChannelSocket *sioc,
255e5e
     buffer_init(&vs->output,         "vnc-output/%p", sioc);
255e5e
     buffer_init(&vs->jobs_buffer,    "vnc-jobs_buffer/%p", sioc);
255e5e
 
255e5e
-    buffer_init(&vs->tight.tight,    "vnc-tight/%p", sioc);
255e5e
-    buffer_init(&vs->tight.zlib,     "vnc-tight-zlib/%p", sioc);
255e5e
-    buffer_init(&vs->tight.gradient, "vnc-tight-gradient/%p", sioc);
255e5e
+    buffer_init(&vs->tight->tight,    "vnc-tight/%p", sioc);
255e5e
+    buffer_init(&vs->tight->zlib,     "vnc-tight-zlib/%p", sioc);
255e5e
+    buffer_init(&vs->tight->gradient, "vnc-tight-gradient/%p", sioc);
255e5e
 #ifdef CONFIG_VNC_JPEG
255e5e
-    buffer_init(&vs->tight.jpeg,     "vnc-tight-jpeg/%p", sioc);
255e5e
+    buffer_init(&vs->tight->jpeg,     "vnc-tight-jpeg/%p", sioc);
255e5e
 #endif
255e5e
 #ifdef CONFIG_VNC_PNG
255e5e
-    buffer_init(&vs->tight.png,      "vnc-tight-png/%p", sioc);
255e5e
+    buffer_init(&vs->tight->png,      "vnc-tight-png/%p", sioc);
255e5e
 #endif
255e5e
     buffer_init(&vs->zlib.zlib,      "vnc-zlib/%p", sioc);
255e5e
-    buffer_init(&vs->zrle.zrle,      "vnc-zrle/%p", sioc);
255e5e
-    buffer_init(&vs->zrle.fb,        "vnc-zrle-fb/%p", sioc);
255e5e
-    buffer_init(&vs->zrle.zlib,      "vnc-zrle-zlib/%p", sioc);
255e5e
+    buffer_init(&vs->zrle->zrle,      "vnc-zrle/%p", sioc);
255e5e
+    buffer_init(&vs->zrle->fb,        "vnc-zrle-fb/%p", sioc);
255e5e
+    buffer_init(&vs->zrle->zlib,      "vnc-zrle-zlib/%p", sioc);
255e5e
 
255e5e
     if (skipauth) {
255e5e
 	vs->auth = VNC_AUTH_NONE;
255e5e
diff --git a/ui/vnc.h b/ui/vnc.h
255e5e
index 7626329..8d9687c 100644
255e5e
--- a/ui/vnc.h
255e5e
+++ b/ui/vnc.h
255e5e
@@ -335,10 +335,10 @@ struct VncState
255e5e
     /* Encoding specific, if you add something here, don't forget to
255e5e
      *  update vnc_async_encoding_start()
255e5e
      */
255e5e
-    VncTight tight;
255e5e
+    VncTight *tight;
255e5e
     VncZlib zlib;
255e5e
     VncHextile hextile;
255e5e
-    VncZrle zrle;
255e5e
+    VncZrle *zrle;
255e5e
     VncZywrle zywrle;
255e5e
 
255e5e
     Notifier mouse_mode_notifier;
255e5e
-- 
255e5e
1.8.3.1
255e5e