Eu tenho um programa simples chamado main
:
#include <iostream>
#include "random.h"
int main()
{
std::cout << "The program has started\n";
return get_another_random_number();
}
A get_another_random_number()
função está em uma nova versão de uma biblioteca compartilhada, mas apenas a versão antiga está instalada. O programa começa a ser executado, mas falha posteriormente quando a pesquisa falha; por exemplo
$ ./main
The program has started
./main: symbol lookup error: ./main: undefined symbol: _Z25get_another_random_numberv
Isso acontecerá se, por exemplo, librandom.so.1.3.1
contiver uma função chamada get_another_random_number()
, mas main
for executada em um servidor que tenha apenas librandom.so.1.2.5
instalado. Essas bibliotecas diferem apenas em sua versão secundária porque a 1.3
versão é compatível com a 1.2
versão da biblioteca, mas 1.2
não possui a função extra.
No meu próprio exemplo, se eu executar readelf -d main | grep NEEDED
, recebo:
0x0000000000000001 (NEEDED) Shared library: [librandom.so.1]
0x0000000000000001 (NEEDED) Shared library: [libstdc++.so.6]
0x0000000000000001 (NEEDED) Shared library: [libm.so.6]
0x0000000000000001 (NEEDED) Shared library: [libgcc_s.so.1]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
Portanto, tudo está vinculado apenas aos números da versão principal.
Para minha biblioteca compartilhada, coloquei /usr/lib/
e adicionei os links simbólicos:
lrwxrwxrwx 1 root root 23 Feb 7 14:25 /usr/lib/librandom.so -> /usr/lib/librandom.so.1
lrwxrwxrwx 1 root root 27 Feb 7 14:13 /usr/lib/librandom.so.1 -> /usr/lib/librandom.so.1.2.5
-rw-r--r-- 1 root root 7696 Feb 7 14:00 /usr/lib/librandom.so.1.2.5
Entre o mantenedor da biblioteca, desenvolvedor do aplicativo e administrador do sistema; quem assume a responsabilidade de evitar a falha desse programa?
- É durante a instalação
main
que um erro deve ser produzido informando que a versão secundária da biblioteca atualmente instalada é muito baixa? - O programa deve chamar uma função especial na biblioteca para identificar a versão e verificar se a versão secundária é suficiente?
- O carregador de biblioteca deve verificar todos os símbolos antes de o programa iniciar a execução?
- Eu entendi mal a numeração da versão ou perdi uma configuração para verificar a versão secundária?
Você não entendeu mal a numeração de versão, e esta é realmente uma área em que a pesquisa de símbolos geralmente falha.
Quanto a quem é a responsabilidade, eu diria que em sistemas modernos ela pertence a quem cria o aplicativo, não à biblioteca: se você vincular o aplicativo
ld -z now
(pelo menos no GNU binutils), o vinculador dinâmico resolverá todos os símbolos na inicialização e falha antecipadamente se algum símbolo estiver faltando (para que você não precise adicionar suas próprias verificações manuais). Você pode ativar esse comportamento depois que um programa é vinculado exportandoLD_BIND_NOW=1
para o ambiente (qualquer valor não vazio funciona e isso não é específico do Linux).Esse tipo de problema é normalmente tratado por sistemas de gerenciamento de pacotes: eles mantêm metadados extensivos que descrevem requisitos de versão para símbolos e geram as dependências com versão apropriadas. Também é possível que os autores da biblioteca ajudem a melhorar a situação, mas isso pode exigir muito esforço; veja os símbolos de versão especial da GNU libc (os
GLIBC_...
símbolos que geralmente aparecem em mensagens de erro) e o tratamento geral completo de símbolos com versão.