Flo*_*sch 3 c++ undefined-behavior
我正在开发一个虚拟机,它使用典型的 Smi(小整数)编码,其中整数表示为标记指针。更准确地说,指针被标记,而整数只是被移动。
这与 V8 和 Dart 采取的方法相同: https: //github.com/v8/v8/blob/main/src/objects/smi.h#L17
在我们的实现中,我们有以下 Smi 代码:
// In smi.h
#include <stdint.h>
class Object {
public:
bool is_smi() const { return (reinterpret_cast<uintptr_t>(this) & 0x1) == 0; }
};
class Smi : public Object {
public:
intptr_t value() const { return reinterpret_cast<intptr_t>(this) >> 1; }
static Smi* from(intptr_t value) { return reinterpret_cast<Smi*>(value << 1); }
static Smi* cast(Object* obj) { return static_cast<Smi*>(obj); }
};
Run Code Online (Sandbox Code Playgroud)
通过此设置,gcc 12.1.0 优化了以下函数,因此当Smi 值为 0-O3时,永远不会采用“if” 。o
// bad_optim.cc
#include "smi.h"
void bad_optim(Object* o) {
if (!o->is_smi() || o == Smi::from(0)) {
printf("in if\n");
}
}
Run Code Online (Sandbox Code Playgroud)
如果我用以下代码替换“if”行,则检查有效:
if (!o->is_smi() || Smi::cast(o)->value() == 0) {
Run Code Online (Sandbox Code Playgroud)
我猜我们遇到了一种未定义的行为,但我不清楚是哪一种。
此外,最好知道是否有一个警告此行为的标志。或者,也许有一个标志可以禁用此优化。
为了完整起见,这里是main触发该行为的。(注意bad_optim和main函数必须单独编译)。
// main.cc
#include "smi.h"
void bad_optim(Object* o);
int main() {
Smi* o = Smi::from(0);
bad_optim(o);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
很简单:取消引用 invalid 或 nullo会导致 UB,因此取消引用后,o应该不能为 null。
调用is_smi()算作解引用,即使它实际上不访问内存。
创建is_smi()一个自由函数(因为这只适用于this,而不适用于指针参数)。我还会创建Object一个不透明的结构(已声明但未定义)。