gpui: Handle null string pointer in window::insert_text (#12446)

`[NSString UTF8String]` sometimes returns null (it's documented as
such), and when it does, zed crashes in `window::insert_text`. I'm
running into this sometimes when using alt-d to delete forward. It
usually only happens with multiple cursors, but sometimes with a single
cursor. It *might* only happen when using the "Unicode Hex Input"
keyboard 'Input Source' (which I started using to avoid entering weird
characters in zed when using emacs meta keybindings that I haven't
defined in zed).

When using the US English input source, alt-d always results in a call
to `insert_text`. When using the Unicode Hex Input source it usually
doesn't, but when it does `text.UTF8String()` returns null. `text` isn't
null. `[text length]` returns 1. `[text characterAtIndex: 0]` seems to
always return `56797` (an undefined utf-16 codepoint).

Release Notes:

- Fixed crash on mac when deleting with alt-d
This commit is contained in:
Sean Billig 2024-06-03 09:36:38 -07:00 committed by GitHub
parent 344e5e1cf2
commit be2df79d5c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 33 additions and 23 deletions

View File

@ -29,7 +29,10 @@ use cocoa::{
};
use objc::runtime::{BOOL, NO, YES};
use std::ops::Range;
use std::{
ffi::{c_char, CStr},
ops::Range,
};
pub(crate) use dispatcher::*;
pub(crate) use display::*;
@ -52,6 +55,21 @@ impl BoolExt for bool {
}
}
trait NSStringExt {
unsafe fn to_str(&self) -> &str;
}
impl NSStringExt for id {
unsafe fn to_str(&self) -> &str {
let cstr = self.UTF8String();
if cstr.is_null() {
""
} else {
CStr::from_ptr(cstr as *mut c_char).to_str().unwrap()
}
}
}
#[repr(C)]
#[derive(Copy, Clone, Debug)]
struct NSRange {

View File

@ -1,12 +1,12 @@
use crate::{
point, px, KeyDownEvent, KeyUpEvent, Keystroke, Modifiers, ModifiersChangedEvent, MouseButton,
MouseDownEvent, MouseExitEvent, MouseMoveEvent, MouseUpEvent, NavigationDirection, Pixels,
PlatformInput, ScrollDelta, ScrollWheelEvent, TouchPhase,
platform::mac::NSStringExt, point, px, KeyDownEvent, KeyUpEvent, Keystroke, Modifiers,
ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseExitEvent, MouseMoveEvent,
MouseUpEvent, NavigationDirection, Pixels, PlatformInput, ScrollDelta, ScrollWheelEvent,
TouchPhase,
};
use cocoa::{
appkit::{NSEvent, NSEventModifierFlags, NSEventPhase, NSEventType},
base::{id, YES},
foundation::NSString as _,
};
use core_graphics::{
event::{CGEvent, CGEventFlags, CGKeyCode},
@ -15,7 +15,7 @@ use core_graphics::{
use ctor::ctor;
use metal::foreign_types::ForeignType as _;
use objc::{class, msg_send, sel, sel_impl};
use std::{borrow::Cow, ffi::CStr, mem, os::raw::c_char, ptr};
use std::{borrow::Cow, mem, ptr};
const BACKSPACE_KEY: u16 = 0x7f;
const SPACE_KEY: u16 = b' ' as u16;
@ -243,11 +243,10 @@ impl PlatformInput {
unsafe fn parse_keystroke(native_event: id) -> Keystroke {
use cocoa::appkit::*;
let mut chars_ignoring_modifiers =
CStr::from_ptr(native_event.charactersIgnoringModifiers().UTF8String() as *mut c_char)
.to_str()
.unwrap()
.to_string();
let mut chars_ignoring_modifiers = native_event
.charactersIgnoringModifiers()
.to_str()
.to_string();
let first_char = chars_ignoring_modifiers.chars().next().map(|ch| ch as u16);
let modifiers = native_event.modifierFlags();
@ -351,9 +350,6 @@ fn chars_for_modified_key(code: CGKeyCode, cmd: bool, shift: bool) -> String {
unsafe {
let event: id = msg_send![class!(NSEvent), eventWithCGEvent: &*event];
CStr::from_ptr(event.characters().UTF8String())
.to_str()
.unwrap()
.to_string()
event.characters().to_str().to_string()
}
}

View File

@ -1,4 +1,4 @@
use super::{ns_string, renderer, MacDisplay, NSRange};
use super::{ns_string, renderer, MacDisplay, NSRange, NSStringExt};
use crate::{
platform::PlatformInputHandler, point, px, size, AnyWindowHandle, Bounds, DevicePixels,
DisplayLink, ExternalPaths, FileDropEvent, ForegroundExecutor, KeyDownEvent, Keystroke,
@ -39,7 +39,6 @@ use std::{
ffi::{c_void, CStr},
mem,
ops::Range,
os::raw::c_char,
path::PathBuf,
ptr::{self, NonNull},
rc::Rc,
@ -1711,9 +1710,8 @@ extern "C" fn insert_text(this: &Object, _: Sel, text: id, replacement_range: NS
} else {
text
};
let text = CStr::from_ptr(text.UTF8String() as *mut c_char)
.to_str()
.unwrap();
let text = text.to_str();
let replacement_range = replacement_range.to_range();
send_to_input_handler(
this,
@ -1739,9 +1737,7 @@ extern "C" fn set_marked_text(
};
let selected_range = selected_range.to_range();
let replacement_range = replacement_range.to_range();
let text = CStr::from_ptr(text.UTF8String() as *mut c_char)
.to_str()
.unwrap();
let text = text.to_str();
send_to_input_handler(
this,