Skip to content

Commit

Permalink
4.4.0: Make code panic safe
Browse files Browse the repository at this point in the history
  • Loading branch information
DoumanAsh committed Jan 23, 2022
1 parent 3248b6f commit 4a5b7aa
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 12 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "clipboard-win"
version = "4.3.0"
version = "4.4.0"
authors = ["Douman <douman@gmx.se>"]
description = "Provides simple way to interact with Windows clipboard."
license = "BSL-1.0"
Expand Down
23 changes: 16 additions & 7 deletions src/raw.rs
Expand Up @@ -31,7 +31,7 @@ use alloc::borrow::ToOwned;
use alloc::format;

use crate::{SysResult, formats};
use crate::utils::{RawMem};
use crate::utils::{unlikely_empty_size_result, RawMem};

#[inline(always)]
fn free_dc(data: HDC) {
Expand Down Expand Up @@ -221,7 +221,9 @@ pub fn count_formats() -> Option<usize> {
///It is safe to pass uninit memory
pub fn get(format: u32, out: &mut [u8]) -> SysResult<usize> {
let size = out.len();
debug_assert!(size > 0);
if size == 0 {
return Ok(unlikely_empty_size_result());
}
let out_ptr = out.as_mut_ptr();

let ptr = RawMem::from_borrowed(get_clipboard_data(format)?);
Expand Down Expand Up @@ -272,7 +274,9 @@ pub fn set(format: u32, data: &[u8]) -> SysResult<()> {
/// This function does not empty the clipboard before setting the data.
pub fn set_without_clear(format: u32, data: &[u8]) -> SysResult<()> {
let size = data.len();
debug_assert!(size > 0);
if size == 0 {
return Ok(unlikely_empty_size_result());
}

let mem = RawMem::new_global_mem(size)?;

Expand Down Expand Up @@ -326,7 +330,9 @@ pub fn get_string(out: &mut alloc::vec::Vec<u8>) -> SysResult<usize> {
///Copies unicode string onto clipboard, performing necessary conversions, returning true on
///success.
pub fn set_string(data: &str) -> SysResult<()> {
debug_assert!(data.len() > 0);
if data.is_empty() {
return Ok(unlikely_empty_size_result());
}

let size = unsafe {
MultiByteToWideChar(CP_UTF8, 0, data.as_ptr() as *const _, data.len() as _, ptr::null_mut(), 0)
Expand Down Expand Up @@ -472,7 +478,7 @@ pub fn get_bitmap(out: &mut alloc::vec::Vec<u8>) -> SysResult<usize> {
mem::size_of::<BITMAPINFOHEADER>() + mem::size_of::<RGBQUAD>() * (1 << clr_bits)
} else {
mem::size_of::<BITMAPINFOHEADER>()
});
})?;

let header = unsafe {
&mut *(header_storage.get() as *mut BITMAPINFO)
Expand Down Expand Up @@ -775,9 +781,12 @@ pub fn format_name_big(format: u32) -> Option<String> {
///
///# Note:
///
///Custom format identifier is in range `0xC000...0xFFFF`.
///- Custom format identifier is in range `0xC000...0xFFFF`.
///- Function fails if input is not null terminated string.
pub unsafe fn register_raw_format(name: &[u16]) -> Option<NonZeroU32> {
debug_assert_eq!(name[name.len()-1], b'\0' as u16);
if name[name.len()-1] != b'\0' as u16 {
return unlikely_empty_size_result()
}
NonZeroU32::new(RegisterClipboardFormatW(name.as_ptr()) )
}

Expand Down
25 changes: 21 additions & 4 deletions src/utils.rs
@@ -1,13 +1,26 @@
use core::{mem, ptr};

use winapi::ctypes::c_void;
use error_code::SystemError;

use crate::SysResult;

const GHND: winapi::ctypes::c_uint = 0x42;

const BYTES_LAYOUT: alloc::alloc::Layout = alloc::alloc::Layout::new::<u8>();

#[cold]
#[inline(never)]
pub fn unlikely_empty_size_result<T: Default>() -> T {
Default::default()
}

#[cold]
#[inline(never)]
pub fn unlikely_last_error() -> SystemError {
SystemError::last()
}

#[inline]
fn noop(_: *mut c_void) {
}
Expand Down Expand Up @@ -46,20 +59,24 @@ pub struct RawMem(Scope<*mut c_void>);

impl RawMem {
#[inline(always)]
pub fn new_rust_mem(size: usize) -> Self {
pub fn new_rust_mem(size: usize) -> SysResult<Self> {
let mem = unsafe {
alloc::alloc::alloc_zeroed(alloc::alloc::Layout::array::<u8>(size).expect("To create layout for bytes"))
};
debug_assert!(!mem.is_null());
Self(Scope(mem as _, free_rust_mem))

if mem.is_null() {
Err(unlikely_last_error())
} else {
Ok(Self(Scope(mem as _, free_rust_mem)))
}
}

#[inline(always)]
pub fn new_global_mem(size: usize) -> SysResult<Self> {
unsafe {
let mem = winapi::um::winbase::GlobalAlloc(GHND, size as _);
if mem.is_null() {
Err(error_code::SystemError::last())
Err(unlikely_last_error())
} else {
Ok(Self(Scope(mem, free_global_mem)))
}
Expand Down

0 comments on commit 4a5b7aa

Please sign in to comment.