Skip to content

Commit

Permalink
Wrap GetConsoleScreenBufferInfo() instead of uninitialized() to avoid…
Browse files Browse the repository at this point in the history
… undefined behavior
  • Loading branch information
rhysd committed Aug 22, 2019
1 parent 53ed376 commit 8edc047
Showing 1 changed file with 45 additions and 48 deletions.
93 changes: 45 additions & 48 deletions src/win.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ use winapi::um::consoleapi::{GetConsoleMode, SetConsoleMode};
use winapi::um::fileapi::{CreateFileA, OPEN_EXISTING};
use winapi::um::handleapi::{CloseHandle, INVALID_HANDLE_VALUE};
use winapi::um::wincon::FillConsoleOutputAttribute;
use winapi::um::wincon::{FillConsoleOutputCharacterW, GetConsoleScreenBufferInfo, COORD};
use winapi::um::wincon::{
FillConsoleOutputCharacterW, GetConsoleScreenBufferInfo, CONSOLE_SCREEN_BUFFER_INFO, COORD,
};
use winapi::um::wincon::{SetConsoleCursorPosition, SetConsoleTextAttribute};
use winapi::um::wincon::{BACKGROUND_INTENSITY, ENABLE_VIRTUAL_TERMINAL_PROCESSING};
use winapi::um::winnt::{FILE_SHARE_WRITE, GENERIC_READ, GENERIC_WRITE, HANDLE};
Expand Down Expand Up @@ -162,12 +164,22 @@ fn test_conout() {
}

#[rustversion::before(1.36)]
unsafe fn uninitialized<T>() -> T {
::std::mem::uninitialized()
unsafe fn get_console_screen_buffer_info(handle: HANDLE) -> io::Result<CONSOLE_SCREEN_BUFFER_INFO> {
let mut buffer_info = ::std::mem::uninitialized();
if GetConsoleScreenBufferInfo(handle, &mut buffer_info) == 0 {
Err(io::Error::last_os_error())
} else {
Ok(buffer_info)
}
}
#[rustversion::since(1.36)]
unsafe fn uninitialized<T>() -> T {
::std::mem::MaybeUninit::uninit().assume_init()
unsafe fn get_console_screen_buffer_info(handle: HANDLE) -> io::Result<CONSOLE_SCREEN_BUFFER_INFO> {
let mut buffer_info = ::std::mem::MaybeUninit::uninit().assume_init();
if GetConsoleScreenBufferInfo(handle, &mut buffer_info) == 0 {
Err(io::Error::last_os_error())
} else {
Ok(buffer_info)
}
}

impl WinConsoleInfo {
Expand All @@ -178,13 +190,9 @@ impl WinConsoleInfo {
let bg;
let handle = conout()?;
unsafe {
let mut buffer_info = uninitialized();
if GetConsoleScreenBufferInfo(*handle, &mut buffer_info) != 0 {
fg = bits_to_color(buffer_info.wAttributes);
bg = bits_to_color(buffer_info.wAttributes >> 4);
} else {
return Err(io::Error::last_os_error());
}
let buffer_info = get_console_screen_buffer_info(*handle)?;
fg = bits_to_color(buffer_info.wAttributes);
bg = bits_to_color(buffer_info.wAttributes >> 4);
}
Ok(WinConsoleInfo {
def_foreground: fg,
Expand Down Expand Up @@ -335,28 +343,24 @@ impl<T: Write + Send> Terminal for WinConsole<T> {
let _unused = self.buf.flush();
let handle = conout()?;
unsafe {
let mut buffer_info = uninitialized();
if GetConsoleScreenBufferInfo(*handle, &mut buffer_info) != 0 {
let (x, y) = (
buffer_info.dwCursorPosition.X,
buffer_info.dwCursorPosition.Y,
);
if y == 0 {
// Even though this might want to be a CursorPositionInvalid, on Unix there
// is no checking to see if the cursor is already on the first line.
// I'm not sure what the ideal behavior is, but I think it'd be silly to have
// cursor_up fail in this case.
let buffer_info = get_console_screen_buffer_info(*handle)?;
let (x, y) = (
buffer_info.dwCursorPosition.X,
buffer_info.dwCursorPosition.Y,
);
if y == 0 {
// Even though this might want to be a CursorPositionInvalid, on Unix there
// is no checking to see if the cursor is already on the first line.
// I'm not sure what the ideal behavior is, but I think it'd be silly to have
// cursor_up fail in this case.
Ok(())
} else {
let pos = COORD { X: x, Y: y - 1 };
if SetConsoleCursorPosition(*handle, pos) != 0 {
Ok(())
} else {
let pos = COORD { X: x, Y: y - 1 };
if SetConsoleCursorPosition(*handle, pos) != 0 {
Ok(())
} else {
Err(io::Error::last_os_error().into())
}
Err(io::Error::last_os_error().into())
}
} else {
Err(io::Error::last_os_error().into())
}
}
}
Expand All @@ -365,10 +369,7 @@ impl<T: Write + Send> Terminal for WinConsole<T> {
let _unused = self.buf.flush();
let handle = conout()?;
unsafe {
let mut buffer_info = uninitialized();
if GetConsoleScreenBufferInfo(*handle, &mut buffer_info) == 0 {
return Err(io::Error::last_os_error().into());
}
let buffer_info = get_console_screen_buffer_info(*handle)?;
let pos = buffer_info.dwCursorPosition;
let size = buffer_info.dwSize;
let num = (size.X - pos.X) as DWORD;
Expand All @@ -391,21 +392,17 @@ impl<T: Write + Send> Terminal for WinConsole<T> {
let _unused = self.buf.flush();
let handle = conout()?;
unsafe {
let mut buffer_info = uninitialized();
if GetConsoleScreenBufferInfo(*handle, &mut buffer_info) != 0 {
let COORD { X: x, Y: y } = buffer_info.dwCursorPosition;
if x == 0 {
Err(Error::CursorDestinationInvalid)
let buffer_info = get_console_screen_buffer_info(*handle)?;
let COORD { X: x, Y: y } = buffer_info.dwCursorPosition;
if x == 0 {
Err(Error::CursorDestinationInvalid)
} else {
let pos = COORD { X: 0, Y: y };
if SetConsoleCursorPosition(*handle, pos) != 0 {
Ok(())
} else {
let pos = COORD { X: 0, Y: y };
if SetConsoleCursorPosition(*handle, pos) != 0 {
Ok(())
} else {
Err(io::Error::last_os_error().into())
}
Err(io::Error::last_os_error().into())
}
} else {
Err(io::Error::last_os_error().into())
}
}
}
Expand Down

0 comments on commit 8edc047

Please sign in to comment.