Ошибка сегментации memcpy в Linux, но не в OS X - PullRequest
4 голосов
/ 08 апреля 2010

Я работаю над реализацией файловой системы на основе журнала для файла как проекта класса. У меня достаточно много работы на моем 64-битном ноутбуке с OS X, но когда я пытаюсь запустить код на 32-битных Linux-машинах отдела CS, я получаю ошибку seg.

API, который мы предоставляем, позволяет записывать DISK_SECTOR_SIZE (512) байтов за раз. Наша запись в журнале состоит из 512 байтов, которые пользователь хочет записать, а также некоторых метаданных (в какой сектор он хочет записать, тип операции и т. Д.).

В целом размер объекта «запись» составляет 528 байт, что означает, что каждая запись журнала занимает 2 сектора на диске.

Первая запись записывает 0-512 в секторе 0 и 0-15 в секторе 1. Вторая запись записывает 16-512 в секторе 1 и 0-31 в секторе 2. Третья запись записывает 32-512 в секторе 2 и 0-47 в секторе 3. Т.Д.

Итак, что я делаю, так это читаю два сектора, которые я буду модифицировать в 2 вновь выделенных буфера, копируя, начиная с записи, в buf1 + вычисленное смещение для байтов с 512 смещением. Это работает правильно на обеих машинах.

Однако вторая memcpy не работает. В частности, "record + DISK_SECTOR_SIZE-offset" в приведенных ниже ошибках кода, но только на машине с Linux. Запустив несколько случайных тестов, становится любопытнее Машина Linux сообщает, что sizeof (Record) равен 528. Поэтому, если я попытаюсь записать memcpy из записи + 500 в buf за 1 байт, у него не должно возникнуть проблем.

На самом деле самое большое смещение, которое я могу получить из записи, - 254. То есть memcpy (buf1, record + 254, 1) работает, но memcpy (buf1, record + 255, 1) segfaults.

Кто-нибудь знает, что мне не хватает?

Record *record = malloc(sizeof(Record));
record->tid = tid;
record->opType = OP_WRITE;
record->opArg = sector;
int i;
for (i = 0; i < DISK_SECTOR_SIZE; i++) {
  record->data[i] = buf[i]; // *buf is passed into this function
}

char* buf1 = malloc(DISK_SECTOR_SIZE);
char* buf2 = malloc(DISK_SECTOR_SIZE);

d_read(ad->disk, ad->curLogSector, buf1);  // API to read a specified sector into a buffer
d_read(ad->disk, ad->curLogSector+1, buf2);

memcpy(buf1+offset, record, DISK_SECTOR_SIZE-offset);
memcpy(buf2, record+DISK_SECTOR_SIZE-offset, offset+sizeof(Record)-sizeof(record->data));

Ответы [ 4 ]

10 голосов
/ 08 апреля 2010

Когда вы добавляете 1 к указателю p, вы не добавляете 1 байт, вы добавляете размер (p) байтов.

Так что в этом случае вам необходимо привести record к char* перед добавлением к нему. Прямо сейчас record+500 фактически указывает 500 * 528 = 264 000 байт от record.

Конечно, это не объясняет, почему memcpy(buf, record+254, 1) не работает по-умолчанию. Думаю, просто "повезло".

3 голосов
/ 08 апреля 2010

record+BLAH означает, при переводе в машинный код: добавить BLAH*sizeof(Record) к адресу в record.

То есть record+500 - это не 500 байтов от record; это 500 * 528 = 264000 байт от record.

2 голосов
/ 08 апреля 2010

Попробуйте запустить свой код Linux под valgrind - это должно привести вас к основной причине проблемы.

0 голосов
/ 08 апреля 2010

запись + DISK_SECTOR_SIZE-смещение это ваша проблема. запись + 1 не дает и адрес записи + 1.

Он дает вам и адрес записи + 1 * sizeof (запись). (когда вы увеличиваете или уменьшаете указатель, он становится кратным типу данных, который вы используете. Просто введите тип указателя записи следующим образом: (byte *) record + DISK_SECTOR_SIZE-offset. Это объяснило бы ошибку сегментации, поскольку запись имеет длину не менее DISK_SECTOR_SIZE .

...