我今天遇到了这段代码:
ushort *LibRaw::ljpeg_row(int jrow, struct jhead *jh)
{
ushort mark = 0, *row[3];
// Irrelevant code here...
FORC3 row[c] = jh->row + jh->wide * jh->clrs * ((jrow + c) & 1);
// Irrelevant code here...
return row[2];
}
void LibRaw::canon_sraw_load_raw()
{
short *rp = 0, (*ip)[4];
// Irrelevant code here...
rp = (short *)ljpeg_row(jrow++, &jh);
// Few lines of code with no assignment to any variable...
FORC(jh.clrs - 2)
{
ip[col + (c >> 1) * width + (c & 1)][0] = rp[jcol + c];
ip[col + (c >> 1) * width + (c & 1)][1] =
ip[col + (c >> 1) * width + (c & 1)][2] = 8192;
}
// Irrelevant code here...
}
让我们将
ljpeg_row
函数作为被调用者,将 canon_sraw_load_raw
作为调用者。据我了解,变量 row
是一个 ushort 指针数组,长度为 3。这在被调用者内部以有效的方式使用。但是,在按值返回数组的单个元素后,调用者将遍历此指针 (rp
),因为它是一个数组! FORC
/FORC3
宏扩展为 for 循环,递增 c
。在我的示例中,FORC(jh.clrs - 2)
c
至少递增一次。
现在我的问题:
rp[jcol + c]
不会有垃圾。row
数组分配在哪里,不仅尝试触摸它,而且还尝试从那里读取有用的数据?!所以,这是一个著名的开源库,有很多贡献者,所以我很犹豫这是不是一个错误(因此要打开一个新的 github 问题并询问)。此外,它可以正常编译和运行,没有分段错误。此外,我检查了 git repo,上面的代码是从 6 年前的第一次提交开始的。然而我们就在这里。我在这里缺少什么?
我已经编译并运行了代码。运行没有问题。 我已经完成了我的橡皮鸭调试,但我无法看透这一点! 我搜索了类似的问题,例如:
https://stackoverflow.com/questions/12416459/can-i-use-a-void-pointer-in-c-as-an-array
只是进一步验证我的问题。
这是原始文件的链接(如果您想检查我已删除的代码): https://github.com/LibRaw/LibRaw/blob/master/src/decoders/decoders_dcraw.cpp
将指向单个项目的指针视为数组是一种常见的做法,但根据静态分析器,它不是“有效的”。
让我们考虑一个 3 槽阵列,
a
:
+---+---+---+
a[3] | 0 | 1 | 2 |
+---+---+---+
我们不知道数组末尾后面是什么。 访问
a[3]
是未定义的行为。
鉴于:
int * p = &a[2]; // Valid location
我们毫无疑问地知道,
p
指向单个项目。p
,但我们不能保证它指向有效的位置。++p; // Valid operation of incrementing a pointer.
有效位置的测试是指针被取消引用时。 在此上下文中有效意味着该位置有可读内存。 然而,指针
p
现在有可能指向一个不包含任何内存的地址。 在这种情况下,引用将调用未定义的行为。
当使用指向不再指向有效对象的单个对象的指针时,会做出许多假设(例如通过递增)。 这些假设可能有效,也可能无效。 您所能保证的是指向单个对象的指针对该对象有效;对修改后的指针的任何取消引用都是未定义的行为。