LLVM GCC 4.2 EXC_BAD_ACCESS

#objective-c #ios #compiler-construction #exc-bad-access #llvm-gcc

#objective-c #iOS #компилятор-конструирование #исключение-bad-access #llvm-gcc

Вопрос:

Приведенный ниже код отлично работает на GCC 4.2, но завершается ошибкой с EXC_BAD_ACCESS в LLVM GCC 4.2

 - (double_t)readDouble  {
    double_t *dt = (double_t *)(buffer offset);
    double_t ret = *dt; // Program received signal: EXC_BAD_ACCESS
    offset  = 8;
    return ret;
}
  

Вот как я распределяю

 int dataLength = [data length];
buffer = malloc(dataLength   1);
buffer[dataLength] = 0; // null terminate to log
[data getBytes:(void *)buffer length:[data length]];
//NSLog(@"%s", buffer);
  

Смещение и буфер похожи

 @interface PRDataSet : NSObject {

    NSMutableArray *tables;
    NSMutableDictionary *tablesByName;
    NSMutableDictionary *tablesById;

@private
    NSURLConnection *conn;
    int offset;
    char *buffer;

}
  

Да, смещение находится в пределах диапазона.
Я не освобождаю буфер перед его использованием.

Есть идеи?

Ответ №1:

Это может быть проблемой с настройкой. Процессоры ARM (и многие другие процессоры) имеют ограничения в отношении выравнивания данных, например, они могут считывать и записывать числа с плавающей запятой только с адресов, кратных 4 или 8.

Судя по тому, как буфер выделен в вашем коде, он может быть выделен неправильно, или ваши double_t элементы данных не выровнены внутри буфера.

Чтобы избежать проблемы, вы должны попытаться сначала скопировать данные в выровненный буфер и прочитать их оттуда.

Комментарии:

1. Вы правы. Речь идет о выравнивании с плавающей запятой. Мой буфер настроен из разных типов данных, поэтому я не смог выровнять буфер. Решение заключается в чтении как целого числа, а затем приведении к числам с плавающей запятой. Я думаю, что это то, что сделал GCC. LLVM не выполняет это исправление, но я думаю, что это должно произойти в будущем. Разработчикам не обязательно знать ограничения процессора. Для этого и существуют компиляторы.

Ответ №2:

LLVM просто не считывает float напрямую.

Вот решение:

 - (uint32_t)readUInt32  {
    uint32_t ret = *(uint32_t *)(buffer offset);
    offset  = 4;
    return ret;
}

- (uint16_t)readUInt16  {
    uint16_t ret = *(uint16_t *)(buffer offset);
    offset  = 2;
    return ret;
}

- (uint64_t)readUInt64  {
    uint64_t ret = *(uint64_t *)(buffer offset);
    offset  = 8;
    return ret;
}

- (float_t)readSingle  {
    uint32_t t = [self readUInt32];
    float_t ret = *((float_t *)(amp;t));
    return ret;
}

- (double_t)readDouble  {
    uint64_t t = [self readUInt64];
    double_t ret = *((double_t *)(amp;t));
    return ret;
}