为什么将联合成员指针强制转换为联合指针而不是 UB,因为它们可以具有不同的大小?

问题描述 投票:0回答:1

在下面的代码片段中,发生了缓冲区溢出,即在执行

u->b = *b;
时。

class A {
public:
  int x;
  A() {
    x = 5;
  }
};

class B {
public:
  int x;
  float y;
  B() {
    x = 10;
    y = 3.14;
  }
};

union U {
  A a;
  B b;
};

U* foo(U* u) {
  B* b = new B();
  u->b = *b;
  return u;
}

int main() {
  A* a  = new A();
  U* u = (U*) a;
  u = foo(u);
  return u->b.y;
}

从我读到的here来看,演员表

(U*) a
应该有明确的定义。据我理解,它不应该是
sizeof(U) != sizeof(A)

看起来

U
A
是指针可相互转换的,但我不确定这是否意味着强制转换已定义良好。

在这种情况下,我在遵循标准时遇到了困难,欢迎任何帮助!

c++ casting language-lawyer union undefined-behavior
1个回答
0
投票

U
类型的对象可以与其子对象
U::a
进行指针互换。这可以用
std::is_pointer_interconvertible_with_class(&U::a)
进行测试。

(U*) a
reinterpret_cast<U*>(a)
。这是
static_cast<U*>(static_cast<void*>(a))
,其中 [expr.static.cast]p14 说:

否则,如果原始指针值指向一个对象 a,并且存在一个与 T 类型类似且可与

a
指针相互转换的对象 b,则结果是指向 b 的指针.

该地址处可能不存在U类型的对象,这意味着您不会获得指向

U
的指针,而只是指向
U
类型的
*a
类型的指针。
随后像 

U

一样访问它是未定义的行为(出于明显的原因,在

[basic.lval]p11
中给出)。

但是,这有可能避免 UB。
operator new

调用可以返回比请求更多的字节(

[basic.stc.dynamic.allocation]p2
[new.delete.single]p3),并且operator new隐式创建对象(
[intro.object] ]p14
)和std::is_implicit_lifetime_v<U>。该
operator new
调用
could
分配足够的字节来存储 U 对象,在这种情况下,它将隐式创建
U
,从而使其格式良好。
更标准的方法是这样的:

A* a = static_cast<A*>(operator new(sizeof(U))); U* u = reinterpret_cast<U*>(a); u = foo(u); return u->b.y;

这明确避免了您担心的尺寸问题。

© www.soinside.com 2019 - 2024. All rights reserved.