在NSTextStorage中混淆编码异常

Abh*_*ert 20 macos cocoa objective-c nstextstorage

我有一个简单的文本编辑器的NSDocument子类(使用Lion的基于新文档的应用程序模板,几乎没有自定义),我遇到了一个奇怪的错误,将文件内容加载到文本存储中.

这是我的代码:

- (void)loadTextContentIntoStorage
{
  if (!self.textStorage || !textContentToLoad)
    return;

  ...

  [self.textStorage beginEditing];

//  NSLog(@"storage: %@ length: %lu textContent: %@", self.textStorage, (unsigned long)self.textStorage.length, textContentToLoad);
//  [self.textStorage replaceCharactersInRange:NSMakeRange(0, self.textStorage.length) withString:textContentToLoad];
  [self.textStorage replaceCharactersInRange:NSMakeRange(0, 0) withString:@"hello world"];

  ..

  [self.textStorage endEditing];
}
Run Code Online (Sandbox Code Playgroud)

当我发生错误时:

  • 在Xcode中运行应用程序(作为调试版本)
  • 打开任何文件
  • 退出应用程序(不关闭文档)
  • 再次从Xcode运行应用程序

它崩溃-replaceCharactersInRange:withString:了"无法将字符串0x10004d430中的字节转换为_NSCStringEncoding".

但它只是发生在每一推出的应用程序(第三发射不会崩溃,它自动重新打开它坠毁试图打开上次的文件).它也只发生在我从Xcode运行应用程序时.发布版本从未在发布时崩溃.

我认为这可能是自动保存系统的编码问题,但是当我注释掉该代码并将@"hello world"字符串加载到文本视图中时它甚至会崩溃(如上面的代码所示).同样,注释掉NSLog()并没有显示任何奇怪的东西.文本存储有效(从xib文件加载),文本存储长度为0,textContent是要打开的文件的内容.

---编辑---

我已经知道这个问题在某种程度上与com.apple.security.app-sandbox权利有关.如果启用了权利/沙箱,那么我的应用程序不会崩溃.如果禁用了权利或app-sandbox功能,那么我的应用程序会在尝试恢复以前打开的文档的每次启动时崩溃.

我只注意到在xcode内部进行构建/运行时崩溃,因为这是我唯一一个禁用沙箱的构建配置.

--- /编辑---

