MacOS: Crash after upgrade
Closed this issue · 4 comments
Please let me know if need other details...
Upgraded from enchant-2 version 2.6.9 -> 2.7.1 using homebrew, and crashes now when spell checking in emacs.
Computer is: Apple M1 Pro, running Sonoma 14.4.1 (23E224).
$ clang --version
Homebrew clang version 18.1.4
Target: arm64-apple-darwin23.4.0
Thread model: posix
InstalledDir: /opt/homebrew/opt/llvm/bin
Here's relevant lldb debug info...
Process 81951 stopped
* thread #2, name = 'org.gnu.Emacs.lisp-main', stop reason = EXC_BREAKPOINT (code=1, subcode=0x193e0d410)
frame #0: 0x0000000193e0d410 CoreFoundation`__CFStringCreateImmutableFunnel3.cold.1 + 16
CoreFoundation`__CFStringCreateImmutableFunnel3.cold.1:
-> 0x193e0d410 <+16>: brk #0x1
CoreFoundation`__CFStringMakeConstantString.cold.1:
0x193e0d414 <+0>: pacibsp
0x193e0d418 <+4>: stp x29, x30, [sp, #-0x10]!
0x193e0d41c <+8>: mov x29, sp
(lldb) bt
* thread #2, name = 'org.gnu.Emacs.lisp-main', stop reason = EXC_BREAKPOINT (code=1, subcode=0x193e0d410)
* frame #0: 0x0000000193e0d410 CoreFoundation`__CFStringCreateImmutableFunnel3.cold.1 + 16
frame #1: 0x0000000193c26fcc CoreFoundation`__CFStringCreateImmutableFunnel3 + 96
frame #2: 0x000000012e94f860 enchant_applespell.so`appleSpell_dict_check(_EnchantDict*, char const*, unsigned long) [inlined] AppleSpellChecker::checkWord(this=0x0000600003c34060, word="Automagically", len=18446744073709551615, lang="en") at applespell_checker.mm:171:19 [opt]
frame #3: 0x000000012e94f820 enchant_applespell.so`appleSpell_dict_check(me=<unavailable>, word="Automagically", len=18446744073709551615) at applespell_checker.mm:293:31 [opt]
frame #4: 0x000000012e93589c libenchant-2.2.dylib`enchant_dict_check(_self_=0x0000600001fa5b00, word_buf=<unavailable>, len=<unavailable>) at dict.vala:154:12 [opt]
frame #5: 0x000000012e90b3f4 jinx-mod.dylib`jinx_check + 132
frame #6: 0x00000001001776e4 Emacs`funcall_module + 300
frame #7: 0x0000000100147b84 Emacs`Ffuncall + 316
frame #8: 0x0000000148c03e90 jinx-a92c61a5-6c94e07d.eln`F6a696e782d2d776f72642d76616c69642d70_jinx__word_valid_p_0 + 448
frame #9: 0x000000010014b524 Emacs`__funcall_subr_block_invoke + 272
frame #10: 0x00000001001fad3c Emacs`mac_autorelease_loop + 48
frame #11: 0x000000010014ae54 Emacs`funcall_subr + 96
frame #12: 0x0000000100147b84 Emacs`Ffuncall + 316
frame #13: 0x000000010014a730 Emacs`run_hook_with_args + 336
frame #14: 0x0000000148c046fc jinx-a92c61a5-6c94e07d.eln`F6a696e782d2d636865636b2d726567696f6e_jinx__check_region_0 + 1036
frame #15: 0x000000010014b548 Emacs`__funcall_subr_block_invoke + 308
frame #16: 0x00000001001fad3c Emacs`mac_autorelease_loop + 48
frame #17: 0x000000010014ae54 Emacs`funcall_subr + 96
frame #18: 0x0000000100147b84 Emacs`Ffuncall + 316
frame #19: 0x0000000148c04248 jinx-a92c61a5-6c94e07d.eln`F6a696e782d2d636865636b2d70656e64696e67_jinx__check_pending_0 + 376
frame #20: 0x000000010014b47c Emacs`__funcall_subr_block_invoke + 104
frame #21: 0x00000001001fad3c Emacs`mac_autorelease_loop + 48
frame #22: 0x000000010014ae54 Emacs`funcall_subr + 96
frame #23: 0x0000000100147b84 Emacs`Ffuncall + 316
frame #24: 0x0000000148c05964 jinx-a92c61a5-6c94e07d.eln`F6a696e782d2d74696d65722d68616e646c6572_jinx__timer_handler_0 + 320
frame #25: 0x000000010014b514 Emacs`__funcall_subr_block_invoke + 256
frame #26: 0x00000001001fad3c Emacs`mac_autorelease_loop + 48
frame #27: 0x000000010014ae54 Emacs`funcall_subr + 96
frame #28: 0x0000000100147b84 Emacs`Ffuncall + 316
frame #29: 0x000000010014b47c Emacs`__funcall_subr_block_invoke + 104
frame #30: 0x00000001001fad3c Emacs`mac_autorelease_loop + 48
frame #31: 0x000000010014ae54 Emacs`funcall_subr + 96
frame #32: 0x0000000100147b84 Emacs`Ffuncall + 316
frame #33: 0x0000000104430e44 timer-3ee7cfd9-226b3dc9.eln`F74696d65722d6576656e742d68616e646c6572_timer_event_handler_0 + 832
frame #34: 0x000000010014b524 Emacs`__funcall_subr_block_invoke + 272
frame #35: 0x00000001001fad3c Emacs`mac_autorelease_loop + 48
frame #36: 0x000000010014ae54 Emacs`funcall_subr + 96
frame #37: 0x0000000100147b84 Emacs`Ffuncall + 316
frame #38: 0x00000001000d54fc Emacs`timer_check + 904
frame #39: 0x00000001000d3c28 Emacs`readable_events + 36
frame #40: 0x00000001000d511c Emacs`get_input_pending + 56
frame #41: 0x00000001000d300c Emacs`detect_input_pending_run_timers + 48
frame #42: 0x000000010019c498 Emacs`wait_reading_process_output + 3760
frame #43: 0x0000000100013228 Emacs`sit_for + 380
frame #44: 0x00000001000d0ae8 Emacs`read_char + 4796
frame #45: 0x00000001000cdda4 Emacs`read_key_sequence + 1032
frame #46: 0x00000001000dd538 Emacs`__command_loop_1_block_invoke + 492
frame #47: 0x00000001001fad3c Emacs`mac_autorelease_loop + 48
frame #48: 0x00000001000cd5f8 Emacs`command_loop_1 + 336
frame #49: 0x00000001001487d4 Emacs`internal_condition_case + 96
frame #50: 0x00000001000cd494 Emacs`command_loop_2 + 52
frame #51: 0x00000001001481ec Emacs`internal_catch + 88
frame #52: 0x0000000100232cc4 Emacs`command_loop.cold.1 + 88
frame #53: 0x00000001000ccd58 Emacs`command_loop + 152
frame #54: 0x00000001000ccc10 Emacs`recursive_edit_1 + 152
frame #55: 0x00000001000ccf54 Emacs`Frecursive_edit + 264
frame #56: 0x00000001000cbebc Emacs`emacs_main + 6792
frame #57: 0x000000010021c39c Emacs`mac_start_lisp_main + 56
frame #58: 0x0000000193bc2f94 libsystem_pthread.dylib`_pthread_start + 136
(lldb) f 0
frame #0: 0x0000000193e0d410 CoreFoundation`__CFStringCreateImmutableFunnel3.cold.1 + 16
CoreFoundation`__CFStringCreateImmutableFunnel3.cold.1:
-> 0x193e0d410 <+16>: brk #0x1
CoreFoundation`__CFStringMakeConstantString.cold.1:
0x193e0d414 <+0>: pacibsp
0x193e0d418 <+4>: stp x29, x30, [sp, #-0x10]!
0x193e0d41c <+8>: mov x29, sp
(lldb) image lookup -va $pc
Address: CoreFoundation[0x0000000180691410] (CoreFoundation.__TEXT.__text + 1995616)
Summary: CoreFoundation`__CFStringCreateImmutableFunnel3.cold.1 + 16
Module: file = "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation", arch = "arm64e"
Symbol: id = {0x00001758}, range = [0x0000000193e0d400-0x0000000193e0d414), name="__CFStringCreateImmutableFunnel3.cold.1"
(lldb) frame variable
(lldb) f 1
frame #1: 0x0000000193c26fcc CoreFoundation`__CFStringCreateImmutableFunnel3 + 96
CoreFoundation`__CFStringCreateImmutableFunnel3:
-> 0x193c26fcc <+96>: mov x25, x6
0x193c26fd0 <+100>: mov x26, x5
0x193c26fd4 <+104>: mov x24, x4
0x193c26fd8 <+108>: mov x22, x3
(lldb) image lookup -va $pc
Address: CoreFoundation[0x00000001804aafcc] (CoreFoundation.__TEXT.__text + 3868)
Summary: CoreFoundation`__CFStringCreateImmutableFunnel3 + 96
Module: file = "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation", arch = "arm64e"
Symbol: id = {0x0000000a}, range = [0x0000000193c26f6c-0x0000000193c27aac), name="__CFStringCreateImmutableFunnel3"
(lldb) f 3
warning: enchant_applespell.so was compiled with optimization - stepping may behave oddly; variables may not be available.
frame #3: 0x000000012e94f820 enchant_applespell.so`appleSpell_dict_check(me=<unavailable>, word="Automagically", len=18446744073709551615) at applespell_checker.mm:293:31 [opt]
290
291 if (AppleSpellDictionary * ASD = static_cast<AppleSpellDictionary *>(me->user_data))
292 {
-> 293 result = ASD->AppleSpell->checkWord (word, len, ASD->DictionaryName);
294 }
295 return result;
296 }
(lldb) frame variable
(EnchantDict *) me = <Could not evaluate DW_OP_entry_value.>
(const char *const) word = 0x00006000038c4070 "Automagically"
(size_t) len = 18446744073709551615
(int) result = 0
(AppleSpellDictionary *) ASD = <variable not available>
(lldb) image lookup -va $pc
Address: enchant_applespell.so[0x0000000000003860] (enchant_applespell.so.__TEXT.__text + 3816)
Summary: enchant_applespell.so`appleSpell_dict_check(_EnchantDict*, char const*, unsigned long) + 128 [inlined] AppleSpellChecker::checkWord(char const*, unsigned long, NSString*) + 64 at applespell_checker.mm:172:6
enchant_applespell.so`appleSpell_dict_check(_EnchantDict*, char const*, unsigned long) + 64 at applespell_checker.mm:293:31
Module: file = "/opt/homebrew/Cellar/enchant/2.7.1/lib/enchant-2/enchant_applespell.so", arch = "arm64"
CompileUnit: id = {0x00000000}, file = "/Users/jeffrey/Library/Caches/Homebrew/Sources/enchant/enchant-2.7.1/providers/applespell_checker.mm", language = "objective-c++"
Function: id = {0x4000000000005089}, name = "appleSpell_dict_check(_EnchantDict*, char const*, unsigned long)", mangled = "_ZL21appleSpell_dict_checkP12_EnchantDictPKcm", range = [0x000000012e94f7e0-0x000000012e94f8d0)
FuncType: id = {0x4000000000005089}, byte-size = 0, decl = applespell_checker.mm:279, compiler_type = "int (EnchantDict *, const char *const, size_t)"
Blocks: id = {0x4000000000005089}, range = [0x12e94f7e0-0x12e94f8d0)
id = {0x40000000000050d7}, range = [0x12e94f808-0x12e94f8b8)
id = {0x40000000000050f4}, ranges = [0x12e94f814-0x12e94f818)[0x12e94f81c-0x12e94f8ac)
id = {0x4000000000005109}, range = [0x12e94f820-0x12e94f8ac), name = "checkWord", decl = applespell_checker.mm:164, mangled = _ZN17AppleSpellChecker9checkWordEPKcmP8NSString, demangled = AppleSpellChecker::checkWord(char const*, unsigned long, NSString*)
LineEntry: [0x000000012e94f860-0x000000012e94f864): /Users/jeffrey/Library/Caches/Homebrew/Sources/enchant/enchant-2.7.1/providers/applespell_checker.mm:172:6
Symbol: id = {0x00000071}, range = [0x000000012e94f7e0-0x000000012e94f8d0), name="appleSpell_dict_check(_EnchantDict*, char const*, unsigned long)", mangled="_ZL21appleSpell_dict_checkP12_EnchantDictPKcm"
Variable: id = {0x400000000000511e}, name = "this", type = "AppleSpellChecker *", valid ranges = <block>, location = [0x0000000000003838, 0x00000000000038ac) -> DW_OP_reg23 W23, decl =
Variable: id = {0x4000000000005127}, name = "word", type = "const char *", valid ranges = <block>, location = [0x0000000000003838, 0x0000000000003898) -> DW_OP_reg20 W20, decl = applespell_checker.mm:164
Variable: id = {0x4000000000005130}, name = "len", type = "size_t", valid ranges = <block>, location = [0x0000000000003838, 0x0000000000003868) -> DW_OP_reg19 W19, decl = applespell_checker.mm:164
Variable: id = {0x4000000000005139}, name = "lang", type = "NSString *", valid ranges = <block>, location = [0x0000000000003838, 0x00000000000038a8) -> DW_OP_reg21 W21, decl = applespell_checker.mm:164
Variable: id = {0x4000000000005142}, name = "str", type = "NSString *", valid ranges = <block>, location = [0x0000000000003860, 0x0000000000003868) -> DW_OP_reg0 W0, decl = applespell_checker.mm:171
Variable: id = {0x40000000000050e4}, name = "result", type = "int", valid ranges = <block>, location = [0x0000000000003814, 0x00000000000038b4) -> DW_OP_consts +0, DW_OP_stack_value, decl = applespell_checker.mm:289
Variable: id = {0x40000000000050a7}, name = "me", type = "EnchantDict *", valid ranges = <block>, location = [0x000000000000383c, 0x00000000000038b4) -> DW_OP_entry_value(DW_OP_reg0 W0), DW_OP_stack_value, decl = applespell_checker.mm:279
Variable: id = {0x40000000000050b7}, name = "word", type = "const char *const", valid ranges = <block>, location = [0x00000000000037fc, 0x0000000000003898) -> DW_OP_reg20 W20, decl = applespell_checker.mm:279
Variable: id = {0x40000000000050c7}, name = "len", type = "size_t", valid ranges = <block>, location = [0x00000000000037f8, 0x0000000000003868) -> DW_OP_reg19 W19, decl = applespell_checker.mm:279
(lldb) f 4
warning: libenchant-2.2.dylib was compiled with optimization - stepping may behave oddly; variables may not be available.
frame #4: 0x000000012e93589c libenchant-2.2.dylib`enchant_dict_check(_self_=0x0000600001fa5b00, word_buf=<unavailable>, len=<unavailable>) at dict.vala:154:12 [opt]
151 return 0;
152
153 if (self.check_method != null)
-> 154 return self.check_method(self, word, len);
155 else if (self.session.is_pwl)
156 return 1;
157
(lldb) frame variable
(EnchantDict *) _self_ = 0x0000600001fa5b00
(const gchar *) word_buf = <Could not evaluate DW_OP_entry_value.>
(ssize_t) len = <Could not evaluate DW_OP_entry_value.>
(gchar *) word = 0x00006000038c4070 "Automagically"
(gboolean) _tmp0_ = <variable not available>
(const gchar *) _tmp2_ = 0x00006000038c4070 "Automagically"
(gchar *) _tmp1_ = 0x00006000038c4070 "Automagically"
(EnchantSession *) _tmp3_ = <variable not available>
(const gchar *) _tmp5_ = 0x00006000038c4070 "Automagically"
(EnchantSession *) _tmp4_ = <variable not available>
(gint) result = <variable not available>
(const gchar *) _tmp7_ = 0x00006000038c4070 "Automagically"
(EnchantSession *) _tmp6_ = <variable not available>
(DictCheck) _tmp8_ = <register x8 is not available>
(DictCheck) _tmp9_ = <no location, value may have been optimized out>
(const gchar *) _tmp10_ = <no location, value may have been optimized out>
(lldb) image lookup -va $pc
Address: libenchant-2.2.dylib[0x000000000000589c] (libenchant-2.2.dylib.__TEXT.__text + 8696)
Summary: libenchant-2.2.dylib`enchant_dict_check + 164 at dict.vala:154:12
Module: file = "/opt/homebrew/Cellar/enchant/2.7.1/lib/libenchant-2.2.dylib", arch = "arm64"
CompileUnit: id = {0x00000000}, file = "/Users/jeffrey/Library/Caches/Homebrew/Sources/enchant/enchant-2.7.1/lib/dict.c", language = "c11"
Function: id = {0x40000200000015a3}, name = "enchant_dict_check", range = [0x000000012e9357f8-0x000000012e9358dc)
FuncType: id = {0x40000200000015a3}, byte-size = 0, decl = dict.c:594, compiler_type = "int (EnchantDict *, const gchar *, ssize_t)"
Blocks: id = {0x40000200000015a3}, range = [0x12e9357f8-0x12e9358dc)
id = {0x400002000000169d}, range = [0x12e93588c-0x12e9358a8)
LineEntry: [0x000000012e93588c-0x000000012e9358a0): /Users/jeffrey/Library/Caches/Homebrew/Sources/enchant/enchant-2.7.1/lib/dict.vala:154:12
Symbol: id = {0x000000ee}, range = [0x000000012e9357f8-0x000000012e9358dc), name="enchant_dict_check"
Variable: id = {0x40000200000016aa}, name = "_tmp9_", type = "DictCheck", valid ranges = <block>, location = <empty>, decl = dict.c:680
Variable: id = {0x40000200000016b6}, name = "_tmp10_", type = "const gchar *", valid ranges = <block>, location = <empty>, decl = dict.c:681
Variable: id = {0x40000200000015bd}, name = "_self_", type = "EnchantDict *", valid ranges = <block>, location = [0x000000000000580c, 0x00000000000058a0) -> DW_OP_reg20 W20, decl = dict.c:594
Variable: id = {0x40000200000015cd}, name = "word_buf", type = "const gchar *", valid ranges = <block>, location = [0x0000000000005824, 0x00000000000058cc) -> DW_OP_entry_value(DW_OP_reg1 W1), DW_OP_stack_value, decl = dict.c:595
Variable: id = {0x40000200000015dd}, name = "len", type = "ssize_t", valid ranges = <block>, location = [0x0000000000005828, 0x00000000000058cc) -> DW_OP_entry_value(DW_OP_reg2 W2), DW_OP_stack_value, decl = dict.c:596
Variable: id = {0x40000200000015ed}, name = "word", type = "gchar *", valid ranges = <block>, location = [0x0000000000005884, 0x00000000000058a8) -> DW_OP_reg19 W19, decl = dict.c:599
Variable: id = {0x400002000000160d}, name = "_tmp2_", type = "const gchar *", valid ranges = <block>, location = [0x0000000000005864, 0x00000000000058cc) -> DW_OP_reg19 W19, decl = dict.c:601
Variable: id = {0x400002000000161d}, name = "_tmp1_", type = "gchar *", valid ranges = <block>, location = [0x0000000000005864, 0x00000000000058cc) -> DW_OP_reg19 W19, decl = dict.c:600
Variable: id = {0x400002000000163d}, name = "_tmp5_", type = "const gchar *", valid ranges = <block>, location = [0x0000000000005864, 0x00000000000058cc) -> DW_OP_reg19 W19, decl = dict.c:604
Variable: id = {0x400002000000166d}, name = "_tmp7_", type = "const gchar *", valid ranges = <block>, location = [0x0000000000005868, 0x00000000000058cc) -> DW_OP_reg19 W19, decl = dict.c:606
(lldb) f 5
frame #5: 0x000000012e90b3f4 jinx-mod.dylib`jinx_check + 132
jinx-mod.dylib`jinx_check:
-> 0x12e90b3f4 <+132>: cbnz w0, 0x12e90b3c0 ; <+80>
0x12e90b3f8 <+136>: adrp x0, 5
0x12e90b3fc <+140>: ldr x19, [x0, #0x10]
0x12e90b400 <+144>: mov x0, x20
(lldb)
Thanks for this! This looks like a straightforward bug, I shall try to have a fix out soon.
Out of interest, how were you spell-checking in Emacs? I cannot see how this bug could have been triggered by Emacs's ispell
command, or similar, using the Enchant command-line interface. (The crash was caused by passing a negative length to the provider's check
method, which the command-line enchant
program never does.)
Out of interest, how were you spell-checking in Emacs?
It's the Jinx package for Emacs.
The crash was caused by passing a negative length to the provider's check method...
Oops, yes I see it. And a few other -1 calls for add and suggest:
https://github.com/minad/jinx/blob/77cac7f240f45d6c4836e844bd68151c7f863298/jinx-mod.c#L135
I'll let the maintainer know.
Thanks for such a quick turn-around fix!
@jeff-phil The jinx code is (most likely, I haven't checked) correct: Enchant's external APIs do accept -1 as a length. The bug in Enchant was that I had incorrectly made an internal call to an API that was expecting an unsigned length. Makes sense that this problem was showing up with jinx; I did wonder!