2016-09-28 91 views
2

我注意到XCode 8中AddressSanitizer有趣的行为。在一种情况下,它导致捕获断点:AddressSanitizer:地址上的堆缓冲区溢出,但我真的不明白为什么:NSData转换堆缓冲区溢出

char * buffer = malloc(length); 
    memset(buffer, 0, length); 
    [output getBytes:buffer 
       length:length]; 
    stringOutput = [NSString stringWithUTF8String:buffer]; // here is crash 

相同于:

stringOutput = [NSString stringWithUTF8String:output.bytes]; 

但一切罚款情况:

stringOutput = [[NSString alloc] initWithData:output 
             encoding:NSUTF8StringEncoding]; 

而且经过一些实验,我已经看到了,如果我们加“0”到缓冲区一切都会精细的结尾:

char * buffer = malloc(length + 1); 
memset(buffer, 0, length + 1); 
[output getBytes:buffer 
      length:length]; 
stringOutput = [NSString stringWithUTF8String:buffer]; 

这种行为不可预料的我,因为我使用stringWithUTF8String:output.bytes现场代码十几次没有任何问题...所以我错了?

+1

'[NSString stringWithUTF8String:buffer]'读取字节,直到找到NUL终结符。如果分配和填充的内存中没有零字节,则将读取未定义的内存。 –

+0

但为什么stringOutput = [NSString stringWithUTF8String:output.bytes];导致崩溃?我认为可可巧妙地解决了这种问题? – toohtik

+0

因为该方法*无法知道*现在许多字节被定义或有效。 –

回答

2

[NSString stringWithUTF8String:]需要const char *作为参数, 和读取字节,在启动给定的存储器位置,直到终止0字节 被发现。 如果在已分配和写入的 内存中没有0字节,它将继续读取未定义的内存,或甚至从 无效的内存位置。该方法具有无信息约 定义了从给定指针开始的多少个字节。

在另一方面[[NSString alloc] initWithData: encoding:] 需要NSData参数(其包括两个的指针数据的长度),并从该对象通过 定义的字节完全读取。

+0

很酷,谢谢Martin。只是从来没有想过,这可能是在那个地方的问题... – toohtik