diff options
| author | Mattias EngdegÄrd | 2020-08-18 12:58:12 +0200 |
|---|---|---|
| committer | Mattias EngdegÄrd | 2020-08-20 19:39:14 +0200 |
| commit | bf60338d6dd02b4d848229878c8e14182f6f861f (patch) | |
| tree | bbeb8e4a96460f3da3b8bc44fee10a3dc3be70c8 /src | |
| parent | 3b8a6ef18543cc56ed4524ac3d6a6843e818f6fb (diff) | |
| download | emacs-bf60338d6dd02b4d848229878c8e14182f6f861f.tar.gz emacs-bf60338d6dd02b4d848229878c8e14182f6f861f.zip | |
Fix NS crash on invalid frame title string (bug#42904)
Instead of blindly assuming that all Emacs strings are valid UTF-8,
which they are not, use a more careful conversion going via UTF-16
which is what NSString uses internally. Unpaired surrogates will
still go through to the NSString objects, but the NS libs handle them
gracefully.
* src/nsterm.h (EmacsString): New category.
* src/nsfns.m (all_nonzero_ascii): New helper function.
([NSString stringWithLispString:]): New method.
(ns_set_name_internal): Use new conversion method.
Diffstat (limited to 'src')
| -rw-r--r-- | src/nsfns.m | 65 | ||||
| -rw-r--r-- | src/nsterm.h | 5 |
2 files changed, 56 insertions, 14 deletions
diff --git a/src/nsfns.m b/src/nsfns.m index 628233ea0dd..5fca15588d0 100644 --- a/src/nsfns.m +++ b/src/nsfns.m | |||
| @@ -401,26 +401,15 @@ ns_set_icon_name (struct frame *f, Lisp_Object arg, Lisp_Object oldval) | |||
| 401 | static void | 401 | static void |
| 402 | ns_set_name_internal (struct frame *f, Lisp_Object name) | 402 | ns_set_name_internal (struct frame *f, Lisp_Object name) |
| 403 | { | 403 | { |
| 404 | Lisp_Object encoded_name, encoded_icon_name; | ||
| 405 | NSString *str; | ||
| 406 | NSView *view = FRAME_NS_VIEW (f); | 404 | NSView *view = FRAME_NS_VIEW (f); |
| 407 | 405 | NSString *str = [NSString stringWithLispString: name]; | |
| 408 | |||
| 409 | encoded_name = ENCODE_UTF_8 (name); | ||
| 410 | |||
| 411 | str = [NSString stringWithUTF8String: SSDATA (encoded_name)]; | ||
| 412 | |||
| 413 | 406 | ||
| 414 | /* Don't change the name if it's already NAME. */ | 407 | /* Don't change the name if it's already NAME. */ |
| 415 | if (! [[[view window] title] isEqualToString: str]) | 408 | if (! [[[view window] title] isEqualToString: str]) |
| 416 | [[view window] setTitle: str]; | 409 | [[view window] setTitle: str]; |
| 417 | 410 | ||
| 418 | if (!STRINGP (f->icon_name)) | 411 | if (STRINGP (f->icon_name)) |
| 419 | encoded_icon_name = encoded_name; | 412 | str = [NSString stringWithLispString: f->icon_name]; |
| 420 | else | ||
| 421 | encoded_icon_name = ENCODE_UTF_8 (f->icon_name); | ||
| 422 | |||
| 423 | str = [NSString stringWithUTF8String: SSDATA (encoded_icon_name)]; | ||
| 424 | 413 | ||
| 425 | if ([[view window] miniwindowTitle] | 414 | if ([[view window] miniwindowTitle] |
| 426 | && ! [[[view window] miniwindowTitle] isEqualToString: str]) | 415 | && ! [[[view window] miniwindowTitle] isEqualToString: str]) |
| @@ -3031,6 +3020,54 @@ DEFUN ("ns-show-character-palette", | |||
| 3031 | #endif | 3020 | #endif |
| 3032 | 3021 | ||
| 3033 | 3022 | ||
| 3023 | /* Whether N bytes at STR are in the [0,127] range. */ | ||
| 3024 | static bool | ||
| 3025 | all_nonzero_ascii (unsigned char *str, ptrdiff_t n) | ||
| 3026 | { | ||
| 3027 | for (ptrdiff_t i = 0; i < n; i++) | ||
| 3028 | if (str[i] < 1 || str[i] > 127) | ||
| 3029 | return false; | ||
| 3030 | return true; | ||
| 3031 | } | ||
| 3032 | |||
| 3033 | @implementation NSString (EmacsString) | ||
| 3034 | /* Make an NSString from a Lisp string. */ | ||
| 3035 | + (NSString *)stringWithLispString:(Lisp_Object)string | ||
| 3036 | { | ||
| 3037 | /* Shortcut for the common case. */ | ||
| 3038 | if (all_nonzero_ascii (SDATA (string), SBYTES (string))) | ||
| 3039 | return [NSString stringWithCString: SSDATA (string) | ||
| 3040 | encoding: NSASCIIStringEncoding]; | ||
| 3041 | string = string_to_multibyte (string); | ||
| 3042 | |||
| 3043 | /* Now the string is multibyte; convert to UTF-16. */ | ||
| 3044 | unichar *chars = xmalloc (4 * SCHARS (string)); | ||
| 3045 | unichar *d = chars; | ||
| 3046 | const unsigned char *s = SDATA (string); | ||
| 3047 | const unsigned char *end = s + SBYTES (string); | ||
| 3048 | while (s < end) | ||
| 3049 | { | ||
| 3050 | int c = string_char_advance (&s); | ||
| 3051 | /* We pass unpaired surrogates through, because they are typically | ||
| 3052 | handled fairly well by the NS libraries (displayed with distinct | ||
| 3053 | glyphs etc). */ | ||
| 3054 | if (c <= 0xffff) | ||
| 3055 | *d++ = c; | ||
| 3056 | else if (c <= 0x10ffff) | ||
| 3057 | { | ||
| 3058 | *d++ = 0xd800 + (c & 0x3ff); | ||
| 3059 | *d++ = 0xdc00 + ((c - 0x10000) >> 10); | ||
| 3060 | } | ||
| 3061 | else | ||
| 3062 | *d++ = 0xfffd; /* Not valid for UTF-16. */ | ||
| 3063 | } | ||
| 3064 | NSString *str = [NSString stringWithCharacters: chars | ||
| 3065 | length: d - chars]; | ||
| 3066 | xfree (chars); | ||
| 3067 | return str; | ||
| 3068 | } | ||
| 3069 | @end | ||
| 3070 | |||
| 3034 | /* ========================================================================== | 3071 | /* ========================================================================== |
| 3035 | 3072 | ||
| 3036 | Lisp interface declaration | 3073 | Lisp interface declaration |
diff --git a/src/nsterm.h b/src/nsterm.h index a511fef5b98..ab868ed3442 100644 --- a/src/nsterm.h +++ b/src/nsterm.h | |||
| @@ -361,6 +361,11 @@ typedef id instancetype; | |||
| 361 | 361 | ||
| 362 | @end | 362 | @end |
| 363 | 363 | ||
| 364 | |||
| 365 | @interface NSString (EmacsString) | ||
| 366 | + (NSString *)stringWithLispString:(Lisp_Object)string; | ||
| 367 | @end | ||
| 368 | |||
| 364 | /* ========================================================================== | 369 | /* ========================================================================== |
| 365 | 370 | ||
| 366 | The Emacs application | 371 | The Emacs application |