4549c1
From 87a76b97164685ea1e1aaab6a35bfbaf18c60366 Mon Sep 17 00:00:00 2001
4549c1
From: jmaloy <jmaloy@redhat.com>
4549c1
Date: Mon, 25 May 2020 21:20:00 -0400
4549c1
Subject: [PATCH] vnc: fix memory leak when vnc disconnect
4549c1
MIME-Version: 1.0
4549c1
Content-Type: text/plain; charset=UTF-8
4549c1
Content-Transfer-Encoding: 8bit
4549c1
4549c1
RH-Author: jmaloy <jmaloy@redhat.com>
4549c1
Message-id: <20200525212000.355756-2-jmaloy@redhat.com>
4549c1
Patchwork-id: 96752
4549c1
O-Subject: [RHEL-7.9 qemu-kvm PATCH v2 1/1] vnc: fix memory leak when vnc disconnect
4549c1
Bugzilla: 1810408
4549c1
RH-Acked-by: Gerd Hoffmann <kraxel@redhat.com>
4549c1
RH-Acked-by: Daniel P. Berrange <berrange@redhat.com>
4549c1
RH-Acked-by: Philippe Mathieu-Daudé <philmd@redhat.com>
4549c1
4549c1
From: Li Qiang <liq3ea@163.com>
4549c1
4549c1
Currently when qemu receives a vnc connect, it creates a 'VncState' to
4549c1
represent this connection. In 'vnc_worker_thread_loop' it creates a
4549c1
local 'VncState'. The connection 'VcnState' and local 'VncState' exchange
4549c1
data in 'vnc_async_encoding_start' and 'vnc_async_encoding_end'.
4549c1
In 'zrle_compress_data' it calls 'deflateInit2' to allocate the libz library
4549c1
opaque data. The 'VncState' used in 'zrle_compress_data' is the local
4549c1
'VncState'. In 'vnc_zrle_clear' it calls 'deflateEnd' to free the libz
4549c1
library opaque data. The 'VncState' used in 'vnc_zrle_clear' is the connection
4549c1
'VncState'. In currently implementation there will be a memory leak when the
4549c1
vnc disconnect. Following is the asan output backtrack:
4549c1
4549c1
Direct leak of 29760 byte(s) in 5 object(s) allocated from:
4549c1
    0 0xffffa67ef3c3 in __interceptor_calloc (/lib64/libasan.so.4+0xd33c3)
4549c1
    1 0xffffa65071cb in g_malloc0 (/lib64/libglib-2.0.so.0+0x571cb)
4549c1
    2 0xffffa5e968f7 in deflateInit2_ (/lib64/libz.so.1+0x78f7)
4549c1
    3 0xaaaacec58613 in zrle_compress_data ui/vnc-enc-zrle.c:87
4549c1
    4 0xaaaacec58613 in zrle_send_framebuffer_update ui/vnc-enc-zrle.c:344
4549c1
    5 0xaaaacec34e77 in vnc_send_framebuffer_update ui/vnc.c:919
4549c1
    6 0xaaaacec5e023 in vnc_worker_thread_loop ui/vnc-jobs.c:271
4549c1
    7 0xaaaacec5e5e7 in vnc_worker_thread ui/vnc-jobs.c:340
4549c1
    8 0xaaaacee4d3c3 in qemu_thread_start util/qemu-thread-posix.c:502
4549c1
    9 0xffffa544e8bb in start_thread (/lib64/libpthread.so.0+0x78bb)
4549c1
    10 0xffffa53965cb in thread_start (/lib64/libc.so.6+0xd55cb)
