CODE Polyglot / 備忘録

dotnet run でファイル1つの C# を動かすと、コンテナでは最初の1回だけ NuGet の警告が標準出力に混ざる

新しいコンテナで `dotnet run hello.cs` を動かすと、最初の1回だけ「warning NU1903」の行が標準出力に混ざり、出力を比べるテストが落ちる。先に `dotnet build` を動かして復元を済ませておくと、`dotnet run` の標準出力はプログラムの出力だけになる。

起きたこと

10言語のプログラムに同じ入力を渡し、標準出力を正解と比べる検証を、毎回まっさらなコンテナで動かしている。C# は .NET 10 の「ファイル1つをそのまま dotnet run で動かす」書き方にしていた。

コンテナで動かすと、C# だけ、どの回でも1件目のケースだけが落ちた。2件目からは通る。標準出力の先頭に、プログラムの出力ではない警告の行が付いていた。

再現の手順

// hello.cs
Console.WriteLine("hello");

新しいコンテナで2回続けて動かし、標準エラーは捨てて、標準出力だけを見る。

$ docker run --rm -v $PWD:/w -w /w <.NET SDK 10 の入ったイメージ> bash -c 'dotnet --version; echo "== 1回目(標準出力だけ)"; dotnet run hello.cs 2>/dev/null; echo "exit=$?"; echo "== 2回目"; dotnet run hello.cs 2>/dev/null; echo "exit=$?"'
10.0.402
== 1回目(標準出力だけ)
/w/hello.cs.csproj : warning NU1903: Package 'Microsoft.DotNet.ILCompiler' 10.0.13 has a known high severity vulnerability, https://github.com/advisories/GHSA-p3jp-9v83-76w9
/w/hello.cs.csproj : warning NU1903: Package 'Microsoft.DotNet.ILCompiler' 10.0.13 has a known high severity vulnerability, https://github.com/advisories/GHSA-p3jp-9v83-76w9
hello
exit=0
== 2回目
hello
exit=0

終了コードは 0 なので、終了コードだけを見ていると気づかない。

原因

dotnet run は、最初の1回にパッケージの復元(restore)をする。そのときの警告(NU1903 は、使うパッケージに既知の脆弱性があるという警告)を、標準エラーではなく標準出力に書く。2回目からは復元が済んでいるので出ない。

毎回まっさらなコンテナで動かすと、どの回でも「最初の1回」が来るので、毎回1件目だけが落ちる。

直し方

プログラムを動かす前に dotnet build を1回動かして、復元を済ませておく。build の出力は捨てる。

$ docker run --rm -v $PWD:/w -w /w <同じイメージ> bash -c 'echo "== build(標準出力は捨てる)"; dotnet build hello.cs --nologo -v q >/dev/null 2>&1; echo "exit=$?"; echo "== run の標準出力"; dotnet run hello.cs 2>/dev/null; echo "exit=$?"'
== build(標準出力は捨てる)
exit=0
== run の標準出力
hello
exit=0

警告そのもの(NU1903)を黙らせる設定もあるが、脆弱性の知らせを消すことになるので、ここでは使わなかった。

確かめたこと

  • Docker の Debian 13(arm64)・.NET SDK 10.0.402 で、上の出力のとおり。新しいコンテナでは毎回、1回目だけ警告が出た
  • 同じ版の SDK の Mac(macOS 26.6.2・arm64)では、新しいファイルでも警告は出なかった。Mac にも同じ版(10.0.13)のパッケージが入っていたが、出ない理由は確かめていない。Mac だけで試していると気づかない
  • 検証の C# を「build してから run」に変えて、コンテナで入門17回を動かし直した。C# は158件中158件が正解と一致した(ほかの9言語も全件一致)