Objective C stringWithCString“方法缓存已损坏”

时间:2014-09-28 12:32:27

标签: objective-c c xcode macos nsstring

我正在创建一个执行shell命令的方法。它看起来像这样:

NSString *cShellStr(NSString *command, int maxBufferSize) {
    if (maxBufferSize<1) {
        maxBufferSize = INT_MAX;
    }
    NSString *newCommand = [NSString stringWithFormat:@"%@ 2>&1", command];
    const char *cStrCommand = [newCommand cStringUsingEncoding:NSUTF8StringEncoding];
    FILE *fp;
    fp = popen(cStrCommand, "r");
    if (fp == NULL) {
        NSLog(@"Failed to open process");
        return nil;
    }
    char *buffer = NULL;
    buffer = (char*)malloc(4);
    if (buffer == NULL) {
        NSLog(@"Failed to allocate memory");
        return nil;
    }
    while (!feof(fp)) {
        buffer = realloc(buffer, sizeof(buffer)+1);
        sprintf(buffer, "%s%c", buffer, fgetc(fp));
    }
    NSString *ret = [NSString stringWithCString:buffer encoding:NSASCIIStringEncoding];
    fclose(fp);
    free(buffer);
    return ret;
}

然而,通常(奇怪的是并非总是)在[NSString stringWithCString:buffer encoding:NSASCIIStringEncoding]处收到此错误:

objc[33674]: Method cache corrupted. This may be a message to an invalid object, or a memory error somewhere else.
objc[33674]: receiver 0x7fff7d62aec0, SEL 0x7fff99ac69f5, isa 0x7fff7d62aee8, cache 0x7fff7d62aef8, buckets 0x100200780, mask 0x3, occupied 0x2, wrap bucket 0x100200780
objc[33674]: receiver 0 bytes, buckets 64 bytes
objc[33674]: selector 'class'
objc[33674]: isa 'NSString'
objc[33674]: Method cache corrupted.
objc[33674]: Method cache corrupted. This may be a message to an invalid object, or a memory error somewhere else.
objc[33674]: receiver 0x7fff7d62aec0, SEL 0x7fff99aea2d4, isa 0x7fff7d62aee8, cache 0x7fff7d62aef8, buckets 0x100200780, mask 0x3, occupied 0x2, wrap bucket 0x100200780
objc[33674]: receiver 0 bytes, buckets 64 bytes
objc[33674]: selector 'stringWithCString:encoding:'
objc[33674]: isa 'NSString'
objc[33674]: Method cache corrupted.

我已经使用lldb逐步完成了它,并确认没有其他错误,并且buffer包含我期望的文本。我错误地使用了stringWithCString

额外信息: Xcode版本: xcode info

笔记本电脑信息: laptop info

Clang版本:

Apple LLVM version 
6.0 (clang-600.0.51) (based on LLVM 3.5svn)
Target: x86_64-apple-darwin13.3.0
Thread model: posix

2 个答案:

答案 0 :(得分:1)

        sprintf(buffer, "%s%c", buffer, fgetc(fp));

这是未定义的行为,因为您正在使用缓冲区两次。任何事都可能出错,幸运的是,确实如此。我说“幸运的你”,因为运气不好,只会在客户手中出错。

我没有注意; user3125367发现的问题差十倍。

答案 1 :(得分:1)

while (!feof(fp)) {
    buffer = realloc(buffer, sizeof(buffer)+1);
    sprintf(buffer, "%s%c", buffer, fgetc(fp));
}

此循环应重写为:

size_t len = 0, cap = 4;
buffer = malloc(cap); // TODO check NULL
int c;
while (EOF != (c = fgetc(fp))) {
    if (len >= cap) {
        cap += cap;
        buffer = realloc(buffer, cap); // TODO check NULL
    }
    buffer[len++] = c;
}
// check feof/ferror