Glad: Segfault al llamar a la función desde una biblioteca de objetos compartidos

Creado en 31 may. 2018  ·  3Comentarios  ·  Fuente: Dav1dde/glad

Estoy usando glad en un archivo que se compila como una biblioteca de objetos compartidos. Cuando
Cargo dinámicamente una función de esa biblioteca y la llamo, obtengo un segfault.

Este error de segmentación ocurre solo cuando la función cargada dinámicamente contiene llamadas a
Funciones OpenGL que han sido cargadas por glad. Si uso Glew, en lugar de contento,
en la biblioteca, el programa funciona como se esperaba.

Ejemplo

He intentado hacer un ejemplo razonablemente mínimo que reproduzca el problema.
Se abre una ventana proporcionada por glfw, una función se carga dinámicamente desde
lib.so con dlopen() y dlsym() , y se llama a esa función. los
La función simplemente borra la pantalla a azul.

Cuando se usa glad, se lanza un segfault durante la llamada a glClearColor() .

Pasos para reproducir

  1. $ chmod +x build.sh && ./build.sh && ./main
  2. Ver segfault
  3. Descomente las líneas comentadas en build.sh
  4. $ .build.sh && ./main
  5. Ver una bonita pantalla azul, según lo previsto

Estructura

.
├── build.sh
├── include
│   ├── glad
│   │   └── glad.h
│   └── KHR
│       └── khrplatform.h
└── src
    ├── glad.c
    ├── lib.c
    └── main.c

4 directories, 6 files

build.sh

#/usr/bin/sh

gcc -std=c99 -Iinclude -Wall -Wextra -Wshadow \
    src/main.c src/glad.c -o main \
    -ldl -lglfw -lGL


gcc -std=c99 -Iinclude -Wall -Wextra -Wshadow -fpic -shared \
    src/lib.c src/glad.c -o lib.so \
    -ldl -lglfw -lGL

# building the library with GLEW fixes the problem
#gcc -std=c99 -Wall -Wextra -Wshadow -fpic -shared \
#    -DUSE_GLEW \
#    src/lib.c -o lib.so \
#    -ldl -lglfw -lGL -lGLEW

src / glad.c

/*

    OpenGL loader generated by glad 0.1.24a0 on Thu May 31 07:06:52 2018.

    Language/Generator: C/C++
    Specification: gl
    APIs: gl=3.3
    Profile: compatibility
    Extensions:

    Loader: True
    Local files: False
    Omit khrplatform: False

    Commandline:
        --profile="compatibility" --api="gl=3.3" --generator="c" --spec="gl" --extensions=""
    Online:
        http://glad.dav1d.de/#profile=compatibility&language=c&specification=gl&loader=on&api=gl%3D3.3
*/

// ...

src / lib.c

#ifdef USE_GLEW
#include <GL/glew.h>
#else
#include <glad/glad.h>
#endif

void draw_blue_screen()
{
    glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);
}

src / main.c

#include <stdio.h>
#include <stddef.h>
#include <dlfcn.h>

#include <glad/glad.h>
#include <GLFW/glfw3.h>

typedef void (draw_blue_screen_func)(void);

int main(void)
{
    if (!glfwInit())
    {
        fprintf(stderr, "GLFW initialization failed\n");
        return -1;
    }

    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);

    GLFWwindow* window = glfwCreateWindow(800, 600, "example", NULL, NULL);
    if (!window)
    {
        fprintf(stderr, "GLFW window creation failed\n");
        glfwTerminate();
        return -1;
    }
    glfwMakeContextCurrent(window);

    if (!gladLoadGLLoader((GLADloadproc) glfwGetProcAddress))
    {
        fprintf(stderr, "glad initialization failed\n");
        glfwDestroyWindow(window);
        glfwTerminate();
        return -1;
    }

    // Dynamically load a function from lib.so
    void *lib_code = dlopen("./lib.so", RTLD_LAZY);
    draw_blue_screen_func *draw_blue_screen = (draw_blue_screen_func *) dlsym(lib_code, "draw_blue_screen");

    uint64_t frame_number = 0;
    while (!glfwWindowShouldClose(window))
    {
        printf("Frame %" PRIu64 "\n", frame_number);

        draw_blue_screen();

        glfwSwapBuffers(window);
        glfwPollEvents();
        frame_number++;
    }

    glfwDestroyWindow(window);
    glfwTerminate();
    return 0;
}
question

Comentario más útil

Además, ¡gracias por alegrarte! Ha sido bastante agradable de usar.

Todos 3 comentarios

Además, ¡gracias por alegrarte! Ha sido bastante agradable de usar.

Oye,

finalmente tuve tiempo de investigar esto. El problema aquí es que lib tampoco funciona con glew, parece funcionar porque se vincula con libGL y glew usa los símbolos de libGL.so , compare:

