在linux上但不是os x的memcpy分段错误

时间:2010-04-08 18:00:23

标签: c pointers segmentation-fault memcpy

我正在为文件作为类项目实现基于日志的文件系统。我有大量的工作在我的64位OS X笔记本电脑上,但是当我尝试在CS部门的32位linux机器上运行代码时,我遇到了一个段错误。

我们给出的API允许一次写入DISK_SECTOR_SIZE(512)字节。我们的日志记录包括用户想要写入的512字节以及一些元数据(他想要写入哪个扇区,操作类型等)。

总而言之,“record”对象的大小为528字节,这意味着每个日志记录跨越磁盘上的2个扇区。

第一条记录在扇区0上写0-512,在扇区1上写0-15。 第二个记录在扇区1上写入16-512,在扇区2上写入0-31。 第三个记录在扇区2上写入32-512,在扇区3上写入0-47。 ETC。

所以我所做的是将我要修改的两个扇区读入2个新分配的缓冲区,从记录开始复制到buf1 + 512偏移字节的计算偏移量。这在两台机器上都能正常工作。

然而,第二个memcpy失败了。具体来说,“record + DISK_SECTOR_SIZE-offset”在下面的代码段错误中,但仅限于linux机器上。运行一些随机测试,它会变得更加好奇。 linux机器将sizeof(Record)报告为528.因此,如果我尝试将记录+ 500的memcpy转换为buf 1个字节,那么它应该没有问题。

实际上,我从记录中获得的最大偏移量是254.也就是说,memcpy(buf1,记录+ 254,1)可以工作,但是memcpy(buf1,记录+ 255,1)段错误。

有谁知道我错过了什么?

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 个答案:

答案 0 :(得分:10)

当你向指针p添加1时,你没有添加1个字节,你要添加sizeof(p)个字节。

因此,在这种情况下,您需要在添加record之前将char*投射到record+500。现在record实际上指向距离memcpy(buf, record+254, 1) 500 * 528 = 264,000字节。

当然,这并不能解释为什么{{1}}不会出现段错误。我想,只是“幸运”。

答案 1 :(得分:3)

record+BLAH表示在翻译成机器代码时:将BLAH*sizeof(Record)添加到record中的地址。

因此record+500不是来自record的500字节;与record相距500 * 528 = 264000字节。

答案 2 :(得分:2)

尝试在valgrind下运行您的Linux代码 - 这应该会直接找到问题的根本原因。

答案 3 :(得分:0)

记录+ DISK_SECTOR_SIZE-offset是你的问题。记录+ 1不给出记录+ 1的地址。

它为您提供记录+ 1 * sizeof(记录)的地址。 (当你递增或递减一个指针时,它会以你使用的数据类型的倍数为步。只需对你的记录指针进行类型转换:(byte *)record + DISK_SECTOR_SIZE-offset。这可以解释分段错误,因为记录长度至少为DISK_SECTOR_SIZE