9

que tienen la siguiente estructura:Fallo de segmentación al acceder a una estructura-función estática a través de puntero devuelto

struct sys_config_s 
{ 
    char server_addr[256]; 
    char listen_port[100]; 
    char server_port[100]; 
    char logfile[PATH_MAX]; 
    char pidfile[PATH_MAX]; 
    char libfile[PATH_MAX]; 
    int debug_flag; 
    unsigned long connect_delay; 
}; 
typedef struct sys_config_s sys_config_t; 

También he una función definida en una biblioteca estática (vamos a llamarlo A.lib):

sys_config_t* sys_get_config(void) 
{ 
    static sys_config_t config; 
    return &config; 
} 

Tengo un programa (llamémoslo B) y una biblioteca dinámica (llamémoslo C). Tanto B como C se vinculan con A.lib. En el tiempo de ejecución B abre C a través de dlopen() y luego obtiene una dirección para la función C func() a través de una llamada al dlsym().

void func(void) 
{ 
    sys_get_config()->connect_delay = 1000; 
} 

El código anterior es el cuerpo de la función de C func() y produce un fallo de segmentación cuando alcanzado. La segfault solo se produce cuando se ejecuta fuera de gdb.

¿Por qué sucede eso?

EDITAR: Hacer sys_config_t config una variable global no ayuda.

Respuesta

1

La solución es trivial. De alguna manera, por un desajuste del encabezado, la constante PATH_MAX se definió de manera diferente en las unidades de compilación de B y C. Necesito ser más cuidadoso en el futuro. (facepalms)

0

No hay diferencia entre que la variable sea estática-local o una variable estática-global. Una variable estática es ESTÁTICA, es decir, no es, en función de demanda de llamada, asignada en la pila dentro del cuadro de función actual, sino que se asigna en uno de los segmentos preexistentes de la memoria definida en los encabezados binarios del ejecutable.

Eso es lo que estoy 100% seguro. La pregunta, en qué segmento exactamente se colocaron, y si se comparten adecuadamente, es otro problema. He visto problemas similares al compartir variables globales/estáticas entre módulos, pero por lo general, el núcleo del problema era muy específico para la configuración exacta.

Tenga en cuenta que la muestra del código es pequeña, y trabajó en esas plataformas hace mucho tiempo. ¡Lo que he escrito arriba podría tener errores de redacción o incluso ser claramente incorrecto en algunos puntos!

Creo que lo importante es que está obteniendo esa segfault en C al tocar esa línea. Establecer un campo entero en una constante no podría haber fallado, nunca, siempre que la dirección de destino sea válida y no esté protegida contra escritura. Eso deja dos opciones: - tu función sys_get_config() se ha bloqueado - o ha devuelto un puntero no válido.

Como dices que la segfault se plantea aquí, no en sys_get_config, lo único que queda es el último punto: puntero roto.

Agregue al sys_get_config un printf trivial que volcará la dirección que se va a devolver, luego haga lo mismo en la función de llamada "func". Verifique si no es nulo, y también verifique si dentro de sys_get_config es lo mismo que después de ser devuelto, solo para asegurarse de que las convenciones de llamadas sean adecuadas, etc. Una buena idea para hacer una verificación doble/triple es también agregar dentro del módulo "A" una copia de la función sys_get_config (con diferente nombre de curso), y para comprobar si las direcciones devueltas desde sys_get_config y su copia son las mismas. Si no lo son, algo salió muy mal durante el enlace

También hay una posibilidad muy pequeña de que la carga del módulo haya sido diferida, y usted está tratando de hacer referencia a una memoria de un módulo que aún no se inicializó por completo. Trabajé en Linux hace mucho tiempo, pero recuerdo que dlopen tiene varias opciones de carga. Pero usted escribió que recibió la dirección por dlsym, así que supongo que el módulo se cargó porque tiene la dirección final del símbolo.

Cuestiones relacionadas