【问题标题】:Casting uint16_t to unsigned int将 uint16_t 转换为 unsigned int
【发布时间】:2021-04-13 08:04:49
【问题描述】:

我们已经投射了二维数组:

struct pixel(*image_data)[width] = (struct pixel(*)[width])img->px;
  1. 我不明白它是如何转换和分配内存的?

宽度:

  unsigned width = img->size_x;

和结构图像:

struct image {
   uint16_t size_x;
   uint16_t size_y;
   struct pixel *px;
};

第二个问题:

宽度可以容纳的最大值是多少?

第三:

如果我们迭代 image_data[x][y] 其中 x 和 y 很长,那么是否存在缓冲区溢出?

【问题讨论】:

  • 这是缺陷 C 代码。 struct pixel *struct pixel(*)[width] 不兼容。此代码可能有效,也可能无效。你可能到​​处都有未定义的行为。
  • 没有像 unsigned width = img->size_x; 中的标题所建议的那样将“uint16_t 转换为 unsigned int”

标签: c casting buffer-overflow integer-overflow


【解决方案1】:
  1. 演员表不分配内存。 image_data 变量的类型是“指向struct pixel 的长度为width 的数组的指针”(在image_data 的声明点使用width 的值),所以image_data + i 是指向struct pixel 的第 i 行(从 0 开始计数)。

  2. 理论上,width 可以是不超过SIZE_MAX / sizeof (struct pixel) 的任何值,但可能会受到其他约束的限制。此外,struct image 中的 size_xsize_y 受其类型 uint16_t 的限制,最大值为 65535。

  3. 如果 x >= 0y >= 0y < width(其中 width 仍然具有值 sizeof (*image_data) / sizeof ((*image_data)[0]))并且 img->px 指向的缓冲区至少为 sizeof (struct pixel) * (x + 1) * width 字节长(并且正确对齐struct pixel) 则不会出现缓冲区溢出。

关于width变量的定义:

unsigned width = img->size_x;

img->size_x 的类型为 uint16_tuint16_t 的最大值正好 65535。width 的类型为 unsigned intunsigned int 的最大值为 至少 65535,所以width 将被初始化为img->size_x 的值而不被截断。

在问题的 cmets 中,Lundin 提到 struct Pixel *struct pixel(*)[width] 不兼容。确实如此,但 C 允许从一种指针类型转换为另一种指针类型。如果结果指针未正确对齐引用类型(此处引用类型为 struct pixel [width]),则行为未定义。数组类型比相应的元素类型具有更严格的对齐要求是非常不寻常的,所以这可能是可以的。即使数组类型比元素类型有更严格的对齐要求,只要指针实际上正确对齐就可以了。如果img->px 指向由malloccalloc 或类似分配的块,那么对于具有“基本”对齐的任何对象类型,它都正确对齐,所以没问题。主要问题是,如果通过img->pximage_data 访问像素数据,则将违反严格别名规则,因为指针具有不兼容的类型。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-20
    • 1970-01-01
    • 1970-01-01
    • 2014-04-05
    • 2012-04-28
    • 1970-01-01
    相关资源
    最近更新 更多