Встроенный MemCpy Chk всегда будет переполнять целевой буфер

Обновление моего приложения с 32-разрядного до 64-разрядного.

Согласно документации Apple, значения с плавающей запятой имеют размер всего 4 байта, и мне нужно использовать CGFloat (8 байт).

Я использую memcpy читать в байтах. Я обновил все мои sizeof(float) с 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;
}

1 ответ

Эта инструкция:

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

Сообщает вашему компилятору:

Читать sizeof(CGFloat) (== 8 байт!) С места [data bytes] и напишите их 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]);

И так далее. Но это крайне неэффективно, так как вы, похоже, всегда ожидаете какую-то структуру фиксированного размера без дополнительных значений, так почему бы не прочитать ее как структуру? Таким образом, вам нужен только один доступ ввода / вывода, чтобы прочитать все это и только один 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;
Другие вопросы по тегам