【发布时间】:2018-09-13 18:37:13
【问题描述】:
我正在优化一些代码,我有一个这样的函数:
const char * gStrPtr = NULL;
void foo (const char *str) {
gStrPtr = strdup(str);
}
截至目前,foo() 仅使用常量字符串调用。例如:
const char fooStr[]="Some really long string...";
foo(fooStr);
请注意,因为它总是用常量调用,所以我应该可以这样做:
void foo (const char *str) {
gStrPtr=str;
}
但是,它打开了一根锋利的棍子:如果将来有人违反约定,并尝试使用稍后释放的字符串的动态副本调用foo(),则可能会导致未定义的行为。
我想知道是否有可能创建一个编译时甚至是运行时检查来检查str 是否在只读内存中,以避免以后出现昂贵的错误。
注意:如果我假设 str 是一个字符串文字,那么我可以使用宏来做到这一点:
#define foo(str) foo_func("" str)
这将导致非字符串文字的编译错误。但它也不接受指向 const 字符的指针。
编辑
我想我会在下面的讨论之后发布这个。 @CraigEtsy 指出了__builtin_constant_p 的使用,这是解决此问题的最佳方法(但可能足以满足我的需求)。我对此进行了以下测试,并得到了这些结果:
void foo(const char *str) {
if (__builtin_constant_p(*str))
printf("%s is constant\n", str);
else
printf("%s is not constant\n", str);
}
const char globalArray[] = "globalArray";
const char *globalPtr = "globalPtr";
int main()
{
const char localArray[]="localArray";
const char *localPtr="localPtr";
char localNonConst[]="localNonConst";
foo("literal"); // constant
foo(localArray); // not constant
foo(localPtr); // constant
foo(globalArray); // constant
foo(globalPtr); // not constant
foo(localNonConst); // not constant
}
当使用 -O3 编译时,它给出了结果:
literal is constant
localArray is not constant
localPtr is constant
globalArray is constant
globalPtr is not constant
localNonConst is not constant
因此,对于我的特殊情况,我可以将const char arr[]="str" 切换到const char * arr="str",然后,在我的foo() 中,我可以检查该值是否为常量,并分配内存并提高运行时如果不是,则发出警告(并标记一个标志,以便我知道以后是否释放指针......)。
【问题讨论】:
-
问题不是只读内存而是静态存储(例如我可以用
mmap动态分配只读内存并稍后释放)。我不认为你可以检查。 -
不,你不能那样做。
-
我想我想检查指针是否位于
.text部分... -
如果你
void myfunc() { const char mystr[] = "abc"; foo(mystr); }然后使用gStrPtr 怎么办?mystr是否在只读内存中?什么是只读存储器? -
您可以使用 [with
gcc]、__builtin_constant_p函数和一个在函数返回 false 时执行strdup的宏。如果你给它"abc",它返回true,否则返回false。然后,您可以对.rodata部分进行范围检查并直接设置是否在其中,但如果不是,则执行strdup。也许太乱了,但我想我会把它传递下去。