首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >结构对齐安全使用

结构对齐安全使用
EN

Stack Overflow用户
提问于 2016-08-10 17:28:03
回答 2查看 173关注 0票数 5

我是一家公司的新手,公司完成了以下结构的使用:

代码语言:javascript
复制
#include <stdio.h>
#include <string.h>

typedef unsigned char uint8;
typedef signed char int8;
typedef unsigned short int uint16;
typedef signed short int int16;

typedef struct padded_t {
    int8 array0[11];
    int8 array1[4];
    uint16 len2;
    int8 array2[25];
    uint16 len3;
    int8 array3[6];
    // many more len/arrays follow
} padded_t;

int main(int argc, char** argv)
{
    padded_t foo;
    memset((void*)&foo, 0, sizeof(padded_t));

    int8* str = "foobar";
    int16 size = (int16)strlen(str);

    int8* ptr = (int8*)&foo.len2;

    // please note that the memcpy references only the pointer to len
    // are the following couple of lines safe?
    memcpy ((void*)ptr, &size, 2);
    memcpy ((void*)&ptr[2], (void*)str, size);

    printf("%d\n", foo.len2);
    printf("%s\n", foo.array2);

    return 0;
}

我知道一些关于对齐和填充的事情,我假设编译器( ARM9设备的gnu ARM9)会添加一些填充来使结构对齐。

但这密码安全吗?

据我所知,只要uint16 len变量紧跟在int8 array[]变量之后,无论其他结构成员如何,它都是安全的。

当uint16之前的大小是奇数时,它会只在它之前添加垫子吗?

这个用法正确吗?更重要的是,这安全吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-08-10 18:30:52

但这密码安全吗? 据我所知,只要uint16 len变量紧跟在int8 array[]变量之后,无论其他结构成员如何,它都是安全的。

从某种意义上说,编译器可以在结构成员之间或之后插入任意数量的填充,这是不安全的,因此您不能确信&ptr[2]指向foo.array2的第一个字节。但是,如果uint16确实有两个字节宽(这绝不是语言所保证的),那么您可以确信,如果size小于25,那么

代码语言:javascript
复制
memcpy ((void*)&ptr[2], (void*)str, size);

不会修改foo.len2的任何字节,也不会修改foo.array2的最后一个字节。由于foo之前填充了零,这将使foo.array2保留为一个正确终止的C字符串。因此,用printf()打印它是安全的。另一方面,C并不保证这样做的结果与打印str的结果相同。

当uint16之前的大小是奇数时,它会只在它之前添加垫子吗?

这由编译器自行决定。它可能会受到语用、命令行选项、配置选项、语言扩展(尽管这些选项在示例中都没有使用)、目标体系结构或编译器希望用来做出此类决定的任何其他因素的影响。

这个用法正确吗?

据我所知,这个程序是一致的,如果你是这个意思的话。

更重要的是,这安全吗?

程序的输出仅从其代码中是不可预测的,因此在这个意义上,不,它是不安全的。

票数 2
EN

Stack Overflow用户

发布于 2016-08-10 18:22:36

您不需要编写适用于每个系统的代码。您应该做的是编写具有可预测行为的代码。要么按设计工作,要么假设不成立,静态断言就会中止编译。

第二个memcpy行无法做到这一点。它假设offsetof(struct padded_t, len2) + 2 == offsetof(struct padded_t, array2)。这一假设往往站得住脚,但却是完全愚蠢的。

为什么不直接写

代码语言:javascript
复制
foo.len2 = strlen(str);
memcpy (foo.array2, str, foo.len2);
//possibly, foo.array2[foo.len2] = '\0';

代码是可读的。没有不需要的变量。没有不必要的石膏。没有不可预测的行为。原来的代码看起来不像你会学到的很多代码,杂乱的东西看上去不像我所期望的一个精通C的人写的东西。

回答你的评论,让他们打包是错误的解决办法。因为它会使成员不对齐,并且只会打开another can of worms

也要警惕定制的固定大小的打字机。我曾经有过在一个系统上调试typedef char int8;的乐趣,该系统具有charunsigned…。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/38879913

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档