diff --git a/src/platform/windows.rs b/src/platform/windows.rs index 86583d38a..105267427 100644 --- a/src/platform/windows.rs +++ b/src/platform/windows.rs @@ -139,12 +139,13 @@ pub fn get_cursor_data(hcursor: u64) -> ResultType { width, height, bm_mask.bmWidthBytes, + bm_mask.bmHeight, ) > 0; } if do_outline { let mut outline = Vec::new(); outline.resize(((width + 2) * (height + 2) * 4) as _, 0); - drawOutline(outline.as_mut_ptr(), cbits.as_ptr(), width, height); + drawOutline(outline.as_mut_ptr(), cbits.as_ptr(), width, height, outline.len() as _); cbits = outline; width += 2; height += 2; @@ -285,7 +286,7 @@ fn fix_cursor_mask( cbits: &mut Vec, width: usize, height: usize, - width_bytes: usize, + bm_width_bytes: usize, ) -> bool { let mut pix_idx = 0; for _ in 0..height { @@ -298,12 +299,18 @@ fn fix_cursor_mask( } let packed_width_bytes = (width + 7) >> 3; + let bm_size = mbits.len(); + let c_size = cbits.len(); // Pack and invert bitmap data (mbits) // borrow from tigervnc for y in 0..height { for x in 0..packed_width_bytes { - mbits[y * packed_width_bytes + x] = !mbits[y * width_bytes + x]; + let a = y * packed_width_bytes + x; + let b = y * bm_width_bytes + x; + if a < bm_size && b < bm_size { + mbits[a] = !mbits[b]; + } } } @@ -315,15 +322,23 @@ fn fix_cursor_mask( let mut bitmask: u8 = 0x80; for x in 0..width { let mask_idx = y * packed_width_bytes + (x >> 3); - let pix_idx = y * bytes_row + (x << 2); - if (mbits[mask_idx] & bitmask) == 0 { - for b1 in 0..4 { - if cbits[pix_idx + b1] != 0 { - mbits[mask_idx] ^= bitmask; - for b2 in b1..4 { - cbits[pix_idx + b2] = 0x00; + if mask_idx < bm_size { + let pix_idx = y * bytes_row + (x << 2); + if (mbits[mask_idx] & bitmask) == 0 { + for b1 in 0..4 { + let a = pix_idx + b1; + if a < c_size { + if cbits[a] != 0 { + mbits[mask_idx] ^= bitmask; + for b2 in b1..4 { + let b = pix_idx + b2; + if b < c_size { + cbits[b] = 0x00; + } + } + break; + } } - break; } } } @@ -339,11 +354,12 @@ fn fix_cursor_mask( for y in 0..height { for x in 0..width { let mask_idx = y * packed_width_bytes + (x >> 3); - let alpha = if (mbits[mask_idx] << (x & 0x7)) & 0x80 == 0 { - 0 - } else { - 255 - }; + let mut alpha = 255; + if mask_idx < bm_size { + if (mbits[mask_idx] << (x & 0x7)) & 0x80 == 0 { + alpha = 0; + } + } let a = cbits[pix_idx + 2]; let b = cbits[pix_idx + 1]; let c = cbits[pix_idx]; @@ -377,9 +393,9 @@ extern "C" { fn LaunchProcessWin(cmd: *const u16, session_id: DWORD, as_user: BOOL) -> HANDLE; fn selectInputDesktop() -> BOOL; fn inputDesktopSelected() -> BOOL; - fn handleMask(out: *mut u8, mask: *const u8, width: i32, height: i32, bmWidthBytes: i32) + fn handleMask(out: *mut u8, mask: *const u8, width: i32, height: i32, bmWidthBytes: i32, bmHeight: i32) -> i32; - fn drawOutline(out: *mut u8, in_: *const u8, width: i32, height: i32); + fn drawOutline(out: *mut u8, in_: *const u8, width: i32, height: i32, out_size: i32); fn get_di_bits(out: *mut u8, dc: HDC, hbmColor: HBITMAP, width: i32, height: i32) -> i32; fn blank_screen(v: BOOL); fn BlockInput(v: BOOL) -> BOOL; diff --git a/src/windows.cc b/src/windows.cc index 8a937a060..e9a7294cd 100644 --- a/src/windows.cc +++ b/src/windows.cc @@ -192,10 +192,13 @@ extern "C" return true; } - int handleMask(uint8_t *rwbuffer, const uint8_t *mask, int width, int height, int bmWidthBytes) + int handleMask(uint8_t *rwbuffer, const uint8_t *mask, int width, int height, int bmWidthBytes, int bmHeight) { auto andMask = mask; - auto xorMask = mask + height * bmWidthBytes; + auto andMaskSize = bmWidthBytes * bmHeight; + auto offset = height * bmWidthBytes; + auto xorMask = mask + offset; + auto xorMaskSize = andMaskSize - offset; int doOutline = 0; for (int y = 0; y < height; y++) { @@ -204,7 +207,7 @@ extern "C" int byte = y * bmWidthBytes + x / 8; int bit = 7 - x % 8; - if (!(andMask[byte] & (1 << bit))) + if (byte < andMaskSize && !(andMask[byte] & (1 << bit))) { // Valid pixel, so make it opaque rwbuffer[3] = 0xff; @@ -215,7 +218,7 @@ extern "C" else rwbuffer[0] = rwbuffer[1] = rwbuffer[2] = 0; } - else if (xorMask[byte] & (1 << bit)) + else if (byte < xorMaskSize && xorMask[byte] & (1 << bit)) { // Replace any XORed pixels with black, because RFB doesn't support // XORing of cursors. XORing is used for the I-beam cursor, which is most @@ -240,10 +243,12 @@ extern "C" return doOutline; } - void drawOutline(uint8_t *out0, const uint8_t *in0, int width, int height) + void drawOutline(uint8_t *out0, const uint8_t *in0, int width, int height, int out0_size) { auto in = in0; - auto out = out0 + width * 4 + 4; + auto out0_end = out0 + out0_size; + auto offset = width * 4 + 4; + auto out = out0 + offset; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) @@ -251,12 +256,16 @@ extern "C" // Visible pixel? if (in[3] > 0) { + auto n = 4 * 3; + auto p = out - (width + 2) * 4 - 4; // Outline above... - memset(out - (width + 2) * 4 - 4, 0xff, 4 * 3); + if (p >= out0 && p + n <= out0_end) memset(p, 0xff, n); // ...besides... - memset(out - 4, 0xff, 4 * 3); + p = out - 4; + if (p + n <= out0_end) memset(p, 0xff, n); // ...and above - memset(out + (width + 2) * 4 - 4, 0xff, 4 * 3); + p = out + (width + 2) * 4 - 4; + if (p + n <= out0_end) memset(p, 0xff, n); } in += 4; out += 4; @@ -267,12 +276,12 @@ extern "C" // Pass 2, overwrite with actual cursor in = in0; - out = out0 + width * 4 + 4; + out = out0 + offset; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { - if (in[3] > 0) + if (in[3] > 0 && out + 4 <= out0_end) memcpy(out, in, 4); in += 4; out += 4;