1

考虑这段 C 代码:

int main(int argc, char *argv[])
{
        char ***map = malloc(sizeof(char *) * 4);
        char *a[] = { "hello", "world" };
        char *b[] = { "foo", "bar" };
        char *c[] = { "test", "last" };
        map[0] = a;
        map[1] = b;
        map[2] = c;

        char *p = NULL;
        int offset = 30; // buffer exploited!

        p = **map + offset;
        if (!p)
                puts("err"); // not detected?
        else
                printf("%p %s\n", p, p);

        return 0;
}

如何(高效安全)获取map的上界地址,避免bufferoverflow错误,因为如果我char **p = map[random_offset];直接访问最终会导致运行时错误

4

3 回答 3

3

默认情况下,不检测越界访问。你必须自己处理。

您认为越界指针具有空值的假设是错误的,并且以下条件不正确。

 if (!p)
            puts("err"); // not detected?

在 C 中允许使用指针算术访问随机内存位置,但无效。

于 2013-01-27T10:04:22.307 回答
1

您必须跟踪自己访问的地址。这可以通过使用通过数组索引访问而不是使用指针算法来缓解。(例如map[entryID][0]键或map[entryID][1]值)。这使得检查 entryID 是否超过最大索引变得容易。0-1 根据合同始终有效。

更新: 如果您想跟踪数组统计信息(例如最大长度、有效条目数等),您必须自己处理。您可以通过将映射指针与所需的统计字段一起嵌入到结构中来实现此目的:

typedef struct MyMap {
    char ***map;
    unsigned int capacity;
    unsigned int last_index;
}tMyMap;

//...

void useTheMap(tMyMap *map);

// ...

    tMyMap mapInstance;

    mapInstance.map = malloc(...);
    mapInstance.capacity = ...;
    mapInstance.last_index = ...;

    useTheMap(&mapInstance);

    // ...

    for (int i = 0;i < mapInstance.last_index;i++) {
        //...
    }

当然,您必须自己更新统计字段。但这将使您有机会在运行时以更新统计字段的开销为代价找出地图的容量......(这实际上是其他 - 更方便 - 其他语言中的字符串实现的工作方式)

于 2013-01-27T10:04:13.193 回答
0

您已为地图中的哨兵分配空间,但未为其分配值。要么,使用类似memset(...)map [3] = (char **) 0;强制终止符。

然后,您可以跟踪地图的长度,或者从头开始线性扫描,直到到达匹配或终止符才停止。Junix 响应提供了第一种选择。如果列表没有排序,那么无论如何都需要线性搜索,并且长度不会真正有帮助。

对 in 类型错误的观察malloc(...)是正确的 - 但是,该语言无法根据 C 中的 LHS 值验证类型。幸运的是char *char **它们都是指针类型,并且具有相同的大小。

于 2013-01-27T22:03:12.140 回答