2009-11-30 7 views
7

Tengo una aplicación multiplataforma de C++ que se divide en varias bibliotecas compartidas y carga funcionalidades adicionales de las bibliotecas compartidas de los complementos. Se supone que las bibliotecas de complementos son autónomas y funcionan por sí mismas, sin conocimiento o dependencia de la aplicación de llamada.Segfault en la biblioteca de complementos de C++ con símbolos duplicados

Uno de los complementos contiene código copiado de la aplicación principal, por lo que contiene nombres de símbolos que están duplicados en el motor. (Sí, sé que generalmente es un no-no, pero en el momento en que se escribió el complemento el motor era un binario monolítico y no podía compartir bibliotecas.) En Windows, todo funciona bien. En Linux obtuvimos segfaults. Al observar el rastro de pila del error, estaba ocurriendo en el complemento al llamar funciones en el nombre de clase duplicado. Parecía ser un resultado de que el motor y el complemento tenían versiones ligeramente diferentes del código compartido (algunas funcionalidades de clase se comentaron en el complemento). Era como si el plugin obtuviera su tiempo de ejecución de símbolos vinculado al motor en lugar del propio. "Solucionamos" el problema cambiando los parámetros dlopen para que sean dlopen(pFilepath, RTLD_LAZY | RTLD_LOCAL).

Pero cuando reescribimos el motor para dividirlo en bibliotecas compartidas (para el propósito final de la reutilización en los complementos), obtenemos el error segfault nuevamente. Y mirando el rastro de la pila, va desde el motor -> plugin -> motor.

¿Hay alguna manera de especificar que el enlazador de tiempo de ejecución no asigne símbolos del complemento al motor (especialmente si están definidos en el complemento)?

Gracias! Matt


Editado 2009-12-3

primera vez que trató de envolver el código del plug-in en su propio espacio de nombres. Eso no funcionó porque está vinculado estáticamente a una biblioteca que también está vinculada al motor. Las versiones de la biblioteca estática son diferentes, ¡así que segfault!

Luego modifiqué la construcción del motor y sus bibliotecas para que estuvieran vinculadas estáticamente. Y cuando lo ejecuto, ya no tengo el problema. Por lo tanto, parece que fue el resultado de exportar los símbolos de la biblioteca compartida y luego reubicarlos dinámicamente en el complemento cuando se abrió. Pero cuando todo el código del motor está en un único ejecutable, no exporta sus símbolos (por lo que no intenta reubicar los símbolos del complemento en el motor).

Todavía tengo un problema, ya que hay una versión paralela del programa (usando Open-MPI) y que aún recibe la segfault. Parece que sigue exportando los símbolos del motor y reubicando el plugin. Eso podría tener que ver con cómo Open-MPI ejecuta la aplicación.

¿Hay indicadores de enlazador que se podrían utilizar en la biblioteca compartida del complemento que indicaría que no se reubiquen dinámicamente los símbolos en el tiempo de ejecución? ¿O esconder sus símbolos para que no se reubiquen? Intenté -s ("Omitir toda la información del símbolo") pero aparentemente no cambió los símbolos dinámicos (verificados usando nm -D <plugin>).

+0

¿Son estos símbolos globales o nombres de funciones? ¿Puedes hacer pequeños cambios al código? –

+0

Son clases y sus funciones miembro. Hay 36 archivos utilizados desde la base de código del motor, por lo que no quiero modificar el nombre o archivo de cada clase. Si bien el objetivo final es volver a escribir el complemento, debido a las limitaciones de tiempo y la validación del código, no quiero hacerlo si no es necesario. – CuppM

+0

@CuppM, entonces, por ejemplo, ¿tienes una clase "Foo" con una "barra" miembro definida en 2 lugares? Y "Foo" está en el mismo espacio de nombres en ambos casos? Si es así, esto nunca funcionará correctamente para usted. Mueve uno de los "Foo" a su propio espacio de nombres y la vida será más fácil. – Glen

Respuesta

4

Creo que he encontrado la solución, la bandera del enlazador -Bsymbolic. Básicamente, este indicador agrega un indicador en la biblioteca compartida para indicarle al vinculador de tiempo de ejecución que primero intente resolver los nombres de símbolos dentro de sí mismo. El motor fue capaz de ejecutarse con el plugin muy bien en todos los casos (monolithic exe, exe w/shared libs, plugin w/w/o envolviendo el espacio de nombre) cuando el plugin estaba vinculado con ese flag.

Hay que parecen ser algunos detractores con advertencias sobre -Bsymbolic:
http://www.technovelty.org/code/c/bsymbolic.html
http://software.intel.com/en-us/articles/performance-tools-for-software-developers-bsymbolic-can-cause-dangerous-side-effects/

Pero teniendo en cuenta sus advertencias y cuál es la intención del plugin es, creo que es la opción correcta para mí. Por ahora.

1

Estoy de acuerdo con Glen: no vas a resolver realmente esto a menos que modifiques los nombres de clase, posiblemente a través de espacios de nombres. Incluso los 36 archivos probablemente demorarán menos tiempo en modificarse que tratar de arreglarlo de manera confiable sin cambiar los nombres de los símbolos.

Comience identificando todas las clases cuyos nombres deban retocarse. Su enlazador probablemente ya los enumere por usted. Luego cambiaría los nombres de tanto conjuntos de clases (desde Foo a Engine :: Foo y Plugin :: Foo por ejemplo) al menos temporalmente.De esta forma, puede hacer que el compilador encuentre todas las referencias a las clases problemáticas. Alejándose de la fuente del complemento hasta que el complemento se compile con referencias a los nuevos nombres correctos de clase de complemento. Una vez hecho esto, cambie las clases de Engine :: a sus nombres anteriores (a menos que también desee modificar permanentemente la fuente del motor, lo que parece que no es). El complemento ahora debe compilar y vincular a las clases correctas y con nombre único.

+0

Si bien es probable que tenga razón acerca de esto. Sin embargo, no es una respuesta satisfactoria, así que voy a dejar la pregunta sin responder un poco por si acaso. Voy a modificar el código del complemento para agregar un espacio de nombres a los bits ofensivos. Hasta que no pueda volver a escribir usando las bibliotecas compartidas del motor, ya que cambié todo el código en el motor, no debería importar si modifico la copia. – CuppM

0

Simplemente envolvería TODO el código del complemento con un espacio de nombres PluginX. Eso seguramente te salvará de estos errores. Es una práctica muy buena e importante de todos modos.

Cuestiones relacionadas