控制未初始化堆栈变量的填充值(例如0xCC)
Controlling the fill value (e.g. 0xCC) for uninitialized stack variables?
首先,一点背景知识:我们有一个框架,它将多次运行一系列测试,并确保每次运行时的状态是相同的。这捕获了许多产生不确定性行为的情况,包括由多线程或按指针值排序引起的情况。这些测试在Visual Studio 2008的Debug中运行(很快将迁移到2010)。
问题是:不幸的是,测试不能像我希望的那样经常捕获未初始化变量的使用。考虑以下情况:
struct Foo{ int m_a; int m_b; };
void doStuff( struct Foo& f);
...
Foo* bar = new Foo();
// Uninitialized in ctor, but heap initialized to 0xCD,
// so appears "deterministic"
if (bar->m_a)
{ ... }
Foo baz;
// may or may not initialize all of baz
// uninitialized members are left to 0xCC
doStuff( baz );
if (baz.m_b)
{ ... }
我想做的是在每次运行时使未初始化的值不同,以捕获这些情况,例如,第一次运行时已知垃圾,第二次运行时为0。这样,对未初始化成员的任何计算都将得到不同的结果,并且在if
语句中检查它们也将采取相反的分支。
我可以控制第一种情况,因为我们通过自己的堆路由new
和delete
。然而,我还没有能够找到关于如何控制堆栈变量的填充值的任何信息-这是可能的吗?我能在这里找到的最接近的问题是,g++可以用已知值填充未初始化的POD变量吗?,但那是为g++准备的。我不需要便携的解决方案;Visual studio特有的技巧就可以了。
注释#1:我知道lint/Rational Purify/Valgrind/[插入静态代码分析的魔弹]将会捕捉到这个问题,并且可能更加健壮。但我正在寻找一个小的改变,我可以对我们现有的框架,这些可能需要更多的时间来整合比我准备花,所以请不要建议这些。
注意#2:我们已经将警告级别设置为max,并将警告作为错误打开,这捕获了一些未初始化变量的情况,但这并不能捕获"doStuff"函数忘记初始化某些结构的所有情况。
注释#3:我不太担心性能,因为这已经在Debug中运行了,并且只用于内部测试。
注释#4:测试使用相同的可执行文件(在"write"模式下运行一次,然后在"check"模式下再次运行以比较结果),所以不幸的是,不同的编译设置目前不是一个选项。
提前感谢!
您可以尝试找出哪些代码正在进行填充并在运行时修补它。如果dllversion是固定的,那么对于调试构建来说,这应该是可以接受的。您可能需要能够处理不同的dll加载地址,因为出于安全原因,它们可能在随机位置加载。
我发现编译器在跟踪这类问题时非常有帮助,使用如下命令:
class checked_int_t {
int i_;
public:
checked_int_t(int const i) : i_ (i) { }
operator int() const { return i_; }
};
现在你的代码可能会像下面这样改变,当你分配一个Foo对象时,会产生一个编译时错误,因为m_a没有在默认构造函数中初始化。
struct Foo{
checked_int_t m_a;
int m_b;
};
请注意,您可以增量地执行此操作以检查未初始化的变量,因此您不必进行大的更改。只要找到一个你认为没有正确初始化的变量并改变它的类型。如果以后一定要设置该值,可以这样做:
class checked_int_t {
int i_;
bool set_;
public:
checked_int_t() : set_ (false) { }
checked_int_t(int const i) : i_ (i), set_ (true) { }
operator int() const { assert(set_); return i_; }
};
您可以使用条件编译来删除发布模式下的类。
#ifdef NDEBUG
typedef int checked_int_t;
#else
class checked_int_t {
int i_;
public:
checked_int_t(int const i) : i_ (i) { }
operator int() const { return i_; }
};
#endif
- 子目录是否继承属性,例如add_definitions,include_directories和父Cmakelist.t
- 标准是否使用多余的大括号(例如 T{{{10}}})定义列表初始化?
- 将数字转换为字母(例如:123 转换为一二三)
- Visual studio代码重构似乎不起作用(例如,重命名符号-f2)
- 如何计算数据类型的范围,例如int
- 这是否符合C++标准:双响双响,例如!!(-0.0).
- 如何将CMSampleBufferRef/CIImage/UIImage转换为像素,例如uint8_t[]
- 使用 make 编译 MPI,几个命名空间错误,例如"错误:未知类型名称'使用'?
- 如何使用文件中的文本,例如变量
- 输入值后,如何在一个括号下显示值,例如"{6,7,8,9}
- 给定一个类型,如何派生一个泛型更广泛的类型(例如,用于溢出安全求和)?
- 初学者问题:如何使用这些晦涩难懂的命令,例如C++中的'RenderWindow'
- C++:将值 int(例如:0x00AAFAD8)转换为指针(指针本身也是 0x00AAFAD8 值)
- 具有多种约束(例如重量、体积等)的背包
- 较高值 n 的分割错误(例如 n=999997)
- 我正在尝试制作一个程序,在添加 n 天(整数)后告诉一个人什么是一天(例如星期一等)
- 在标准中,模板参数的语法在哪里定义,例如,'std::function<int(char)>'?
- 从/到 UTF-8/UTF-16 的转换需要(例如:utf8 -> 代码点,然后代码点到 utf16)或(例如:utf8 -> utf16)?
- 计算车辆之间的距离并设置速度,使距离保持不变,例如 5 米
- 控制未初始化堆栈变量的填充值(例如0xCC)