别名 (计算)

别名(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交換演算法,其引數是二個指標,函式會假設二個指標指向不同的位置。若二個指標的位置相同(或互為別名),程式可能會出現錯誤。對於接受指標作為引數的函式來說,這是常見的問題,是否允許二個指標互為別名,需要明確的說明,特別是在會在指標指向記憶區塊,進行複雜處理的函式。

优化时冲突

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

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. . 2006-06-01 [2017-11-20]. (原始内容存档于2013-05-08).
  2. Neil Schemenauer. . 2003-07-17 [2017-11-20]. (原始内容存档于2020-06-05).
  3. Linus Torvalds. . 2003-02-26 [2017-11-20]. (原始内容存档于2020-11-12).
  4. Michael Barr. . 2012-07-27 [2017-11-20]. (原始内容存档于2020-11-29).

外部链接

This article is issued from Wikipedia. The text is licensed under Creative Commons - Attribution - Sharealike. Additional terms may apply for the media files.