Recentemente, mudamos para um GCC mais recente e ele otimizou uma função inteira e a substituiu pelo código de armadilha "acesso ao ponteiro nulo" ao otimizar o tamanho. Olhando para godbolt, o problema apareceu com o GCC 11.1 ao otimizar com -Os
. Otimizar com -O2
e -O3
funciona bem, mesmo com -fstrict-aliasing
.
Simplificado, o código fica assim ( link godbolt ):
#include <inttypes.h>
#include <stddef.h>
#include <string.h>
typedef struct bounds_s {
uint8_t *start;
uint8_t *end;
} bounds_s_t;
static void reserve_space(bounds_s_t *bounds, size_t len, uint8_t **element)
{
if (bounds->start + len > bounds->end) {
return;
}
*element = bounds->start;
bounds->start += len;
}
void bug(uint8_t *buffer, size_t size)
{
bounds_s_t bounds;
uint32_t *initialize_this;
initialize_this = NULL;
bounds.start = buffer;
bounds.end = buffer + size;
reserve_space(&bounds, sizeof(*initialize_this), (uint8_t **)&initialize_this);
uint32_t value = 1234;
memcpy(initialize_this, &value, sizeof(*initialize_this));
}
E leva à seguinte montagem:
bug:
xor eax, eax
mov DWORD PTR ds:0, eax
ud2
Que otimização faz o GCC pensar que a initialize_this
variável é NULL? A única coisa que me vem à mente é quebrar regras rígidas de alias. Mas será que a tipificação de ponteiros duplos pode uint32_t **
realmente uint8_t **
ser o problema aqui e levar a consequências tão pesadas?