【问题标题】:Builtin MemCpy Chk will always overflow destination buffer内置 MemCpy Chk 将始终溢出目标缓冲区
【发布时间】:2017-11-11 12:08:20
【问题描述】:

将我的应用从 32 位更新到 64 位。

根据 Apple 文档,浮点数只有 4 个字节,我需要使用 CGFloat(8 个字节)

我正在使用memcpy 读取字节。我已将我所有的 sizeof(float)s 更新为 sizeof(CGFloat)

但是当我这样做时,我会遇到语义问题

__builtin___memcpy_chk 总是会溢出目标缓冲区。扩展自宏memcpy

我将NSData readDataOfLenght 更新为sizeof(CGFloat),它似乎工作正常。有时并非所有读入的数据都是正确的。

恐怕我在这方面有点不知所措,需要一些帮助。

-(void) readByteData:(NSFileHandle *)fHandle Size:(NSInteger)byteSize
{
    [super readByteData:fHandle Size:byteSize];

    NSData *data = [fHandle readDataOfLength:sizeof(CGFloat)];
    float r;
    memcpy(&r, [data bytes], sizeof(CGFloat));
    self.radius = r;

    int nCGPointSize = sizeof(CGFloat) * 2;
    data = [fHandle readDataOfLength:nCGPointSize];
    float xy[2];
    memcpy(xy, [data bytes], nCGPointSize);
    self.centerPos = ccp(xy[0], xy[1]);

    data = [fHandle readDataOfLength:sizeof(CGFloat)];
    float start_angle;
    memcpy(&start_angle, [data bytes], sizeof(CGFloat));
    self.startAngle = start_angle;

    data = [fHandle readDataOfLength:sizeof(CGFloat)];
    float end_angle;
    memcpy(&end_angle, [data bytes], sizeof(CGFloat));
    self.endAngle = end_angle;

    data = [fHandle readDataOfLength:sizeof(int)];
    int d;
    memcpy(&d, [data bytes], sizeof(int));
    self.dir = d;

    flagClosed = YES;
}

【问题讨论】:

    标签: ios objective-c 64-bit nsdata memcpy


    【解决方案1】:

    这条指令:

    float r;
    memcpy(&r, [data bytes], sizeof(CGFloat));
    

    告诉你的编译器:

    [data bytes] 位置读取sizeof(CGFloat)(== 8 个字节!) 并写信给r

    但是r 的大小只有 4 个字节! 所以前 4 个字节被写入内存中的r,接下来的 4 个字节被写入内存中r 之后的任何内容,这是不允许。 memcpy 是一个简单的字节复制指令,它将任意数量的字节从内存位置 A 移动到内存位置 B,它无法为您转换数据类型。如果您需要将CGFloat 值转换为float 值,那么您实际上需要自己进行转换。

    CGFloat bigR;
    memcpy(&bigR, [data bytes], sizeof(bigR));
    self.radius = (float)bigR;
    

    读取多个值时相同:

    CGFloat bigXY[2];
    data = [fHandle readDataOfLength:sizeof(bigXY)];
    memcpy(bigXY, [data bytes], sizeof(bigXY));
    self.centerPos = ccp((float)bigXY[0], (float)bixXY[1]);
    

    强制转换只是为了更清楚地说明转换发生的位置,大多数编译器也会在没有所有 (float) 强制转换且不抱怨的情况下编译代码。

    作为一般规则:

    memcpy(dst, src, size)
    

    size 绝不能大于src指向的内存或dst指向的内存。在您的情况下,size 总是大于 dst 指向的内存。

    到目前为止,您的代码不起作用的解释。但是,您实际上根本不需要使用memcpy,就好像您有一个已知数据类型的多个值中的内存块一样,当然您可以直接访问该内存而无需将其复制到任何地方:

    NSData * data = [fHandle readDataOfLength:sizeof(CGFloat)];
    if (!data) {
        // ... handle errorr ...
    }
    const CGFloat * cgfloatsInData = (const CGFloat *)[data bytes];
    self.radius = (float)cgfloatsInData[0];
    
    data = [fHandle readDataOfLength:sizeof(CGFloat) * 2];
    if (!data) {
        // ... handle errorr ...
    }
    const CGFloat * cgfloatsInData = (const CGFloat *)[data bytes];
    self.centerPos = ccp((float)cgfloatsInData[0], (float)cgfloatsInData[1]);
    

    等等。但这是非常低效的,因为您似乎总是期望一些没有可选值的固定大小的结构,那么为什么不将它作为一个结构来阅读呢?这样一来,您只需要一次 I/O 访问即可读取所有内容,并且系统只需创建一个 NSData 对象。

    const struct {
        CGFloat radius;
        CGFloat xCoord;
        CGFloat yCoord;
        CGFloat startAngle;
        CGFloat endAngle;
        int dir;
    } __attribute__((packed)) * entry;
    // `const` as the memory `entry` will point to will be read-only.
    // `* entry` means entry is a pointer to memory of a struct
    // that looks as described above. __attribute__((packed)) means
    // the memory must be laid out exactly as shown above and have no
    // padding for better alignment of fields.
    
    NSData * data = [fHandle readDataOfLength:sizeof(*entry)];
    // `sizeof(*entry)` means the size of the memory entry points to,
    // contrary to `sizeof(entry)` which would be the size of entry itself
    // and that would simply be the size of a pointer on your system, 8 bytes,
    // whereas `sizeof(*entry)` will be 44 bytes.
    
    entry = (const void *)dataBytes;
    // Any pointer type can be cased to `void *` and assigning
    // a `void *` pointer so some pointer is always allowed by the compiler.
    
    self.radius = (float)entry->radius;
    self.centerPos = ccp((float)entry->xCoord, (float)entry->yCoord);
    self.startAngle = (float)entry->startAngle;
    self.endAngle = (float)entry->endAngle;
    self.dir = entry->dir;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-06-13
      • 2015-12-16
      • 1970-01-01
      • 2010-11-11
      • 1970-01-01
      • 2013-11-06
      • 2011-06-28
      相关资源
      最近更新 更多