strcpy () / strncpy () se bloquea en el miembro de la estructura con espacio adicional cuando se activa la optimización en Unix?

Al escribir un proyecto, me encontré con un problema extraño.

Este es el código mínimo que logré escribir para recrear el problema. Estoy almacenando intencionalmente una cadena real en lugar de otra cosa, con suficiente espacio asignado.

// #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <stddef.h> // For offsetof()

typedef struct _pack{
    // The type of `c` doesn't matter as long as it's inside of a struct.
    int64_t c;
} pack;

int main(){
    pack *p;
    char str[9] = "aaaaaaaa"; // Input
    size_t len = offsetof(pack, c) + (strlen(str) + 1);
    p = malloc(len);
    // Version 1: crash
        strcpy((char*)&(p->c), str);
    // Version 2: crash
        strncpy((char*)&(p->c), str, strlen(str)+1);
    // Version 3: works!
        memcpy((char*)&(p->c), str, strlen(str)+1);
    // puts((char*)&(p->c));
    free(p);
  return 0;
}

El código anterior me está confundiendo:

Congcc/clang -O0, ambosstrcpy()&nbsp;ymemcpy()&nbsp;funciona en Linux / WSL, y elputs()&nbsp;a continuación da lo que ingresé.Conclang -O0 en OSX, el código se bloquea constrcpy().Congcc/clang -O2&nbsp;o-O3 en Ubuntu / Fedora / WSL, el códigochoca (!!)&nbsp;astrcpy(), mientrasmemcpy()&nbsp;funciona bien.Congcc.exe&nbsp;en Windows, el código funciona bien sea cual sea el nivel de optimización.

También encontré algunos otros rasgos del código:

(Parece que)la entrada mínima para reproducir el bloqueo es de 9 bytes&nbsp;(incluido el terminador cero), o1+sizeof(p->c). Con esa longitud (o más) se garantiza un bloqueo (Querido ...).Incluso si asigno espacio adicional (hasta 1 MB) enmalloc()No ayuda. Los comportamientos anteriores no cambian en absoluto.strncpy()&nbsp;se comporta exactamente igual, incluso con la longitud correcta proporcionada a su tercer argumento.El puntero no parece importar. Si miembro de la estructurachar *c&nbsp;se cambia along long c&nbsp;(oint64_t), el comportamiento sigue siendo el mismo. (Actualización: ya ha cambiado).

El mensaje de bloqueo no parece regular. Se proporciona mucha información adicional.

Probé todos estos compiladores y no hicieron ninguna diferencia:

GCC 5.4.0 (Ubuntu / Fedora / OS X / WSL, todos son de 64 bits)GCC 6.3.0 (solo Ubuntu)GCC 7.2.0 (Android, norepro ???) (Este es el GCC deC4droid)Clang 5.0.0 (Ubuntu / OS X)MinGW GCC 6.3.0 (Windows 7/10, ambos x64)

Además, esta función de copia de cadena personalizada, que se ve exactamente como la estándar, funciona bien con cualquier configuración de compilador mencionada anteriormente:

char* my_strcpy(char *d, const char* s){
    char *r = d;
    while (*s){
        *(d++) = *(s++);
    }
    *d = '\0';
    return r;
}
Preguntas:Por questrcpy()&nbsp;¿fallar? Como puede¿Por qué falla solo si la optimización está activada?Por qué nomemcpy()&nbsp;fallar independientemente de-O&nbsp;¿¿nivel??

* Si desea debatir sobre la infracción de acceso de miembros de struct, por favor diríjaseaquí.

Parte deobjdump -dLa salida de un ejecutable que falla (en WSL):

PD Inicialmente, quiero escribir una estructura, cuyo último elemento es un puntero a un espacio asignado dinámicamente (para una cadena). Cuando escribo la estructura en el archivo, no puedo escribir el puntero. Debo escribir la cadena real. Entonces se me ocurrió esta solución: forzar el almacenamiento de una cadena en el lugar de un puntero.

También por favor no te quejesgets(). No lo uso en mi proyecto, pero solo el código de ejemplo anterior.