如果对表达式的求值导致C中的未定义行为,并且在执行程序时总是计算表达式(例如,如果它出现在开头main
),那么如果实现在编译时拒绝它,它是否符合要求?在编译/翻译程序和执行程序之间,C有区别吗?
我知道有C的口译员.他们如何按照C标准处理这种差异?
示例(读取未初始化的本地)
int main() { int i; return i; }
在运行它时,在执行的任何阶段(甚至在main
调用之前),程序都可以做一些有趣的事情.但是,当我们甚至没有试图运行它时,还会发生一些有趣的事吗?它会在编译器本身导致缓冲区溢出吗?
从C11草案:
3.4.3未定义的行为
使用不可移植或错误的程序结构或错误数据时的行为,本国际标准不对此要求
注意可能的未定义行为包括完全忽略具有不可预测结果的情况,在转换或程序执行期间以环境特征(有或没有发出诊断消息)的特定文档执行,终止转换或执行(使用发布诊断消息).
提到终止翻译是(非规范)注释中未定义行为的可能后果,因此编译时效果显然无意排除.规范部分肯定允许它 - 它允许任何东西.因此,如果在编译期间检测到未定义的行为,则符合标准的编译器可以终止转换.
此外,4美元一致性:
如果违反约束或运行时约束之外的''shall''或''shall not''要求,则行为未定义.未定义的行为在本国际标准中以"未定义的行为"或"省略行为的任何明确定义"的方式表示.这三者之间的重点没有区别; 他们都描述了"未定义的行为".
在"翻译时间"和"执行时间"之间的规范性定义或一致性描述中没有区别.未定义行为的不同"变种"之间没有区别.
此外,ouah在Can代码中指出的缺陷报告#109 将永远不会被执行调用未定义的行为?有这个回应:
[...]如果一个表达式的评估会导致未定义的行为出现在需要常量表达式的上下文中,则包含的程序并不严格符合.此外,如果给定程序的每个可能的执行都会导致未定义的行为,则给定的程序不严格符合.
一致的实现必须简单地转换严格符合的程序,因为该程序的某些可能的执行将导致未定义的行为.[...]
这表明如果编译器无法静态确定所有路径都会导致未定义的行为,则编译器不能使转换失败.
在C11标准中,§3.7.1在术语未定义行为的定义下声明:
未定义的行为:在使用不可移植或错误的程序结构或错误数据时的行为,本国际标准不对此要求
2注意可能的未定义行为包括完全忽略不可预测结果的情况,以及以环境特征(有或没有发出诊断消息)的文档化方式执行转换或程序执行,终止翻译或执行(带有发出诊断信息).
所以我猜你可以静态拒绝包含未定义行为的程序,即使它是有效的.
如果实现在编译时拒绝它,它是否符合?
它可能会也可能不会.C标准在第3.4.3节中说明了这一点:
C11:3.4.3 未定义的行为
使用不可移植或错误的程序结构或错误数据时的行为,本国际标准不对此要求
注意可能的未定义行为包括完全忽略具有不可预测结果的情况,在转换或程序执行期间以环境特征(有或没有发出诊断消息)的特定文档执行,终止转换或执行(使用发布诊断消息).
所以回答你的问题:它能否在编译器本身导致缓冲区溢出?
是的,它可以.