/tmp/issue151 » ldd lib.so   # built with USE_GLEW    
       linux-vdso.so.1 (0x00007fff6434d000)
        libdl.so.2 => /lib/libdl.so.2 (0x00007f3a8a97e000)
        libGLEW.so.2.1 => /lib/libGLEW.so.2.1 (0x00007f3a8a6d6000)
        libc.so.6 => /lib/libc.so.6 (0x00007f3a8a31a000)
        /usr/lib64/ld-linux-x86-64.so.2 (0x00007f3a8ad84000)
        libGL.so.1 => /lib/libGL.so.1 (0x00007f3a8a08f000)
        libX11.so.6 => /lib/libX11.so.6 (0x00007f3a89d50000)
        libGLX.so.0 => /lib/libGLX.so.0 (0x00007f3a89b1f000)
        libXext.so.6 => /lib/libXext.so.6 (0x00007f3a8990d000)
        libGLdispatch.so.0 => /lib/libGLdispatch.so.0 (0x00007f3a89657000)
        libpthread.so.0 => /lib/libpthread.so.0 (0x00007f3a89439000)
        libxcb.so.1 => /lib/libxcb.so.1 (0x00007f3a89210000)
        libXau.so.6 => /lib/libXau.so.6 (0x00007f3a8900c000)
        libXdmcp.so.6 => /lib/libXdmcp.so.6 (0x00007f3a88e06000)

y

/tmp/issue151 » ldd lib.so  # built without USE_GLEW (glad)
        linux-vdso.so.1 (0x00007ffeab9c2000)
        libdl.so.2 => /lib/libdl.so.2 (0x00007efc18716000)
        libc.so.6 => /lib/libc.so.6 (0x00007efc1835a000)
        /usr/lib64/ld-linux-x86-64.so.2 (0x00007efc18b36000)

Agregué algunos printf adicionales en sus archivos fuente:

    printf("[lib] glClearColor: %p@%p\n", glClearColor, &glClearColor);
    printf("[lib] glClear: %p@%p\n", glClear, &glClear);
    printf("[lib] glFramebufferTexture: %p@%p\n", glFramebufferTexture, &glFramebufferTexture);
#ifdef USE_GLEW
    printf("[glew] glClearColor: %p@%p\n", __glewClearColorx, &__glewClearColorx);
#endif
[glad] glClearColor: 0x7fb491c2d720<strong i="17">@0x55de31f07428</strong>
[glad] glClear: 0x7fb491c2d600<strong i="18">@0x55de31f06af0</strong>
[dlsym] glClearColor: 0x7fb4939fb720<strong i="19">@0x7fff96d92858</strong>
[dlsym] glClear: 0x7fb4939fb600<strong i="20">@0x7fff96d92850</strong>
Frame 0
[lib] glClearColor: 0x7fb4939fb720<strong i="21">@0x7fb4939fb720</strong>
[lib] glClear: 0x7fb4939fb600<strong i="22">@0x7fb4939fb600</strong>
[lib] glFramebufferTexture: (nil)<strong i="23">@0x7fb48db18050</strong>
[glew] glClearColor: (nil)<strong i="24">@0x7fb48db13db8</strong>

Como puede ver, glFramebufferTexture es nil así como el símbolo de glew interno para glClearColor . lib.c se rompería en el momento en que use cualquier cosa que no sea OpenGL 1.0.

Puede solucionar esto inicializando OpenGL (glad o glew) en su biblioteca:

void lib_init() 
{
#ifndef USE_GLEW
    gladLoadGL();
#endif
}
    // Dynamically load a function from lib.so
    void *lib_code = dlopen("./lib.so", RTLD_LAZY);
    draw_blue_screen_func *draw_blue_screen = (draw_blue_screen_func *) dlsym(lib_code, "draw_blue_screen");
    ((void(*)()) dlsym(lib_code, "lib_init"))();

No sé si puede hacer algunos trucos y obligar a la biblioteca a usar los símbolos ya cargados de su aplicación, puede funcionar si se vincula dinámicamente contra glad / glew como una biblioteca dinámica en ambos archivos ( main.c y lib.c ) pero, sinceramente, no estoy lo suficientemente familiarizado con POSIX ni con los enlaces dinámicos.

Espero haber respondido a tu pregunta.

Gracias por echarle un vistazo a esto. Después de ver una solución funcional a mi ejemplo, terminé investigando y aprendiendo mucho más sobre lo que está haciendo glad cuando llamo gladLoadGL() . Ahora tiene sentido por qué los símbolos no eran accesibles para la biblioteca de objetos compartidos.

¿Fue útil esta página
0 / 5 - 0 calificaciones

Temas relacionados

ButchDean picture ButchDean  ·  4Comentarios

MythreyaK picture MythreyaK  ·  9Comentarios

lazysquid picture lazysquid  ·  5Comentarios

NamelessPerson picture NamelessPerson  ·  3Comentarios

sasmaster picture sasmaster  ·  9Comentarios