El segmentation fault, segmentation violation, segfault, SIGSEGV o violación de acceso es la pesadilla de muchos, casi siempre causada por presencia de "undefined behaviour" (UB), lo primero que viene a la mente es punteros y memoria no asignada por ejemplo:
std::vector<int> *v;
v->push_back(5);
Pero hoy les traigo una nueva forma de ocasionar un SIGSEGV sin usar punteros, memoria dinámica o malas practicas, con un objeto stack llamando a cualquier metodo va a generar un heap-buffer-overflow. Para esto vamos a crear una app con qml y C++ en Qt Creator. Después de tener el proyecto listo vamos a agregar una clase para el backend de nuestra app, esta solo tiene una función miembro que lo que hace es escribir a stderr, tiene un parámetro de tipo QVariantMap porque cuando pasas un objeto de javascript a C++ el runtime de qml lo convierte.
En la función main vamos a crear una instancia de esa clase y hacerla accesible desde qml
Como detonador vamos a crear una ventana con un botón, al hacer click se invoca la función con un objeto y es to inicia la reacción en cadena
Ok, hasta aquí todo parece normal, todo es muy simple y no hay forma de que falle ¿Entonces donde esta el truco? ¡En las instrucciones de compilación! Este error lo encontre usando GCC (MinGW en windows), la biblioteca estandar incluida con GCC (libstdc++) tiene un modo debug, para activarlo hay que pasar un define al compilador: _GLIBCXX_DEBUG. Al activarlo g++ utiliza versiones debug de contenedores estandar que realizan mas verificaciones que lo normal, en la linea 7 se ve como se activa.
Tarde mucho en aislar el error porque tenia otros bugs y ya reparados parecia muy extraño ver un segfault en un objecto stack allocated, pero logre detectar lo que pasaba gracias al backtrace, pude ver que se estaba usando std::__debug::map en vez del regular, esto estaba causando un problema de incompatibilidad de ABI porque Qt6 esta compilado sin el modo debug y el memory layout es diferente y al querer accesar a los datos estos no estan el la misma direccion
Para concluir surge esta pregunta: ¿Esto es UB? Se siguen todas las buenas practicas de C++ moderno en el proyecto y el código en si no tiene bugs, pero técnicamente si tiene UB porque al hacer el include el código de la biblioteca pasar a ser parte del programa, los contenedores de la biblioteca abstraen el manejo de memoria y aquí al acceder a una función a traves de una API no compatible se mostró el problema
El proyecto completo esta en mi github no olviden ponerle estrella