有没有人有任何想法?完整的例外如下,完整的源代码在github上:https://github.com/abhibeckert/Dux/blob/master/Dux/DuxTextView.m

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Unable to convert bytes in string 0x10004d430 to _NSCStringEncoding'
*** First throw call stack:
(
    0   CoreFoundation                      0x00007fff84afb286 __exceptionPreprocess + 198
    1   libobjc.A.dylib                     0x00007fff88991d5e objc_exception_throw + 43
    2   CoreFoundation                      0x00007fff84afb0ba +[NSException raise:format:arguments:] + 106
    3   CoreFoundation                      0x00007fff84afb044 +[NSException raise:format:] + 116
    4   Foundation                          0x00007fff835bfae4 copyFromStringToStorage + 262
    5   Foundation                          0x00007fff835bf979 -[NSBigMutableString replaceCharactersInRange:withString:] + 1000
    6   Foundation                          0x00007fff835bc3f7 -[NSConcreteMutableAttributedString replaceCharactersInRange:withString:] + 375
    7   AppKit                              0x00007fff86149e14 -[NSConcreteTextStorage replaceCharactersInRange:withString:] + 81
    8   Dux                                 0x0000000100002f9a -[MyTextDocument loadTextContentIntoStorage] + 1338
    9   Dux                                 0x00000001000022a0 -[MyTextDocument windowControllerDidLoadNib:] + 640
    10  AppKit                              0x00007fff860f1328 -[NSWindowController _windowDidLoad] + 667
    11  AppKit                              0x00007fff860e89a3 -[NSWindowController window] + 109
    12  AppKit                              0x00007fff8615d761 -[NSDocument windowForSheet] + 86
    13  AppKit                              0x00007fff860e82c4 -[NSDocument _shouldShowAutosaveButtonForWindow:] + 50
    14  AppKit                              0x00007fff860e7fbb -[NSWindowController setDocument:] + 237
    15  AppKit                              0x00007fff8629c9b6 -[NSDocument makeWindowControllers] + 139
    16  AppKit                              0x00007fff8615d555 -[NSDocument(NSPersistentUISupport) restoreDocumentWindowWithIdentifier:state:completionHandler:] + 90
    17  AppKit                              0x00007fff8615d4aa -[NSDocumentControllerPersistentRestoration loadedDocument:forAutoID:] + 179
    18  AppKit                              0x00007fff8615cfbe __-[NSDocumentController reopenDocumentForURL:withContentsOfURL:display:completionHandler:]_block_invoke_8 + 187
    19  AppKit                              0x00007fff86148e14 __-[NSDocumentController reopenDocumentForURL:withContentsOfURL:display:completionHandler:]_block_invoke_5 + 163
    20  AppKit                              0x00007fff86148d5f __-[NSDocumentController reopenDocumentForURL:withContentsOfURL:display:completionHandler:]_block_invoke_4 + 697
    21  AppKit                              0x00007fff86148aa1 -[NSDocumentController _openDocumentWithContentsOfURL:usingProcedure:] + 530
    22  AppKit                              0x00007fff8614868d __-[NSDocumentController reopenDocumentForURL:withContentsOfURL:display:completionHandler:]_block_invoke_3 + 242
    23  libdispatch.dylib                   0x00007fff8bbbe8ba _dispatch_call_block_and_release + 18
    24  libdispatch.dylib                   0x00007fff8bbc072a _dispatch_main_queue_callback_4CF + 308
    25  CoreFoundation                      0x00007fff84a904dc __CFRunLoopRun + 1724
    26  CoreFoundation                      0x00007fff84a8fae6 CFRunLoopRunSpecific + 230
    27  HIToolbox                           0x00007fff8852f3d3 RunCurrentEventLoopInMode + 277
    28  HIToolbox                           0x00007fff8853663d ReceiveNextEventCommon + 355
    29  HIToolbox                           0x00007fff885364ca BlockUntilNextEventMatchingListInMode + 62
    30  AppKit                              0x00007fff85ef23f1 _DPSNextEvent + 659
    31  AppKit                              0x00007fff85ef1cf5 -[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:] + 135
    32  AppKit                              0x00007fff85eee62d -[NSApplication run] + 470
    33  AppKit                              0x00007fff8616d80c NSApplicationMain + 867
    34  Dux                                 0x0000000100001e32 main + 34
    35  Dux                                 0x0000000100001e04 start + 52
    36  ???                                 0x0000000000000003 0x0 + 3
)
Run Code Online (Sandbox Code Playgroud)

MrG*_*mez 5

我承认,这个问题困扰了我很长一段时间.不过,我想我终于找到了一个复制品.

查看模拟此行为GNUstep 代码,我找到了以下源代码:

if (enc == NSASCIIStringEncoding
    && isByteEncoding(internalEncoding))
    {
      unsigned  i;

      if (bytes > self->_count)
    {
      bytes = self->_count;
    }
      for (i = 0; i < bytes; i++)
    {
      unsigned char c = self->_contents.c[i];

      if (c > 127)
        {
          [NSException raise: NSCharacterConversionException
              format: @"unable to convert to encoding"];
        }
      buffer[i] = c;
    }
      buffer[bytes] = '\0';
      if (bytes < self->_count)
    {
      return NO;
    }
      return YES;
    }
...
Run Code Online (Sandbox Code Playgroud)

显然,此代码与您的错误消息不是一对一的.但是,我从你的错误repro中注意到这一点:

reason: 'Unable to convert bytes in string 0x10004d430 to_NSCStringEncoding'

好吧,我们都知道C字符串是什么,如果你使用了错误的编码方法(例如,Wide预期ASCII,反之亦然),你最终会遇到这个问题.因此:您是否尝试在应用程序中使用不同的ASCII和Wide数据类型来解决此问题?

由于这种行为的常见程度,它很可能表明它是应用程序沙箱的处理案例.但是,我还没有找到这种效果的文档.sandboxd正如我在问题勘误表中提出的那样,这应该是明确指出的.


Abh*_*ert 0

这似乎是 OS X 10.7 (Lion) 中的一个错误。通过对代码进行零更改,在符合 Xcode 4.4.1 的 OS X 10.8 (Mountain Lion) 上不再发生崩溃。