может быть на не отображенной странице памяти.

р, показывающий оптимизацию gcc и код пользователя, который может быть ошибочным

Функция 'foo' в приведенном ниже фрагменте загрузит только один из членов структуры A или B; ну, по крайней мере, это намерение неоптимизированного кода.

typedef struct {
  int A;
  int B;
} Pair;

int foo(const Pair *P, int c) {
  int x;
  if (c)
    x = P->A;
  else
    x = P->B;
  return c/102 + x;
}

Вот что дает gcc -O3:

mov eax, esi
mov edx, -1600085855
test esi, esi
mov ecx, DWORD PTR [rdi+4]   <-- ***load P->B**
cmovne ecx, DWORD PTR [rdi]  <-- ***load P->A***
imul edx
lea eax, [rdx+rsi]
sar esi, 31
sar eax, 6
sub eax, esi
add eax, ecx
ret

Таким образом, похоже, что gcc разрешено спекулятивно загружать оба члена структуры для устранения ветвления. Но тогда считается ли следующий код неопределенным поведением или оптимизация gcc выше запрещена?

#include <stdlib.h>  

int naughty_caller(int c) {
  Pair *P = (Pair*)malloc(sizeof(Pair)-1); // *** Allocation is enough for A but not for B ***
  if (!P) return -1;

  P->A = 0x42; // *** Initializing allocation only where it is guaranteed to be allocated ***

  int res = foo(P, 1); // *** Passing c=1 to foo should ensure only P->A is accessed? ***

  free(P);
  return res;
}

Если предположения о загрузке произойдут в приведенном выше сценарии, есть вероятность, что загрузка P-> B вызовет исключение, поскольку последний байт P-> B может находиться в нераспределенной памяти. Это исключение не произойдет, если оптимизация отключена.

Вопрос

Является ли приведенная выше оптимизация gcc для спекуляций нагрузки допустимой? Где спецификация говорит или подразумевает, что это нормально? Если оптимизация законна, как код в naughtly_caller может оказаться неопределенным поведением?

Ответы на вопрос(6)

Ваш ответ на вопрос