4549c1
4549c1
This is because the opaque allocated in 'deflateInit2' is not freed in
4549c1
'deflateEnd'. The reason is that the 'deflateEnd' calls 'deflateStateCheck'
4549c1
and in the latter will check whether 's->strm != strm'(libz's data structure).
4549c1
This check will be true so in 'deflateEnd' it just return 'Z_STREAM_ERROR' and
4549c1
not free the data allocated in 'deflateInit2'.
4549c1
4549c1
The reason this happens is that the 'VncState' contains the whole 'VncZrle',
4549c1
so when calling 'deflateInit2', the 's->strm' will be the local address.
4549c1
So 's->strm != strm' will be true.
4549c1
4549c1
To fix this issue, we need to make 'zrle' of 'VncState' to be a pointer.
4549c1
Then the connection 'VncState' and local 'VncState' exchange mechanism will
4549c1
work as expection. The 'tight' of 'VncState' has the same issue, let's also turn
4549c1
it to a pointer.
4549c1
4549c1
Reported-by: Ying Fang <fangying1@huawei.com>
4549c1
Signed-off-by: Li Qiang <liq3ea@163.com>
4549c1
Message-id: 20190831153922.121308-1-liq3ea@163.com
4549c1
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
4549c1
4549c1
(cherry picked from commit 6bf21f3d83e95bcc4ba35a7a07cc6655e8b010b0)
4549c1
Manually re-adapted, since there has been a huge number of conflicting
4549c1
commits applied upsteam since this code version. The re-adapted commit
4549c1
was still very similar to the upstream one in the end.
4549c1
4549c1
Signed-off-by: Jon Maloy <jmaloy@redhat.com>
4549c1
Signed-off-by: Jon Maloy <jmaloy.redhat.com>
4549c1
---
4549c1
 ui/vnc-enc-tight.c         | 219 +++++++++++++++++++------------------
4549c1
 ui/vnc-enc-zlib.c          |  11 +-
4549c1
 ui/vnc-enc-zrle-template.c |   2 +-
4549c1
 ui/vnc-enc-zrle.c          |  68 ++++++------
4549c1
 ui/vnc.c                   |  12 +-
4549c1
 ui/vnc.h                   |   4 +-
4549c1
 6 files changed, 162 insertions(+), 154 deletions(-)
4549c1
4549c1
diff --git a/ui/vnc-enc-tight.c b/ui/vnc-enc-tight.c
4549c1
index e6966aebc3..f01375d5ef 100644
4549c1
--- a/ui/vnc-enc-tight.c
4549c1
+++ b/ui/vnc-enc-tight.c
4549c1
@@ -119,7 +119,7 @@ static int send_png_rect(VncState *vs, int x, int y, int w, int h,
4549c1
 
4549c1
 static bool tight_can_send_png_rect(VncState *vs, int w, int h)
4549c1
 {
4549c1
-    if (vs->tight.type != VNC_ENCODING_TIGHT_PNG) {
4549c1
+    if (vs->tight->type != VNC_ENCODING_TIGHT_PNG) {
4549c1
         return false;
4549c1
     }
4549c1
 
4549c1
@@ -147,7 +147,7 @@ tight_detect_smooth_image24(VncState *vs, int w, int h)
4549c1
     int pixels = 0;
4549c1
     int pix, left[3];
4549c1
     unsigned int errors;
4549c1
-    unsigned char *buf = vs->tight.tight.buffer;
4549c1
+    unsigned char *buf = vs->tight->tight.buffer;
4549c1
 
4549c1
     /*
4549c1
      * If client is big-endian, color samples begin from the second
4549c1
@@ -214,7 +214,7 @@ tight_detect_smooth_image24(VncState *vs, int w, int h)
4549c1
         int pixels = 0;                                                 \
4549c1
         int sample, sum, left[3];                                       \
4549c1
         unsigned int errors;                                            \
4549c1
-        unsigned char *buf = vs->tight.tight.buffer;                    \
4549c1
+        unsigned char *buf = vs->tight->tight.buffer;                    \
4549c1
                                                                         \
4549c1
         endian = 0; /* FIXME: ((vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) != \
4549c1
                       (vs->ds->surface->flags & QEMU_BIG_ENDIAN_FLAG)); */ \
4549c1
@@ -294,8 +294,8 @@ static int
4549c1
 tight_detect_smooth_image(VncState *vs, int w, int h)
4549c1
 {
4549c1
     unsigned int errors;
4549c1
-    int compression = vs->tight.compression;
4549c1
-    int quality = vs->tight.quality;
4549c1
+    int compression = vs->tight->compression;
4549c1
+    int quality = vs->tight->quality;
4549c1
 
4549c1
     if (!vs->vd->lossy) {
4549c1
         return 0;
4549c1
@@ -307,7 +307,7 @@ tight_detect_smooth_image(VncState *vs, int w, int h)
4549c1
         return 0;
4549c1
     }
4549c1
 
4549c1
-    if (vs->tight.quality != (uint8_t)-1) {
4549c1
+    if (vs->tight->quality != (uint8_t)-1) {
4549c1
         if (w * h < VNC_TIGHT_JPEG_MIN_RECT_SIZE) {
4549c1
             return 0;
4549c1
         }
4549c1
@@ -318,9 +318,9 @@ tight_detect_smooth_image(VncState *vs, int w, int h)
4549c1
     }
4549c1
 
4549c1
     if (vs->client_pf.bytes_per_pixel == 4) {
4549c1
-        if (vs->tight.pixel24) {
4549c1
+        if (vs->tight->pixel24) {
4549c1
             errors = tight_detect_smooth_image24(vs, w, h);
4549c1
-            if (vs->tight.quality != (uint8_t)-1) {
4549c1
+            if (vs->tight->quality != (uint8_t)-1) {
4549c1
                 return (errors < tight_conf[quality].jpeg_threshold24);
4549c1
             }
4549c1
             return (errors < tight_conf[compression].gradient_threshold24);
4549c1
@@ -350,7 +350,7 @@ tight_detect_smooth_image(VncState *vs, int w, int h)
4549c1
         uint##bpp##_t c0, c1, ci;                                       \
4549c1
         int i, n0, n1;                                                  \
4549c1
                                                                         \
4549c1
-        data = (uint##bpp##_t *)vs->tight.tight.buffer;                 \
4549c1
+        data = (uint##bpp##_t *)vs->tight->tight.buffer;                \
4549c1
                                                                         \
4549c1
         c0 = data[0];                                                   \
4549c1
         i = 1;                                                          \
4549c1
@@ -421,9 +421,9 @@ static int tight_fill_palette(VncState *vs, int x, int y,
4549c1
 {
4549c1
     int max;
4549c1
 
4549c1
-    max = count / tight_conf[vs->tight.compression].idx_max_colors_divisor;
4549c1
+    max = count / tight_conf[vs->tight->compression].idx_max_colors_divisor;
4549c1
     if (max < 2 &&
4549c1
-        count >= tight_conf[vs->tight.compression].mono_min_rect_size) {
4549c1
+        count >= tight_conf[vs->tight->compression].mono_min_rect_size) {
4549c1
         max = 2;
4549c1
     }
4549c1
     if (max >= 256) {
4549c1
@@ -555,7 +555,7 @@ tight_filter_gradient24(VncState *vs, uint8_t *buf, int w, int h)
4549c1
     int x, y, c;
4549c1
 
4549c1
     buf32 = (uint32_t *)buf;
4549c1
-    memset(vs->tight.gradient.buffer, 0, w * 3 * sizeof(int));
4549c1
+    memset(vs->tight->gradient.buffer, 0, w * 3 * sizeof(int));
4549c1
 
4549c1
     if (1 /* FIXME: (vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) ==
4549c1
              (vs->ds->surface->flags & QEMU_BIG_ENDIAN_FLAG) */) {
4549c1
@@ -573,7 +573,7 @@ tight_filter_gradient24(VncState *vs, uint8_t *buf, int w, int h)
4549c1
             upper[c] = 0;
4549c1
             here[c] = 0;
4549c1
         }
4549c1
-        prev = (int *)vs->tight.gradient.buffer;
4549c1
+        prev = (int *)vs->tight->gradient.buffer;
4549c1
         for (x = 0; x < w; x++) {
4549c1
             pix32 = *buf32++;
4549c1
             for (c = 0; c < 3; c++) {
4549c1
@@ -613,7 +613,7 @@ tight_filter_gradient24(VncState *vs, uint8_t *buf, int w, int h)
4549c1
         int prediction;                                                 \
4549c1
         int x, y, c;                                                    \
4549c1
                                                                         \
4549c1
-        memset (vs->tight.gradient.buffer, 0, w * 3 * sizeof(int));     \
4549c1
+        memset(vs->tight->gradient.buffer, 0, w * 3 * sizeof(int));     \
4549c1
                                                                         \
4549c1
         endian = 0; /* FIXME: ((vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) != \
4549c1
                        (vs->ds->surface->flags & QEMU_BIG_ENDIAN_FLAG)); */ \
4549c1
@@ -630,7 +630,7 @@ tight_filter_gradient24(VncState *vs, uint8_t *buf, int w, int h)
4549c1
                 upper[c] = 0;                                           \
4549c1
                 here[c] = 0;                                            \
4549c1
             }                                                           \
4549c1
-            prev = (int *)vs->tight.gradient.buffer;                    \
4549c1
+            prev = (int *)vs->tight->gradient.buffer;                    \
4549c1
             for (x = 0; x < w; x++) {                                   \
4549c1
                 pix = *buf;                                             \
4549c1
                 if (endian) {                                           \
4549c1
@@ -786,7 +786,7 @@ static void extend_solid_area(VncState *vs, int x, int y, int w, int h,
4549c1
 static int tight_init_stream(VncState *vs, int stream_id,
4549c1
                              int level, int strategy)
4549c1
 {
4549c1
-    z_streamp zstream = &vs->tight.stream[stream_id];
4549c1
+    z_streamp zstream = &vs->tight->stream[stream_id];
4549c1
 
4549c1
     if (zstream->opaque == NULL) {
4549c1
         int err;
4549c1
@@ -804,15 +804,15 @@ static int tight_init_stream(VncState *vs, int stream_id,
4549c1
             return -1;
4549c1
         }
4549c1
 
4549c1
-        vs->tight.levels[stream_id] = level;
4549c1
+        vs->tight->levels[stream_id] = level;
4549c1
         zstream->opaque = vs;
4549c1
     }
4549c1
 
4549c1
-    if (vs->tight.levels[stream_id] != level) {
4549c1
+    if (vs->tight->levels[stream_id] != level) {
4549c1
         if (deflateParams(zstream, level, strategy) != Z_OK) {
4549c1
             return -1;
4549c1
         }
4549c1
-        vs->tight.levels[stream_id] = level;
4549c1
+        vs->tight->levels[stream_id] = level;
4549c1
     }
4549c1
     return 0;
4549c1
 }
4549c1
@@ -840,11 +840,11 @@ static void tight_send_compact_size(VncState *vs, size_t len)
4549c1
 static int tight_compress_data(VncState *vs, int stream_id, size_t bytes,
4549c1
                                int level, int strategy)
4549c1
 {
4549c1
-    z_streamp zstream = &vs->tight.stream[stream_id];
4549c1
+    z_streamp zstream = &vs->tight->stream[stream_id];
4549c1
     int previous_out;
4549c1
 
4549c1
     if (bytes < VNC_TIGHT_MIN_TO_COMPRESS) {
4549c1
-        vnc_write(vs, vs->tight.tight.buffer, vs->tight.tight.offset);
4549c1
+        vnc_write(vs, vs->tight->tight.buffer, vs->tight->tight.offset);
4549c1
         return bytes;
4549c1
     }
4549c1
 
4549c1
@@ -853,13 +853,13 @@ static int tight_compress_data(VncState *vs, int stream_id, size_t bytes,
4549c1
     }
4549c1
 
4549c1
     /* reserve memory in output buffer */
4549c1
-    buffer_reserve(&vs->tight.zlib, bytes + 64);
4549c1
+    buffer_reserve(&vs->tight->zlib, bytes + 64);
4549c1
 
4549c1
     /* set pointers */
4549c1
-    zstream->next_in = vs->tight.tight.buffer;
4549c1
-    zstream->avail_in = vs->tight.tight.offset;
4549c1
-    zstream->next_out = vs->tight.zlib.buffer + vs->tight.zlib.offset;
4549c1
-    zstream->avail_out = vs->tight.zlib.capacity - vs->tight.zlib.offset;
4549c1
+    zstream->next_in = vs->tight->tight.buffer;
4549c1
+    zstream->avail_in = vs->tight->tight.offset;
4549c1
+    zstream->next_out = vs->tight->zlib.buffer + vs->tight->zlib.offset;
4549c1
+    zstream->avail_out = vs->tight->zlib.capacity - vs->tight->zlib.offset;
4549c1
     previous_out = zstream->avail_out;
4549c1
     zstream->data_type = Z_BINARY;
4549c1
 
4549c1
@@ -869,14 +869,14 @@ static int tight_compress_data(VncState *vs, int stream_id, size_t bytes,
4549c1
         return -1;
4549c1
     }
4549c1
 
4549c1
-    vs->tight.zlib.offset = vs->tight.zlib.capacity - zstream->avail_out;
4549c1
+    vs->tight->zlib.offset = vs->tight->zlib.capacity - zstream->avail_out;
4549c1
     /* ...how much data has actually been produced by deflate() */
4549c1
     bytes = previous_out - zstream->avail_out;
4549c1
 
4549c1
     tight_send_compact_size(vs, bytes);
4549c1
-    vnc_write(vs, vs->tight.zlib.buffer, bytes);
4549c1
+    vnc_write(vs, vs->tight->zlib.buffer, bytes);
4549c1
 
4549c1
-    buffer_reset(&vs->tight.zlib);
4549c1
+    buffer_reset(&vs->tight->zlib);
4549c1
 
4549c1
     return bytes;
4549c1
 }
4549c1
@@ -928,16 +928,17 @@ static int send_full_color_rect(VncState *vs, int x, int y, int w, int h)
4549c1
 
4549c1
     vnc_write_u8(vs, stream << 4); /* no flushing, no filter */
4549c1
 
4549c1
-    if (vs->tight.pixel24) {
4549c1
-        tight_pack24(vs, vs->tight.tight.buffer, w * h, &vs->tight.tight.offset);
4549c1
+    if (vs->tight->pixel24) {
4549c1
+        tight_pack24(vs, vs->tight->tight.buffer, w * h,
4549c1
+                     &vs->tight->tight.offset);
4549c1
         bytes = 3;
4549c1
     } else {
4549c1
         bytes = vs->client_pf.bytes_per_pixel;
4549c1
     }
4549c1
 
4549c1
     bytes = tight_compress_data(vs, stream, w * h * bytes,
4549c1
-                                tight_conf[vs->tight.compression].raw_zlib_level,
4549c1
-                                Z_DEFAULT_STRATEGY);
4549c1
+                            tight_conf[vs->tight->compression].raw_zlib_level,
4549c1
+                            Z_DEFAULT_STRATEGY);
4549c1
 
4549c1
     return (bytes >= 0);
4549c1
 }
4549c1
@@ -948,14 +949,14 @@ static int send_solid_rect(VncState *vs)
4549c1
 
4549c1
     vnc_write_u8(vs, VNC_TIGHT_FILL << 4); /* no flushing, no filter */
4549c1
 
4549c1
-    if (vs->tight.pixel24) {
4549c1
-        tight_pack24(vs, vs->tight.tight.buffer, 1, &vs->tight.tight.offset);
4549c1
+    if (vs->tight->pixel24) {
4549c1
+        tight_pack24(vs, vs->tight->tight.buffer, 1, &vs->tight->tight.offset);
4549c1
         bytes = 3;
4549c1
     } else {
4549c1
         bytes = vs->client_pf.bytes_per_pixel;
4549c1
     }
4549c1
 
4549c1
-    vnc_write(vs, vs->tight.tight.buffer, bytes);
4549c1
+    vnc_write(vs, vs->tight->tight.buffer, bytes);
4549c1
     return 1;
4549c1
 }
4549c1
 
4549c1
@@ -964,7 +965,7 @@ static int send_mono_rect(VncState *vs, int x, int y,
4549c1
 {
4549c1
     ssize_t bytes;
4549c1
     int stream = 1;
4549c1
-    int level = tight_conf[vs->tight.compression].mono_zlib_level;
4549c1
+    int level = tight_conf[vs->tight->compression].mono_zlib_level;
4549c1
 
4549c1
 #ifdef CONFIG_VNC_PNG
4549c1
     if (tight_can_send_png_rect(vs, w, h)) {
4549c1
@@ -992,26 +993,26 @@ static int send_mono_rect(VncState *vs, int x, int y,
4549c1
         uint32_t buf[2] = {bg, fg};
4549c1
         size_t ret = sizeof (buf);
4549c1
 
4549c1
-        if (vs->tight.pixel24) {
4549c1
+        if (vs->tight->pixel24) {
4549c1
             tight_pack24(vs, (unsigned char*)buf, 2, &ret;;
4549c1
         }
4549c1
         vnc_write(vs, buf, ret);
4549c1
 
4549c1
-        tight_encode_mono_rect32(vs->tight.tight.buffer, w, h, bg, fg);
4549c1
+        tight_encode_mono_rect32(vs->tight->tight.buffer, w, h, bg, fg);
4549c1
         break;
4549c1
     }
4549c1
     case 2:
4549c1
         vnc_write(vs, &bg, 2);
4549c1
         vnc_write(vs, &fg, 2);
4549c1
-        tight_encode_mono_rect16(vs->tight.tight.buffer, w, h, bg, fg);
4549c1
+        tight_encode_mono_rect16(vs->tight->tight.buffer, w, h, bg, fg);
4549c1
         break;
4549c1
     default:
4549c1
         vnc_write_u8(vs, bg);
4549c1
         vnc_write_u8(vs, fg);
4549c1
-        tight_encode_mono_rect8(vs->tight.tight.buffer, w, h, bg, fg);
4549c1
+        tight_encode_mono_rect8(vs->tight->tight.buffer, w, h, bg, fg);
4549c1
         break;
4549c1
     }
4549c1
-    vs->tight.tight.offset = bytes;
4549c1
+    vs->tight->tight.offset = bytes;
4549c1
 
4549c1
     bytes = tight_compress_data(vs, stream, bytes, level, Z_DEFAULT_STRATEGY);
4549c1
     return (bytes >= 0);
4549c1
@@ -1041,7 +1042,7 @@ static void write_palette(int idx, uint32_t color, void *opaque)
4549c1
 static bool send_gradient_rect(VncState *vs, int x, int y, int w, int h)
4549c1
 {
4549c1
     int stream = 3;
4549c1
-    int level = tight_conf[vs->tight.compression].gradient_zlib_level;
4549c1
+    int level = tight_conf[vs->tight->compression].gradient_zlib_level;
4549c1
     ssize_t bytes;
4549c1
 
4549c1
     if (vs->client_pf.bytes_per_pixel == 1) {
4549c1
@@ -1051,23 +1052,23 @@ static bool send_gradient_rect(VncState *vs, int x, int y, int w, int h)
4549c1
     vnc_write_u8(vs, (stream | VNC_TIGHT_EXPLICIT_FILTER) << 4);
4549c1
     vnc_write_u8(vs, VNC_TIGHT_FILTER_GRADIENT);
4549c1
 
4549c1
-    buffer_reserve(&vs->tight.gradient, w * 3 * sizeof (int));
4549c1
+    buffer_reserve(&vs->tight->gradient, w * 3 * sizeof(int));
4549c1
 
4549c1
-    if (vs->tight.pixel24) {
4549c1
-        tight_filter_gradient24(vs, vs->tight.tight.buffer, w, h);
4549c1
+    if (vs->tight->pixel24) {
4549c1
+        tight_filter_gradient24(vs, vs->tight->tight.buffer, w, h);
4549c1
         bytes = 3;
4549c1
     } else if (vs->client_pf.bytes_per_pixel == 4) {
4549c1
-        tight_filter_gradient32(vs, (uint32_t *)vs->tight.tight.buffer, w, h);
4549c1
+        tight_filter_gradient32(vs, (uint32_t *)vs->tight->tight.buffer, w, h);
4549c1
         bytes = 4;
4549c1
     } else {
4549c1
-        tight_filter_gradient16(vs, (uint16_t *)vs->tight.tight.buffer, w, h);
4549c1
+        tight_filter_gradient16(vs, (uint16_t *)vs->tight->tight.buffer, w, h);
4549c1
         bytes = 2;
4549c1
     }
4549c1
 
4549c1
-    buffer_reset(&vs->tight.gradient);
4549c1
+    buffer_reset(&vs->tight->gradient);
4549c1
 
4549c1
     bytes = w * h * bytes;
4549c1
-    vs->tight.tight.offset = bytes;
4549c1
+    vs->tight->tight.offset = bytes;
4549c1
 
4549c1
     bytes = tight_compress_data(vs, stream, bytes,
4549c1
                                 level, Z_FILTERED);
4549c1
@@ -1078,7 +1079,7 @@ static int send_palette_rect(VncState *vs, int x, int y,
4549c1
                              int w, int h, VncPalette *palette)
4549c1
 {
4549c1
     int stream = 2;
4549c1
-    int level = tight_conf[vs->tight.compression].idx_zlib_level;
4549c1
+    int level = tight_conf[vs->tight->compression].idx_zlib_level;
4549c1
     int colors;
4549c1
     ssize_t bytes;
4549c1
 
4549c1
@@ -1105,12 +1106,12 @@ static int send_palette_rect(VncState *vs, int x, int y,
4549c1
         palette_iter(palette, write_palette, &priv;;
4549c1
         vnc_write(vs, header, sizeof(header));
4549c1
 
4549c1
-        if (vs->tight.pixel24) {
4549c1
+        if (vs->tight->pixel24) {
4549c1
             tight_pack24(vs, vs->output.buffer + old_offset, colors, &offset);
4549c1
             vs->output.offset = old_offset + offset;
4549c1
         }
4549c1
 
4549c1
-        tight_encode_indexed_rect32(vs->tight.tight.buffer, w * h, palette);
4549c1
+        tight_encode_indexed_rect32(vs->tight->tight.buffer, w * h, palette);
4549c1
         break;
4549c1
     }
4549c1
     case 2:
4549c1
@@ -1120,7 +1121,7 @@ static int send_palette_rect(VncState *vs, int x, int y,
4549c1
 
4549c1
         palette_iter(palette, write_palette, &priv;;
4549c1
         vnc_write(vs, header, sizeof(header));
4549c1
-        tight_encode_indexed_rect16(vs->tight.tight.buffer, w * h, palette);
4549c1
+        tight_encode_indexed_rect16(vs->tight->tight.buffer, w * h, palette);
4549c1
         break;
4549c1
     }
4549c1
     default:
4549c1
@@ -1128,7 +1129,7 @@ static int send_palette_rect(VncState *vs, int x, int y,
4549c1
         break;
4549c1
     }
4549c1
     bytes = w * h;
4549c1
-    vs->tight.tight.offset = bytes;
4549c1
+    vs->tight->tight.offset = bytes;
4549c1
 
4549c1
     bytes = tight_compress_data(vs, stream, bytes,
4549c1
                                 level, Z_DEFAULT_STRATEGY);
4549c1
@@ -1147,7 +1148,7 @@ static int send_palette_rect(VncState *vs, int x, int y,
4549c1
 static void jpeg_init_destination(j_compress_ptr cinfo)
4549c1
 {
4549c1
     VncState *vs = cinfo->client_data;
4549c1
-    Buffer *buffer = &vs->tight.jpeg;
4549c1
+    Buffer *buffer = &vs->tight->jpeg;
4549c1
 
4549c1
     cinfo->dest->next_output_byte = (JOCTET *)buffer->buffer + buffer->offset;
4549c1
     cinfo->dest->free_in_buffer = (size_t)(buffer->capacity - buffer->offset);
4549c1
@@ -1157,7 +1158,7 @@ static void jpeg_init_destination(j_compress_ptr cinfo)
4549c1
 static boolean jpeg_empty_output_buffer(j_compress_ptr cinfo)
4549c1
 {
4549c1
     VncState *vs = cinfo->client_data;
4549c1
-    Buffer *buffer = &vs->tight.jpeg;
4549c1
+    Buffer *buffer = &vs->tight->jpeg;
4549c1
 
4549c1
     buffer->offset = buffer->capacity;
4549c1
     buffer_reserve(buffer, 2048);
4549c1
@@ -1169,7 +1170,7 @@ static boolean jpeg_empty_output_buffer(j_compress_ptr cinfo)
4549c1
 static void jpeg_term_destination(j_compress_ptr cinfo)
4549c1
 {
4549c1
     VncState *vs = cinfo->client_data;
4549c1
-    Buffer *buffer = &vs->tight.jpeg;
4549c1
+    Buffer *buffer = &vs->tight->jpeg;
4549c1
 
4549c1
     buffer->offset = buffer->capacity - cinfo->dest->free_in_buffer;
4549c1
 }
4549c1
@@ -1188,7 +1189,7 @@ static int send_jpeg_rect(VncState *vs, int x, int y, int w, int h, int quality)
4549c1
         return send_full_color_rect(vs, x, y, w, h);
4549c1
     }
4549c1
 
4549c1
-    buffer_reserve(&vs->tight.jpeg, 2048);
4549c1
+    buffer_reserve(&vs->tight->jpeg, 2048);
4549c1
 
4549c1
     cinfo.err = jpeg_std_error(&jerr);
4549c1
     jpeg_create_compress(&cinfo);
4549c1
@@ -1223,9 +1224,9 @@ static int send_jpeg_rect(VncState *vs, int x, int y, int w, int h, int quality)
4549c1
 
4549c1
     vnc_write_u8(vs, VNC_TIGHT_JPEG << 4);
4549c1
 
4549c1
-    tight_send_compact_size(vs, vs->tight.jpeg.offset);
4549c1
-    vnc_write(vs, vs->tight.jpeg.buffer, vs->tight.jpeg.offset);
4549c1
-    buffer_reset(&vs->tight.jpeg);
4549c1
+    tight_send_compact_size(vs, vs->tight->jpeg.offset);
4549c1
+    vnc_write(vs, vs->tight->jpeg.buffer, vs->tight->jpeg.offset);
4549c1
+    buffer_reset(&vs->tight->jpeg);
4549c1
 
4549c1
     return 1;
4549c1
 }
4549c1
@@ -1241,7 +1242,7 @@ static void write_png_palette(int idx, uint32_t pix, void *opaque)
4549c1
     VncState *vs = priv->vs;
4549c1
     png_colorp color = &priv->png_palette[idx];
4549c1
 
4549c1
-    if (vs->tight.pixel24)
4549c1
+    if (vs->tight->pixel24)
4549c1
     {
4549c1
         color->red = (pix >> vs->client_pf.rshift) & vs->client_pf.rmax;
4549c1
         color->green = (pix >> vs->client_pf.gshift) & vs->client_pf.gmax;
4549c1
@@ -1268,10 +1269,10 @@ static void png_write_data(png_structp png_ptr, png_bytep data,
4549c1
 {
4549c1
     VncState *vs = png_get_io_ptr(png_ptr);
4549c1
 
4549c1
-    buffer_reserve(&vs->tight.png, vs->tight.png.offset + length);
4549c1
-    memcpy(vs->tight.png.buffer + vs->tight.png.offset, data, length);
4549c1
+    buffer_reserve(&vs->tight->png, vs->tight->png.offset + length);
4549c1
+    memcpy(vs->tight->png.buffer + vs->tight->png.offset, data, length);
4549c1
 
4549c1
-    vs->tight.png.offset += length;
4549c1
+    vs->tight->png.offset += length;
4549c1
 }
4549c1
 
4549c1
 static void png_flush_data(png_structp png_ptr)
4549c1
@@ -1296,8 +1297,8 @@ static int send_png_rect(VncState *vs, int x, int y, int w, int h,
4549c1
     png_infop info_ptr;
4549c1
     png_colorp png_palette = NULL;
4549c1
     pixman_image_t *linebuf;
4549c1
-    int level = tight_png_conf[vs->tight.compression].png_zlib_level;
4549c1
-    int filters = tight_png_conf[vs->tight.compression].png_filters;
4549c1
+    int level = tight_png_conf[vs->tight->compression].png_zlib_level;
4549c1
+    int filters = tight_png_conf[vs->tight->compression].png_filters;
4549c1
     uint8_t *buf;
4549c1
     int dy;
4549c1
 
4549c1
@@ -1341,21 +1342,23 @@ static int send_png_rect(VncState *vs, int x, int y, int w, int h,
4549c1
         png_set_PLTE(png_ptr, info_ptr, png_palette, palette_size(palette));
4549c1
 
4549c1
         if (vs->client_pf.bytes_per_pixel == 4) {
4549c1
-            tight_encode_indexed_rect32(vs->tight.tight.buffer, w * h, palette);
4549c1
+            tight_encode_indexed_rect32(vs->tight->tight.buffer, w * h,
4549c1
+                                        palette);
4549c1
         } else {
4549c1
-            tight_encode_indexed_rect16(vs->tight.tight.buffer, w * h, palette);
4549c1
+            tight_encode_indexed_rect16(vs->tight->tight.buffer, w * h,
4549c1
+                                        palette);
4549c1
         }
4549c1
     }
4549c1
 
4549c1
     png_write_info(png_ptr, info_ptr);
4549c1
 
4549c1
-    buffer_reserve(&vs->tight.png, 2048);
4549c1
+    buffer_reserve(&vs->tight->png, 2048);
4549c1
     linebuf = qemu_pixman_linebuf_create(PIXMAN_BE_r8g8b8, w);
4549c1
     buf = (uint8_t *)pixman_image_get_data(linebuf);
4549c1
     for (dy = 0; dy < h; dy++)
4549c1
     {
4549c1
         if (color_type == PNG_COLOR_TYPE_PALETTE) {
4549c1
-            memcpy(buf, vs->tight.tight.buffer + (dy * w), w);
4549c1
+            memcpy(buf, vs->tight->tight.buffer + (dy * w), w);
4549c1
         } else {
4549c1
             qemu_pixman_linebuf_fill(linebuf, vs->vd->server, w, x, y + dy);
4549c1
         }
4549c1
@@ -1373,27 +1376,27 @@ static int send_png_rect(VncState *vs, int x, int y, int w, int h,
4549c1
 
4549c1
     vnc_write_u8(vs, VNC_TIGHT_PNG << 4);
4549c1
 
4549c1
-    tight_send_compact_size(vs, vs->tight.png.offset);
4549c1
-    vnc_write(vs, vs->tight.png.buffer, vs->tight.png.offset);
4549c1
-    buffer_reset(&vs->tight.png);
4549c1
+    tight_send_compact_size(vs, vs->tight->png.offset);
4549c1
+    vnc_write(vs, vs->tight->png.buffer, vs->tight->png.offset);
4549c1
+    buffer_reset(&vs->tight->png);
4549c1
     return 1;
4549c1
 }
4549c1
 #endif /* CONFIG_VNC_PNG */
4549c1
 
4549c1
 static void vnc_tight_start(VncState *vs)
4549c1
 {
4549c1
-    buffer_reset(&vs->tight.tight);
4549c1
+    buffer_reset(&vs->tight->tight);
4549c1
 
4549c1
     // make the output buffer be the zlib buffer, so we can compress it later
4549c1
-    vs->tight.tmp = vs->output;
4549c1
-    vs->output = vs->tight.tight;
4549c1
+    vs->tight->tmp = vs->output;
4549c1
+    vs->output = vs->tight->tight;
4549c1
 }
4549c1
 
4549c1
 static void vnc_tight_stop(VncState *vs)
4549c1
 {
4549c1
     // switch back to normal output/zlib buffers
4549c1
-    vs->tight.tight = vs->output;
4549c1
-    vs->output = vs->tight.tmp;
4549c1
+    vs->tight->tight = vs->output;
4549c1
+    vs->output = vs->tight->tmp;
4549c1
 }
4549c1
 
4549c1
 static int send_sub_rect_nojpeg(VncState *vs, int x, int y, int w, int h,
4549c1
@@ -1427,9 +1430,9 @@ static int send_sub_rect_jpeg(VncState *vs, int x, int y, int w, int h,
4549c1
     int ret;
4549c1
 
4549c1
     if (colors == 0) {
4549c1
-        if (force || (tight_jpeg_conf[vs->tight.quality].jpeg_full &&
4549c1
+        if (force || (tight_jpeg_conf[vs->tight->quality].jpeg_full &&
4549c1
                       tight_detect_smooth_image(vs, w, h))) {
4549c1
-            int quality = tight_conf[vs->tight.quality].jpeg_quality;
4549c1
+            int quality = tight_conf[vs->tight->quality].jpeg_quality;
4549c1
 
4549c1
             ret = send_jpeg_rect(vs, x, y, w, h, quality);
4549c1
         } else {
4549c1
@@ -1441,9 +1444,9 @@ static int send_sub_rect_jpeg(VncState *vs, int x, int y, int w, int h,
4549c1
         ret = send_mono_rect(vs, x, y, w, h, bg, fg);
4549c1
     } else if (colors <= 256) {
4549c1
         if (force || (colors > 96 &&
4549c1
-                      tight_jpeg_conf[vs->tight.quality].jpeg_idx &&
4549c1
+                      tight_jpeg_conf[vs->tight->quality].jpeg_idx &&
4549c1
                       tight_detect_smooth_image(vs, w, h))) {
4549c1
-            int quality = tight_conf[vs->tight.quality].jpeg_quality;
4549c1
+            int quality = tight_conf[vs->tight->quality].jpeg_quality;
4549c1
 
4549c1
             ret = send_jpeg_rect(vs, x, y, w, h, quality);
4549c1
         } else {
4549c1
@@ -1467,20 +1470,20 @@ static int send_sub_rect(VncState *vs, int x, int y, int w, int h)
4549c1
     bool allow_jpeg = true;
4549c1
 #endif
4549c1
 
4549c1
-    vnc_framebuffer_update(vs, x, y, w, h, vs->tight.type);
4549c1
+    vnc_framebuffer_update(vs, x, y, w, h, vs->tight->type);
4549c1
 
4549c1
     vnc_tight_start(vs);
4549c1
     vnc_raw_send_framebuffer_update(vs, x, y, w, h);
4549c1
     vnc_tight_stop(vs);
4549c1
 
4549c1
 #ifdef CONFIG_VNC_JPEG
4549c1
-    if (!vs->vd->non_adaptive && vs->tight.quality != (uint8_t)-1) {
4549c1
+    if (!vs->vd->non_adaptive && vs->tight->quality != (uint8_t)-1) {
4549c1
         double freq = vnc_update_freq(vs, x, y, w, h);
4549c1
 
4549c1
-        if (freq < tight_jpeg_conf[vs->tight.quality].jpeg_freq_min) {
4549c1
+        if (freq < tight_jpeg_conf[vs->tight->quality].jpeg_freq_min) {
4549c1
             allow_jpeg = false;
4549c1
         }
4549c1
-        if (freq >= tight_jpeg_conf[vs->tight.quality].jpeg_freq_threshold) {
4549c1
+        if (freq >= tight_jpeg_conf[vs->tight->quality].jpeg_freq_threshold) {
4549c1
             force_jpeg = true;
4549c1
             vnc_sent_lossy_rect(vs, x, y, w, h);
4549c1
         }
4549c1
@@ -1490,7 +1493,7 @@ static int send_sub_rect(VncState *vs, int x, int y, int w, int h)
4549c1
     colors = tight_fill_palette(vs, x, y, w * h, &fg, &bg, &palette);
4549c1
 
4549c1
 #ifdef CONFIG_VNC_JPEG
4549c1
-    if (allow_jpeg && vs->tight.quality != (uint8_t)-1) {
4549c1
+    if (allow_jpeg && vs->tight->quality != (uint8_t)-1) {
4549c1
         ret = send_sub_rect_jpeg(vs, x, y, w, h, bg, fg, colors, palette,
4549c1
                                  force_jpeg);
4549c1
     } else {
4549c1
@@ -1506,7 +1509,7 @@ static int send_sub_rect(VncState *vs, int x, int y, int w, int h)
4549c1
 
4549c1
 static int send_sub_rect_solid(VncState *vs, int x, int y, int w, int h)
4549c1
 {
4549c1
-    vnc_framebuffer_update(vs, x, y, w, h, vs->tight.type);
4549c1
+    vnc_framebuffer_update(vs, x, y, w, h, vs->tight->type);
4549c1
 
4549c1
     vnc_tight_start(vs);
4549c1
     vnc_raw_send_framebuffer_update(vs, x, y, w, h);
4549c1
@@ -1524,8 +1527,8 @@ static int send_rect_simple(VncState *vs, int x, int y, int w, int h,
4549c1
     int rw, rh;
4549c1
     int n = 0;
4549c1
 
4549c1
-    max_size = tight_conf[vs->tight.compression].max_rect_size;
4549c1
-    max_width = tight_conf[vs->tight.compression].max_rect_width;
4549c1
+    max_size = tight_conf[vs->tight->compression].max_rect_size;
4549c1
+    max_width = tight_conf[vs->tight->compression].max_rect_width;
4549c1
 
4549c1
     if (split && (w > max_width || w * h > max_size)) {
4549c1
         max_sub_width = (w > max_width) ? max_width : w;
4549c1
@@ -1634,16 +1637,16 @@ static int tight_send_framebuffer_update(VncState *vs, int x, int y,
4549c1
 
4549c1
     if (vs->client_pf.bytes_per_pixel == 4 && vs->client_pf.rmax == 0xFF &&
4549c1
         vs->client_pf.bmax == 0xFF && vs->client_pf.gmax == 0xFF) {
4549c1
-        vs->tight.pixel24 = true;
4549c1
+        vs->tight->pixel24 = true;
4549c1
     } else {
4549c1
-        vs->tight.pixel24 = false;
4549c1
+        vs->tight->pixel24 = false;
4549c1
     }
4549c1
 
4549c1
 #ifdef CONFIG_VNC_JPEG
4549c1
-    if (vs->tight.quality != (uint8_t)-1) {
4549c1
+    if (vs->tight->quality != (uint8_t)-1) {
4549c1
         double freq = vnc_update_freq(vs, x, y, w, h);
4549c1
 
4549c1
-        if (freq > tight_jpeg_conf[vs->tight.quality].jpeg_freq_threshold) {
4549c1
+        if (freq > tight_jpeg_conf[vs->tight->quality].jpeg_freq_threshold) {
4549c1
             return send_rect_simple(vs, x, y, w, h, false);
4549c1
         }
4549c1
     }
4549c1
@@ -1655,8 +1658,8 @@ static int tight_send_framebuffer_update(VncState *vs, int x, int y,
4549c1
 
4549c1
     /* Calculate maximum number of rows in one non-solid rectangle. */
4549c1
 
4549c1
-    max_rows = tight_conf[vs->tight.compression].max_rect_size;
4549c1
-    max_rows /= MIN(tight_conf[vs->tight.compression].max_rect_width, w);
4549c1
+    max_rows = tight_conf[vs->tight->compression].max_rect_size;
4549c1
+    max_rows /= MIN(tight_conf[vs->tight->compression].max_rect_width, w);
4549c1
 
4549c1
     return find_large_solid_color_rect(vs, x, y, w, h, max_rows);
4549c1
 }
4549c1
@@ -1664,33 +1667,33 @@ static int tight_send_framebuffer_update(VncState *vs, int x, int y,
4549c1
 int vnc_tight_send_framebuffer_update(VncState *vs, int x, int y,
4549c1
                                       int w, int h)
4549c1
 {
4549c1
-    vs->tight.type = VNC_ENCODING_TIGHT;
4549c1
+    vs->tight->type = VNC_ENCODING_TIGHT;
4549c1
     return tight_send_framebuffer_update(vs, x, y, w, h);
4549c1
 }
4549c1
 
4549c1
 int vnc_tight_png_send_framebuffer_update(VncState *vs, int x, int y,
4549c1
                                           int w, int h)
4549c1
 {
4549c1
-    vs->tight.type = VNC_ENCODING_TIGHT_PNG;
4549c1
+    vs->tight->type = VNC_ENCODING_TIGHT_PNG;
4549c1
     return tight_send_framebuffer_update(vs, x, y, w, h);
4549c1
 }
4549c1
 
4549c1
 void vnc_tight_clear(VncState *vs)
4549c1
 {
4549c1
     int i;
4549c1
-    for (i=0; i<ARRAY_SIZE(vs->tight.stream); i++) {
4549c1
-        if (vs->tight.stream[i].opaque) {
4549c1
-            deflateEnd(&vs->tight.stream[i]);
4549c1
+    for (i = 0; i < ARRAY_SIZE(vs->tight->stream); i++) {
4549c1
+        if (vs->tight->stream[i].opaque) {
4549c1
+            deflateEnd(&vs->tight->stream[i]);
4549c1
         }
4549c1
     }
4549c1
 
4549c1
-    buffer_free(&vs->tight.tight);
4549c1
-    buffer_free(&vs->tight.zlib);
4549c1
-    buffer_free(&vs->tight.gradient);
4549c1
+    buffer_free(&vs->tight->tight);
4549c1
+    buffer_free(&vs->tight->zlib);
4549c1
+    buffer_free(&vs->tight->gradient);
4549c1
 #ifdef CONFIG_VNC_JPEG
4549c1
-    buffer_free(&vs->tight.jpeg);
4549c1
+    buffer_free(&vs->tight->jpeg);
4549c1
 #endif
4549c1
 #ifdef CONFIG_VNC_PNG
4549c1
-    buffer_free(&vs->tight.png);
4549c1
+    buffer_free(&vs->tight->png);
4549c1
 #endif
4549c1
 }
4549c1
diff --git a/ui/vnc-enc-zlib.c b/ui/vnc-enc-zlib.c
4549c1
index d1b97f2516..5c31fe5771 100644
4549c1
--- a/ui/vnc-enc-zlib.c
4549c1
+++ b/ui/vnc-enc-zlib.c
4549c1
@@ -75,7 +75,8 @@ static int vnc_zlib_stop(VncState *vs)
4549c1
         zstream->zalloc = vnc_zlib_zalloc;
4549c1
         zstream->zfree = vnc_zlib_zfree;
4549c1
 
4549c1
-        err = deflateInit2(zstream, vs->tight.compression, Z_DEFLATED, MAX_WBITS,
4549c1
+        err = deflateInit2(zstream, vs->tight->compression, Z_DEFLATED,
4549c1
+                           MAX_WBITS,
4549c1
                            MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY);
4549c1
 
4549c1
         if (err != Z_OK) {
4549c1
@@ -83,16 +84,16 @@ static int vnc_zlib_stop(VncState *vs)
4549c1
             return -1;
4549c1
         }
4549c1
 
4549c1
-        vs->zlib.level = vs->tight.compression;
4549c1
+        vs->zlib.level = vs->tight->compression;
4549c1
         zstream->opaque = vs;
4549c1
     }
4549c1
 
4549c1
-    if (vs->tight.compression != vs->zlib.level) {
4549c1
-        if (deflateParams(zstream, vs->tight.compression,
4549c1
+    if (vs->tight->compression != vs->zlib.level) {
4549c1
+        if (deflateParams(zstream, vs->tight->compression,
4549c1
                           Z_DEFAULT_STRATEGY) != Z_OK) {
4549c1
             return -1;
4549c1
         }
4549c1
-        vs->zlib.level = vs->tight.compression;
4549c1
+        vs->zlib.level = vs->tight->compression;
4549c1
     }
4549c1
 
4549c1
     // reserve memory in output buffer
4549c1
diff --git a/ui/vnc-enc-zrle-template.c b/ui/vnc-enc-zrle-template.c
4549c1
index 70ae624ee9..6687f8cb0e 100644
4549c1
--- a/ui/vnc-enc-zrle-template.c
4549c1
+++ b/ui/vnc-enc-zrle-template.c
4549c1
@@ -96,7 +96,7 @@ static void ZRLE_ENCODE(VncState *vs, int x, int y, int w, int h,
4549c1
 static void ZRLE_ENCODE_TILE(VncState *vs, ZRLE_PIXEL *data, int w, int h,
4549c1
                              int zywrle_level)
4549c1
 {
4549c1
-    VncPalette *palette = &vs->zrle.palette;
4549c1
+    VncPalette *palette = &vs->zrle->palette;
4549c1
 
4549c1
     int runs = 0;
4549c1
     int single_pixels = 0;
4549c1
diff --git a/ui/vnc-enc-zrle.c b/ui/vnc-enc-zrle.c
4549c1
index ed3b48465d..c85758fe2e 100644
4549c1
--- a/ui/vnc-enc-zrle.c
4549c1
+++ b/ui/vnc-enc-zrle.c
4549c1
@@ -36,18 +36,18 @@ static const int bits_per_packed_pixel[] = {
4549c1
 
4549c1
 static void vnc_zrle_start(VncState *vs)
4549c1
 {
4549c1
-    buffer_reset(&vs->zrle.zrle);
4549c1
+    buffer_reset(&vs->zrle->zrle);
4549c1
 
4549c1
     /* make the output buffer be the zlib buffer, so we can compress it later */
4549c1
-    vs->zrle.tmp = vs->output;
4549c1
-    vs->output = vs->zrle.zrle;
4549c1
+    vs->zrle->tmp = vs->output;
4549c1
+    vs->output = vs->zrle->zrle;
4549c1
 }
4549c1
 
4549c1
 static void vnc_zrle_stop(VncState *vs)
4549c1
 {
4549c1
     /* switch back to normal output/zlib buffers */
4549c1
-    vs->zrle.zrle = vs->output;
4549c1
-    vs->output = vs->zrle.tmp;
4549c1
+    vs->zrle->zrle = vs->output;
4549c1
+    vs->output = vs->zrle->tmp;
4549c1
 }
4549c1
 
4549c1
 static void *zrle_convert_fb(VncState *vs, int x, int y, int w, int h,
4549c1
@@ -55,24 +55,24 @@ static void *zrle_convert_fb(VncState *vs, int x, int y, int w, int h,
4549c1
 {
4549c1
     Buffer tmp;
4549c1
 
4549c1
-    buffer_reset(&vs->zrle.fb);
4549c1
-    buffer_reserve(&vs->zrle.fb, w * h * bpp + bpp);
4549c1
+    buffer_reset(&vs->zrle->fb);
4549c1
+    buffer_reserve(&vs->zrle->fb, w * h * bpp + bpp);
4549c1
 
4549c1
     tmp = vs->output;
4549c1
-    vs->output = vs->zrle.fb;
4549c1
+    vs->output = vs->zrle->fb;
4549c1
 
4549c1
     vnc_raw_send_framebuffer_update(vs, x, y, w, h);
4549c1
 
4549c1
-    vs->zrle.fb = vs->output;
4549c1
+    vs->zrle->fb = vs->output;
4549c1
     vs->output = tmp;
4549c1
-    return vs->zrle.fb.buffer;
4549c1
+    return vs->zrle->fb.buffer;
4549c1
 }
4549c1
 
4549c1
 static int zrle_compress_data(VncState *vs, int level)
4549c1
 {
4549c1
-    z_streamp zstream = &vs->zrle.stream;
4549c1
+    z_streamp zstream = &vs->zrle->stream;
4549c1
 
4549c1
-    buffer_reset(&vs->zrle.zlib);
4549c1
+    buffer_reset(&vs->zrle->zlib);
4549c1
 
4549c1
     if (zstream->opaque != vs) {
4549c1
         int err;
4549c1
@@ -92,13 +92,13 @@ static int zrle_compress_data(VncState *vs, int level)
4549c1
     }
4549c1
 
4549c1
     /* reserve memory in output buffer */
4549c1
-    buffer_reserve(&vs->zrle.zlib, vs->zrle.zrle.offset + 64);
4549c1
+    buffer_reserve(&vs->zrle->zlib, vs->zrle->zrle.offset + 64);
4549c1
 
4549c1
     /* set pointers */
4549c1
-    zstream->next_in = vs->zrle.zrle.buffer;
4549c1
-    zstream->avail_in = vs->zrle.zrle.offset;
4549c1
-    zstream->next_out = vs->zrle.zlib.buffer + vs->zrle.zlib.offset;
4549c1
-    zstream->avail_out = vs->zrle.zlib.capacity - vs->zrle.zlib.offset;
4549c1
+    zstream->next_in = vs->zrle->zrle.buffer;
4549c1
+    zstream->avail_in = vs->zrle->zrle.offset;
4549c1
+    zstream->next_out = vs->zrle->zlib.buffer + vs->zrle->zlib.offset;
4549c1
+    zstream->avail_out = vs->zrle->zlib.capacity - vs->zrle->zlib.offset;
4549c1
     zstream->data_type = Z_BINARY;
4549c1
 
4549c1
     /* start encoding */
4549c1
@@ -107,8 +107,8 @@ static int zrle_compress_data(VncState *vs, int level)
4549c1
         return -1;
4549c1
     }
4549c1
 
4549c1
-    vs->zrle.zlib.offset = vs->zrle.zlib.capacity - zstream->avail_out;
4549c1
-    return vs->zrle.zlib.offset;
4549c1
+    vs->zrle->zlib.offset = vs->zrle->zlib.capacity - zstream->avail_out;
4549c1
+    return vs->zrle->zlib.offset;
4549c1
 }
4549c1
 
4549c1
 /* Try to work out whether to use RLE and/or a palette.  We do this by
4549c1
@@ -259,14 +259,14 @@ static int zrle_send_framebuffer_update(VncState *vs, int x, int y,
4549c1
     size_t bytes;
4549c1
     int zywrle_level;
4549c1
 
4549c1
-    if (vs->zrle.type == VNC_ENCODING_ZYWRLE) {
4549c1
-        if (!vs->vd->lossy || vs->tight.quality == (uint8_t)-1
4549c1
-            || vs->tight.quality == 9) {
4549c1
+    if (vs->zrle->type == VNC_ENCODING_ZYWRLE) {
4549c1
+        if (!vs->vd->lossy || vs->tight->quality == (uint8_t)-1
4549c1
+            || vs->tight->quality == 9) {
4549c1
             zywrle_level = 0;
4549c1
-            vs->zrle.type = VNC_ENCODING_ZRLE;
4549c1
-        } else if (vs->tight.quality < 3) {
4549c1
+            vs->zrle->type = VNC_ENCODING_ZRLE;
4549c1
+        } else if (vs->tight->quality < 3) {
4549c1
             zywrle_level = 3;
4549c1
-        } else if (vs->tight.quality < 6) {
4549c1
+        } else if (vs->tight->quality < 6) {
4549c1
             zywrle_level = 2;
4549c1
         } else {
4549c1
             zywrle_level = 1;
4549c1
@@ -337,30 +337,30 @@ static int zrle_send_framebuffer_update(VncState *vs, int x, int y,
4549c1
 
4549c1
     vnc_zrle_stop(vs);
4549c1
     bytes = zrle_compress_data(vs, Z_DEFAULT_COMPRESSION);
4549c1
-    vnc_framebuffer_update(vs, x, y, w, h, vs->zrle.type);
4549c1
+    vnc_framebuffer_update(vs, x, y, w, h, vs->zrle->type);
4549c1
     vnc_write_u32(vs, bytes);
4549c1
-    vnc_write(vs, vs->zrle.zlib.buffer, vs->zrle.zlib.offset);
4549c1
+    vnc_write(vs, vs->zrle->zlib.buffer, vs->zrle->zlib.offset);
4549c1
     return 1;
4549c1
 }
4549c1
 
4549c1
 int vnc_zrle_send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
4549c1
 {
4549c1
-    vs->zrle.type = VNC_ENCODING_ZRLE;
4549c1
+    vs->zrle->type = VNC_ENCODING_ZRLE;
4549c1
     return zrle_send_framebuffer_update(vs, x, y, w, h);
4549c1
 }
4549c1
 
4549c1
 int vnc_zywrle_send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
4549c1
 {
4549c1
-    vs->zrle.type = VNC_ENCODING_ZYWRLE;
4549c1
+    vs->zrle->type = VNC_ENCODING_ZYWRLE;
4549c1
     return zrle_send_framebuffer_update(vs, x, y, w, h);
4549c1
 }
4549c1
 
4549c1
 void vnc_zrle_clear(VncState *vs)
4549c1
 {
4549c1
-    if (vs->zrle.stream.opaque) {
4549c1
-        deflateEnd(&vs->zrle.stream);
4549c1
+    if (vs->zrle->stream.opaque) {
4549c1
+        deflateEnd(&vs->zrle->stream);
4549c1
     }
4549c1
-    buffer_free(&vs->zrle.zrle);
4549c1
-    buffer_free(&vs->zrle.fb);
4549c1
-    buffer_free(&vs->zrle.zlib);
4549c1
+    buffer_free(&vs->zrle->zrle);
4549c1
+    buffer_free(&vs->zrle->fb);
4549c1
+    buffer_free(&vs->zrle->zlib);
4549c1
 }
4549c1
diff --git a/ui/vnc.c b/ui/vnc.c
4549c1
index 99b1ab14a5..0acdd3870f 100644
4549c1
--- a/ui/vnc.c
4549c1
+++ b/ui/vnc.c
4549c1
@@ -1141,6 +1141,8 @@ void vnc_disconnect_finish(VncState *vs)
4549c1
         g_free(vs->lossy_rect[i]);
4549c1
     }
4549c1
     g_free(vs->lossy_rect);
4549c1
+    g_free(vs->zrle);
4549c1
+    g_free(vs->tight);
4549c1
     g_free(vs);
4549c1
 }
4549c1
 
4549c1
@@ -2003,8 +2005,8 @@ static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
4549c1
 
4549c1
     vs->features = 0;
4549c1
     vs->vnc_encoding = 0;
4549c1
-    vs->tight.compression = 9;
4549c1
-    vs->tight.quality = -1; /* Lossless by default */
4549c1
+    vs->tight->compression = 9;
4549c1
+    vs->tight->quality = -1; /* Lossless by default */
4549c1
     vs->absolute = -1;
4549c1
 
4549c1
     /*
4549c1
@@ -2069,11 +2071,11 @@ static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
4549c1
             vs->features |= VNC_FEATURE_LED_STATE_MASK;
4549c1
             break;
4549c1
         case VNC_ENCODING_COMPRESSLEVEL0 ... VNC_ENCODING_COMPRESSLEVEL0 + 9:
4549c1
-            vs->tight.compression = (enc & 0x0F);
4549c1
+            vs->tight->compression = (enc & 0x0F);
4549c1
             break;
4549c1
         case VNC_ENCODING_QUALITYLEVEL0 ... VNC_ENCODING_QUALITYLEVEL0 + 9:
4549c1
             if (vs->vd->lossy) {
4549c1
-                vs->tight.quality = (enc & 0x0F);
4549c1
+                vs->tight->quality = (enc & 0x0F);
4549c1
             }
4549c1
             break;
4549c1
         default:
4549c1
@@ -2906,6 +2908,8 @@ static void vnc_connect(VncDisplay *vd, int csock, int skipauth, bool websocket)
4549c1
     int i;
4549c1
 
4549c1
     vs->csock = csock;
4549c1
+    vs->zrle = g_new0(VncZrle, 1);
4549c1
+    vs->tight = g_new0(VncTight, 1);
4549c1
 
4549c1
     if (skipauth) {
4549c1
 	vs->auth = VNC_AUTH_NONE;
4549c1
diff --git a/ui/vnc.h b/ui/vnc.h
4549c1
index f9c5f89950..99af25748a 100644
4549c1
--- a/ui/vnc.h
4549c1
+++ b/ui/vnc.h
4549c1
@@ -346,10 +346,10 @@ struct VncState
4549c1
     /* Encoding specific, if you add something here, don't forget to
4549c1
      *  update vnc_async_encoding_start()
4549c1
      */
4549c1
-    VncTight tight;
4549c1
+    VncTight *tight;
4549c1
     VncZlib zlib;
4549c1
     VncHextile hextile;
4549c1
-    VncZrle zrle;
4549c1
+    VncZrle *zrle;
4549c1
     VncZywrle zywrle;
4549c1
 
4549c1
     Notifier mouse_mode_notifier;
4549c1
-- 
4549c1
2.18.2
4549c1