别名(Aliasing)是指内存中的一个数据位置可以通过程序中的多个名称来访问。通过某一个名称修改数据,其他别名关联的值也会改变,这是程序员可能不会预期到的。别名的存在使得程式的理解、分析及优化程序变得困难。别名分析可以分析处理程序中有关别名的信息。

例子 编辑

缓冲区溢出 编辑

大部分C语言的实现都不会有阵列索引的边界检查。因此,可以利用此一漏洞,写入在阵列范围外的资料(缓冲区溢出),根据C语言的标准,这是未定义行为,但在大部分没有阵列索引边界检查的C语言中,会出现上述的别名效果,用某一个名称更改资料,而对应别名的数值随之变化。

若阵列是在呼叫堆叠中产生,而有变数恰好就在阵列位置的前后,写入阵列索引范围外的元素,可能就会改到该变数。例如,假设有二个元素的int阵列(其名称为arr),后面是一个int变数(名称是i),若arr[2](阵列的第三个元素)位置和i相同,这二个变数就互为别名。

# include <stdio.h>

int main()
{
 int arr[2] = { 1, 2 };
 int i=10;

 /* Write beyond the end of arr. Undefined behaviour in standard C, will write to i in some implementations. */
 arr[2] = 20;

 printf("element 0: %d \t", arr[0]); // outputs 1
 printf("element 1: %d \t", arr[1]); // outputs 2
 printf("element 2: %d \t", arr[2]); // outputs 20, if aliasing occurred
 printf("i: %d \t\t", i); // might also output 20, not 10, because of aliasing, but the compiler might have i stored in a register and print 10
 /* arr size is still 2. */
 printf("arr size: %d \n", (sizeof(arr) / sizeof(int)));
}

在一些C语言的实现中,有可能会出现上述的结果,因为这些实现会为阵列安排一块连续的内存,而阵列元素就是用阵列位置再位移阵列索引值乘以阵列元素大小,再进行间接定址。C语言没有边界检查,因此阵列的存取可能会超过阵列范围。上述的别名效果其实属于未定义行为,有些实现方式会不会让堆叠中的变数紧邻阵列,例如,依其处理器的长度有对齐功能等。C语言标准没有特别说明资料在内存中摆放的方式(ISO/IEC 9899:1999, section 6.2.6.1)。

若C语言编辑器在存取阵列范围以外的位置时,没有别名效果,这也是可以的。

别名指针 编辑

另一种编程语言中会出现的别名,是指用不同的变数(例如指标)参考同一个位置的内存。例如XOR交换算法英语XOR swap algorithm,其引数是二个指标,函式会假设二个指标指向不同的位置。若二个指标的位置相同(或互为别名),程式可能会出现错误。对于接受指标作为引数的函式来说,这是常见的问题,是否允许二个指标互为别名,需要明确的说明,特别是在会在指标指向记忆区块,进行复杂处理的函式。

优化时冲突 编辑

优化编译器在存在指针时往往对变量做出保守假设。如常量传播能否使用。代码重排序(code reordering)也受别名的影响,这可能会改善指令调度或允许更多的循环优化英语loop optimization.

C语言C99标准,提出了严格别名规则(strict aliasing rule)见section 6.5, paragraph 7。指出使用不同类型的指针访问同一内存位置是违规的。编译器因而可以假定不同类型的指针不会是别名,这可能带来性能的巨大提升。[1]一些著名项目,如Python 2违反了此规则。[2]Linux内核也解决了类似问题。[3] 使用gcc编译选项-fno-strict-aliasing可关闭此规则。

C++11规定下述广义左值类型为严格别名规则的例外情形:

  • 对象的动态类型
  • cv量化版本
  • signed或unsigned版本
  • 聚合类型(如struct、class)或union类型,包含此前所指的类型作为它的元素,或非静态数据成员(包括递归嵌套类型)
  • 动态类型的基类型
  • char或unsigned

参见 编辑

参考文献 编辑

  1. ^ Mike Acton. Understanding Strict Aliasing. 2006-06-01 [2017-11-20]. (原始内容存档于2013-05-08). 
  2. ^ Neil Schemenauer. ANSI strict aliasing and Python. 2003-07-17 [2017-11-20]. (原始内容存档于2020-06-05). 
  3. ^ Linus Torvalds. Re: Invalid compilation without -fno-strict-aliasing. 2003-02-26 [2017-11-20]. (原始内容存档于2020-11-12). 
  4. ^ Michael Barr. Software Based Memory Testing. 2012-07-27 [2017-11-20]. (原始内容存档于2020-11-29). 

外部链接 编辑