【问题标题】:Pointer arithmetic resulting in incorrect address write指针运算导致地址写入不正确
【发布时间】:2020-09-03 16:33:00
【问题描述】:

这里我试图将下一个block_t 的地址写入前一个块具有其有效负载结构的地址。这只是我正在测试的一个 PoC,以便稍后集成到我的主代码中。但是,它不会将地址写入下一个块,而是将地址写入自身,正如您在看到输出时会注意到的那样。

编辑 1:所以我想现在的问题归结为“如何重用分配给有效负载的指针以指向另一个块?”

#include <stdio.h>
#include <stdlib.h>

typedef unsigned word_t;

typedef struct block {
    word_t header;
    char payload[0];
} block_t;

static void set_next_free_block(block_t *block, block_t *nblock) {
    
    // Store the address of next block at the location where payload starts
    word_t *next_address = (word_t *)(block->payload);
    
    // Now write the address of next block here
    *next_address = nblock;
    
    return;
}

static block_t *get_next_free_block(block_t *block) {
    
    block_t *next_address = (block_t *)((word_t *)block->payload);
    
    return next_address;
}

int main() {
    block_t *block = (block_t *)malloc(sizeof(block_t));
    block_t *nblock = (block_t *)malloc(sizeof(block_t));
    block_t *next = NULL;
    set_next_free_block(block, nblock);
    next = get_next_free_block(block);
    printf("Block 1\nBlock address: %16x\n", (word_t)block);
    printf("Payload address: %16x\n", (word_t)block->payload);
    printf("Next: %16x\n", (word_t)next);
    printf("Block 2\nBlock address: %16x\n", (word_t)nblock);
    
    return 0;
}

我不明白为什么我在set_next_free_block中设置的指向nblock的地址的地址指向错误的地址。

当我运行它时,我得到:

【问题讨论】:

  • 首先char payload[0]; 在 ISO C 中是不允许的,所以你依赖于编译器扩展
  • *next_address = nblock; 只是写入超出分配范围(导致未定义的行为)。也许你想要word_t *payload; 而不是char payload[0];
  • 我不完全确定您要做什么(例如,如果这是一个链表内存分配器,您将同时拥有下一个块指针和有效负载)
  • 目前您没有为有效负载分配任何空间,因此您将不得不更改该部分设计。如果您将有效负载与块内联,那么您需要为块分配空间(例如,malloc(sizeof(block_t) + 100) 用于 100 字节有效负载)
  • 您没有空间容纳单个指针。 char payload[0]; (可能在通常的编译器扩展中)是一个没有空格的零大小数组。 word_t *payload; 将是单个指针

标签: c arrays pointers malloc dynamic-memory-allocation


【解决方案1】:

所以使用set_next_free_block 函数,您正试图将nblock 的地址存储在block-&gt;payload 中,对吧?

首先我将char payload[0] 更改为word_t 以正确存储地址。 char payload[0] 对我来说没有多大意义。

然后我简单地将nblock 指针转换为word_t 以获取其地址并将其存储在block-&gt;payload 中。

get_next_free_block 函数中,您无需将block-&gt;payload 转换为word_t *,然后再将其转换为block_t *

这段代码是否给出了你想要的结果?

#include <stdio.h>
#include <stdlib.h>

typedef unsigned word_t;

typedef struct block {
    word_t header;
    word_t payload;
} block_t;

static void set_next_free_block(block_t *block, block_t *nblock) {
    block->payload = (word_t)nblock;
    return;
}

static block_t *get_next_free_block(block_t *block) {
    return (block_t *)block->payload;
}

int main() {
    block_t *block = (block_t *)malloc(sizeof(block_t));
    block_t *nblock = (block_t *)malloc(sizeof(block_t));
    block_t *next = NULL;
    set_next_free_block(block, nblock);
    next = get_next_free_block(block);
    printf("Block 1\nBlock address:\t\t%16x\n", (word_t)block);
    printf("Payload address:\t%16x\n", (word_t)block->payload);
    printf("Next:\t\t\t%16x\n", (word_t)next);
    printf("Block 2\nBlock address:\t\t%16x\n", (word_t)nblock);
    getchar();

    return 0;
}

我得到以下信息:

Block 1
Block address:                   15a4a10
Payload address:                 15a4a48
Next:                            15a4a48
Block 2
Block address:                   15a4a48

【讨论】:

    【解决方案2】:

    我实际上明白我试图修改 char payload[0] 的方式是非常不正确的。虽然我们的作业使用 GCC 扩展来允许声明长度为 0 的数组只是为了添加指向块结构的指针,但长度为 0 的数组应该是结构中的最后一个元素。

    我不会在这里添加答案,因为这会以不道德的方式帮助家庭作业,我只会告诉我们已经可用的内容:

    如果我们想以多种方式使用这个负载指针,我们应该在联合中声明它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-06-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-12
      • 1970-01-01
      • 2016-02-19
      相关资源
      最近更新 更多