首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >比较已被释放的指针是否会调用UB?

比较已被释放的指针是否会调用UB?
EN

Stack Overflow用户
提问于 2018-10-03 14:00:38
回答 3查看 435关注 0票数 8

这似乎是一种相当常见的模式,例如在十六进制(可能不编译,也见插件文档 )。还请注意,hexchat_plugin_get_info一直没有在其中使用过,所以为了简单起见,我省略了它):

代码语言:javascript
复制
static hexchat_plugin *ph;
static int timer_cb(void *userdata) {
    if (hexchat_set_context(ph, userdata)) { /* <-- is this line UB? */
        /* omitted */
    }
    return 0;
}
static int do_ub(char *word[], char *word_eol[], void *userdata) {
    void *context = hexchat_get_context(ph);
    hexchat_hook_timer(ph, 1000, timer_cb, context);
    hexchat_command(ph, "close"); /* free the context - in practice this would be done by another plugin or by the user, not like this, but for the purposes of this example this simulates the user closing the context. */
    return HEXCHAT_EAT_ALL;
}
int hexchat_plugin_init(hexchat_plugin *plugin_handle, char **plugin_name, char **plugin_desc, char **plugin_version, char *arg) {
    *plugin_name = "do_ub";
    *plugin_desc = "does ub when you /do_ub";
    *plugin_version = "1.0.0";
    ph = plugin_handle;
    /* etc */
    hexchat_hook_command(ph, "do_ub", 0, do_ub, "does UB", NULL);
    return 1;
}

timer_cb中的行会使六话将(在本例中可能是免费的)指针与另一个指针进行比较(在本例中,请参见do_ub中的注释),如果您跟随(背景)的话,您将在会议)中结束。若要调用此代码,请以十六进制方式运行/do_ub

相关守则:

代码语言:javascript
复制
int
hexchat_set_context (hexchat_plugin *ph, hexchat_context *context)
{
    if (is_session (context))
    {
        ph->context = context;
        return 1;
    }
    return 0;
}

int
is_session (session * sess)
{
    return g_slist_find (sess_list, sess) ? 1 : 0;
}

这类东西是UB吗?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2018-10-03 14:18:55

使用指针的值,在它所指向的对象到达之后,它的生存期结束是不确定的,正如C11标准草案6.2.4p2 (对象的存储时间)中所述(重点是我的):

对象的生存期是程序执行期间保证为其保留存储的部分。对象存在,具有常量地址,并在其生命周期内保留其最后存储的值.如果一个对象在其生命周期之外被引用,则该行为是未定义的。当指针所指向的对象(或刚刚过去的)到达其生命周期结束时,指针的值变为不确定的

使用它的值(仅用于任何事物)是一个显式的未定义行为,如附件J.2(未定义的行为)中所述:

此行为在下列情况下未定义:.使用指向生存期已结束的对象的指针的值(6.2.4)。

票数 7
EN

Stack Overflow用户

发布于 2018-10-03 14:37:40

是的,使用被释放的指针值--甚至一个看似无害的比较--严格地说,是未定义的行为。它不太可能在实践中造成任何实际问题,但我认为值得避免。

还请参阅C常见问题列表,问题7.21

票数 3
EN

Stack Overflow用户

发布于 2018-10-03 17:00:29

tl;dr:能够执行某些操作,例如对指针进行比较,而不考虑由此标识的对象的生存期,这是一个流行的扩展,绝大多数编译器可以配置为支持禁用优化。然而,对它的支持并不是标准所要求的,而且激进的优化器可能会破坏依赖它的代码。

在编写标准时,有一些分段内存平台,试图将指针加载到寄存器中将导致系统检索有关指针所在内存区域的信息。如果不能再获得这类信息,试图检索这些信息可能会在“标准”管辖范围之外产生任意后果。如果标准要求涉及这些指针的比较除了产生0或1之外没有任何副作用,那么这种语言在这样的平台上就会变得不切实际。

虽然“标准”的作者无疑意识到,能够使用与任意指针的比较(但要注意的是,结果可能并不特别有意义)是每一个针对传统硬件的实现所支持的有用特性,但他们认为没有必要将其视为一个“受欢迎的扩展”,每当这样做时,高质量的实现支持将是有用和实用的。

根据C89的基本原理,第11行第23行:

未指定的行为、未定义的行为和实现定义的行为等术语用于对编写程序的结果进行分类,这些程序的属性标准没有或不能完全描述。采用这种分类的目的是允许某种不同的实现,使实现的质量成为市场上的一种积极力量,并允许某些流行的扩展,而不需要消除符合标准的声望。标准附件J列出了这些行为,这些行为属于这三种类型之一。

不幸的是,尽管今天使用的几乎所有平台都可以以基本零成本(*)支持这种语义,但一些编译器作者认为,他们的愿望是,代码永远不会用自由指针做任何事情,这比程序员从传统平台上一个基本得到普遍支持的扩展中获得的任何价值更为重要。除非一个人能够保证使用自己的代码的任何人都会禁用那些过于热心的优化器的作者强加的虚假的“优化”,因为他们试图消除语言中有用的扩展,否则我们可能需要编写额外的代码来避免这些扩展的出现。

(*)在某些情况下,如果一个函数将多个指针暴露在外部代码中,将多个指针暴露到它已分配和释放的存储区域,那么就需要一个必须维护这样的指针将相等的行为保证的编译器才能实际执行泄漏指针的存储操作;将指针视为不确定值将允许删除存储。然而,在设计的方案之外,用泄露到外部世界的指针消除此类商店的成本节省很少会对性能产生任何有意义的影响。

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

https://stackoverflow.com/questions/52628773

复制
相关文章

相似问题

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