Introduction

結果としては、多分、この記事は間違っている可能性が高いが、忘れないようにメモ。

事の経緯は、.NET Core 3.1 でビルドしたアプリが Ubuntu 16 上で動かなかったことから。
実行時に、依存関係が足りないと言われるも、ldd で問題のライブラリの依存関係に問題は無かった。

そこでピンと来たのが、以前、開発メモ その190 .NET CoreでP/Invokeでの動的リンクに失敗したためLD_DEBUGで原因を調べてみる で書いたように、ライブラリが足りないのではなく、シンボルが読めないのでは?と思い下記で調べてみた。

1
$ LD_DEBUG=libs dotnet test -c Release 2> error.log

するとたくさん出るエラー。

1
2
3
4
5
6
7
8
9
10
...
1367: /lib/x86_64-linux-gnu/libssl.so.1.0.0: error: symbol lookup error: undefined symbol: BIO_up_ref (fatal)
1367: /lib/x86_64-linux-gnu/libssl.so.1.0.0: error: symbol lookup error: undefined symbol: DSA_get0_key (fatal)
1367: /lib/x86_64-linux-gnu/libssl.so.1.0.0: error: symbol lookup error: undefined symbol: DSA_get0_pqg (fatal)
1367: /lib/x86_64-linux-gnu/libssl.so.1.0.0: error: symbol lookup error: undefined symbol: DSA_get_method (fatal)
1367: /lib/x86_64-linux-gnu/libssl.so.1.0.0: error: symbol lookup error: undefined symbol: DSA_set0_key (fatal)
1367: /lib/x86_64-linux-gnu/libssl.so.1.0.0: error: symbol lookup error: undefined symbol: DSA_set0_pqg (fatal)
1367: /lib/x86_64-linux-gnu/libssl.so.1.0.0: error: symbol lookup error: undefined symbol: EVP_CIPHER_CTX_reset (fatal)
1367: /lib/x86_64-linux-gnu/libssl.so.1.0.0: error: symbol lookup error: undefined symbol: EVP_PKEY_up_ref (fatal)
...

確かに、nm -D /lib/x86_64-linux-gnu/libssl.so.1.0.0 | grep BIO_up_ref ってしても、問題のシンボルが見つからない。

でも、サポートされているディストリビューション のページでは Ubuntu 16.04 において、3.1 はサポート対象であると明記されている。

Why?

答えは下記にあった。

.NET Core 3.0 では、OpenSSL 1.0.x よりも OpenSSL 1.1.x が優先されます
Linux 用 .NET Core では、複数の Linux ディストリビューションで動作するため、OpenSSL 1.0.x と OpenSSL 1.1.x の両方がサポートされます。 .NET Core 2.1 および .NET Core 2.2 では、最初に 1.0.x が検索されてから、1.1.x にフォールバックされます。 .NET Core 3.0 では、最初に 1.1.x が検索されます。 この変更は、新しい暗号化標準のサポートを追加するために行われました。

うん、つまり
libssl 1.0.X がデフォルトの Ubuntu 16 では、どうにもならないってことです。
手動で Libssl 1.1.X を自分でビルドしてインストールすればいいんだろうけど。

でも、暗号系のAPI何か読んでいないのに、どうしてこんなエラーになったのかは疑問に残る。
予想だが、ビルドしたアプリが依存していたC++のライブラリ (ここではprotobuf) が OpenSSL を動的リンクしていて、そいつが .NET Core の依存する libssl の一致しなかったのでは、と考える。

However…

と思ったら、このエラーは関係ない可能性が高い。
というのも、 Ubuntu 20 における、 .NET Core 5.0 ではあるが、空のコンソールアプリケーションを作っても、似たようなシンボルが見つからないエラーが表示される。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ dotnet new console
$ dotnet run -c Relese -r linux-x64 2> error.log

...
4603: find library=liblttng-ust-tracepoint.so.0 [0]; searching
4603: search cache=/etc/ld.so.cache
4603: search path=/lib/x86_64-linux-gnu:/usr/lib/x86_64-linux-gnu:/lib:/usr/lib (system search path)
4603: trying file=/lib/x86_64-linux-gnu/liblttng-ust-tracepoint.so.0
4603: trying file=/usr/lib/x86_64-linux-gnu/liblttng-ust-tracepoint.so.0
4603: trying file=/lib/liblttng-ust-tracepoint.so.0
4603: trying file=/usr/lib/liblttng-ust-tracepoint.so.0
4603:
4603: dotnet: error: symbol lookup error: undefined symbol: DllMain (fatal)
4603: /usr/share/dotnet/shared/Microsoft.NETCore.App/5.0.8/libcoreclr.so: error: symbol lookup error: undefined symbol: PAL_RegisterModule (fatal)
4603:
4603: calling init: /usr/share/dotnet/shared/Microsoft.NET

libssl や libicuuc でも同様のエラーが出ている事を見ると、エラーが出てもフォールバックで何事もなかったかのように処理をしている模様。

で、調査中だが、問題はC#からP/Invokeで呼出しているC++ライブラリがマズい可能性が高い。
自作のC++ライブラリを念のため別のC++から呼出す実行プログラムからリンクさせると、これがリンクの段階で動かない。

1
2
3
4
/usr/bin/ld: XXXXX: hidden symbol `__cpu_indicator_init' in /usr/lib/gcc/x86_64-linux-gnu/5/libgcc.a(cpuinfo.o) is referenced by DSO
/usr/bin/ld: final link failed: Bad value
collect2: error: ld returned 1 exit status
CMakeFiles/XXXXX.dir/build.make:95: recipe for target 'XXXXX' failed

このC++ライブラリの少し古いバージョンは問題なくリンクできて実行できた。
なので、差分を見ていって、問題を解決する。