Strict Aliasing

Table of Contents

1. Strict Aliasing

aliasing 是指编译器总是假设两个指针可能指向同一块内存, 导致无法进行某些优化.

strict aliasing 是指编译器放松一下前面的假设, 认为某些条件下两个指令不会指向同一块内存, 从而能进行优化.

通过 `-O2` 或 `-fstrict-aliasing` 可以打开 strict aliasing. 如果代码不符合 strict aliasing rule, 则会出现一些问题

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* no alias */
/* strict alias rule 认为 int 和 short 类型的指令 =不会= 指向同一块内存 */
void test_1(int *a, short *b) {
    *a = 0x12345678;
    b[0] = 0xabcd;
    printf("0x%x\n", *a);
}

/* no alias */
/* __restrict 告诉编译器 a 不是 alias */
void test_4(int *__restrict a, int *b) {
    *a = 0x12345678;
    b[0] = 0xabcd;
    printf("0x%x\n", *a);
}

/* may alias */
/* 相同的数据类型 (int/unsiged int/const int) 之间是 alias */
void test_2(int *a, unsigned int *b) {
    *a = 0x12345678;
    b[0] = 0xabcd;
    printf("0x%x\n", *a);
}

/* may alias */
/* char 类型总是其它任意类型的 alias */
void test_3(int *a, char *b) {
    *a = 0x12345678;
    b[0] = 0xa;
    printf("0x%x\n", *a);
}

/* may alias */
/* short_may_alias 相当于 char, 它总是其它类型的 alias */
typedef short __attribute__((__may_alias__)) short_may_alias;
void test_5(int *a, short_may_alias *b) {
    *a = 0x12345678;
    b[0] = 0xabcd;
    printf("0x%x\n", *a);
}

int main(int argc, char *argv[]) {
    int a = 0;
    test_1(&a, (short *)&a);
    test_4(&a, &a);

    test_2(&a, (unsigned int *)&a);
    test_3(&a, (char *)&a);
    test_5(&a, (short *)&a);
    return 0;
}
0x12345678
0x12345678
0xabcd
0x1234560a
0x1234abcd

为了避免 strict aliasing 导致问题, 可以:

  1. 用 `-fno-strict-alising` 关掉 strict aliasing
  2. 尽量不要使用指针的 reinterpret cast 造成 type punning, 而是使用 union 或通过 memcpy, 例如

    void foo_bad(char* buffer) {
        int *p = *((int*)buffer);
        *p = 0x1;
    }
    
    void foo_good(char* buffer) {
        int tmp = 0x1;
        memcpy(buffer, &tmp, sizeof(tmp));
    }
    

    使用 memcpy/union 不仅能避免 strict aliasing 问题, 还能避免对齐的问题

  3. 如果实在需要 alias, 只使用 char 或 may_alias 类型

Backlinks

GCC Attribute (GCC Attribute > may_alias): Strict Aliasing

RISC-V Vector Extension (RISC-V Vector Extension > gcc rvv auto vectorization): 代码使用了 __restrict 关键字, 告诉编译器不需要考虑 a 和 b 有重叠的情况, 参考 Strict Aliasing

slow_unaligned_access (mtune > riscv_tune_param > slow_unaligned_access): 或者通过 may_alias 的指明存在 type punning:

Author: [email protected]
Date: 2023-11-20 Mon 14:48
Last updated: 2023-11-20 Mon 18:23

知识共享许可协议