.NET 10 single-file publishing silently produces empty executables above 2 GiB due to integer overflow in BinaryUtils.WriteToStream
I maintainer di solito rispondono entro 1 giorno
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 2/5
- Tempo stimato
- 1-3 ore
- Idoneità per principianti
- 68/100
- Tipo di issue
- Bug
- Chiarezza
- Specificata chiaramente
- Stato di attività
- Attiva
- Stack tecnologico
- csharp
- Ambito
- build-system
Direzione di ricerca
Il bug si trova in WriteToStream in src/installer/managed/Microsoft.NET.HostModel/AppHost/BinaryUtils.cs, dove la lunghezza long viene ridotta a int prima del calcolo della dimensione del blocco. Inizia da lì e verifica come sono tipizzati pos e bytesRequested. Esegui il repro con reflection dell'issue, che dovrebbe stampare firstWrite=16384 per il caso 2 GiB+1 una volta corretto. È completato quando quel caso raggiunge la prima scrittura sulla destinazione e un unit test copre lunghezze superiori a Int32.MaxValue.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
Description
Publishing a single-file executable larger than 2 GiB can produce a 0-byte executable while reporting success.
The issue appears to be a narrowing conversion in BinaryUtils.WriteToStream:
https://github.com/dotnet/runtime/blob/6aa72daa24f66c01c3d7b6a32519e9d21396deec/src/installer/managed/Microsoft.NET.HostModel/AppHost/BinaryUtils.cs#L186
For lengths between 2 GiB and 4 GiB, converting length to int produces a negative value. On the first iteration, bytesRequested <= 0, so the method returns without writing anything or throwing an exception.
The .NET 10 bundler creates/truncates the output file immediately before calling this method, leaving an empty executable. dotnet publish nevertheless exits successfully.
Reproduction Steps
Use .NET SDK 10.0.403 with a 64-bit process.
The following dependency-free console application invokes the actual internal SDK method through reflection. It does not substitute or patch the implementation.
To avoid generating a multi-gigabyte installer, it uses a large virtual mapping and stops at the first destination write. It only needs to read one chunk, and no large output file is created.
- Create Repro.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<None Include="$(NetCoreRoot)sdk\$(NETCoreSdkVersion)\Microsoft.NET.HostModel.dll"
Link="Microsoft.NET.HostModel.dll"
CopyToOutputDirectory="Always" />
</ItemGroup>
</Project>
- Create Program.cs
using System.IO.MemoryMappedFiles;
using System.Reflection;
var assembly = Assembly.LoadFrom(
Path.Combine(AppContext.BaseDirectory, "Microsoft.NET.HostModel.dll"));
var method = assembly
.GetType("Microsoft.NET.HostModel.AppHost.BinaryUtils", throwOnError: true)
.GetMethod("WriteToStream", BindingFlags.Static | BindingFlags.NonPublic);
var copy = method.CreateDelegate<
Action<MemoryMappedViewAccessor, FileStream, long>>();
bool failed = false;
foreach (long length in new[] { 16384L, 2147483649L })
{
using var map = MemoryMappedFile.CreateNew(null, length);
using var source = map.CreateViewAccessor();
using var destination = new FirstWriteStream();
try
{
copy(source, destination, length);
}
catch (CopyStartedException)
{
// Stop after the first chunk; no multi-gigabyte output file is needed.
}
Console.WriteLine(
$"length={length}, firstWrite={destination.BytesWritten}");
failed |= destination.BytesWritten == 0;
}
return failed ? 1 : 0;
sealed class FirstWriteStream : FileStream
{
public int BytesWritten { get; private set; }
public FirstWriteStream()
: base(Path.GetTempFileName(), FileMode.Open,
FileAccess.Write, FileShare.None, 1, FileOptions.DeleteOnClose)
{
}
public override void Write(byte[] buffer, int offset, int count)
=> Stop(count);
public override void Write(ReadOnlySpan<byte> buffer)
=> Stop(buffer.Length);
private void Stop(int count)
{
BytesWritten = count;
throw new CopyStartedException();
}
}
sealed class CopyStartedException : Exception
{
}
- run
dotnet run --configuration Release
Expected behavior
WriteToStream should handle valid lengths and positions larger than Int32.MaxValue without truncation.
Both reproduction cases should reach the first destination write. With the current 16 KiB buffer size, the output would be:
length=16384, firstWrite=16384
length=2147483649, firstWrite=16384
Actual behavior
The verified reproduction prints:
length=16384, firstWrite=16384
length=2147483649, firstWrite=0
The reproduction itself exits with code 1 to flag that failure. In contrast, the affected dotnet publish command exits with code 0.
Regression?
This appears to be a publishing-path regression that exposes a pre-existing helper bug.
The narrowing conversion already exists in the .NET 9 helper. However:
- The .NET 9 bundler writes the bundle directly to the output file.
- The .NET 10 bundler writes the completed memory-mapped bundle through BinaryUtils.WriteToStream.
Verified with SDK 10.0.403.
Known Workarounds
The relevant implementation is in the function:
https://github.com/dotnet/runtime/blob/6aa72daa24f66c01c3d7b6a32519e9d21396deec/src/installer/managed/Microsoft.NET.HostModel/AppHost/BinaryUtils.cs#L177
pos must be long, as length is long:
https://github.com/dotnet/runtime/blob/6aa72daa24f66c01c3d7b6a32519e9d21396deec/src/installer/managed/Microsoft.NET.HostModel/AppHost/BinaryUtils.cs#L179
-int pos = 0;
+long pos = 0;
Cast to int without overflow:
https://github.com/dotnet/runtime/blob/6aa72daa24f66c01c3d7b6a32519e9d21396deec/src/installer/managed/Microsoft.NET.HostModel/AppHost/BinaryUtils.cs#L186
- int bytesRequested = Math.Min((int)length - pos, bufSize);
+ int bytesRequested = (int)Math.Min(length - pos, (long)bufSize);
This narrows only the bounded chunk size, rather than the total length.
Configuration
No response
Other information
No response
- Lingua principale
- C#
- Stelle
- 18.4k
- Fork
- 5.8k
- Merge medio
- 2g 14h
- PR unite (30g)
- 585
Preparare l'ambiente
Avvia il container di sviluppo del progetto nel browser, con il tuo account GitHub.
- Nessun Dockerfile né file Docker Compose
- Ha un modello di pull request
- Leggi la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di dotnet/runtime
-
ImmutableSortedSet<T>.Builder: enumerating through IEnumerable<T> doesn't throw on modification and can return wrong itemsForse già presa @aw0lid l’ha presa oggi. Apertaarea-System.Collections
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
dotnet/runtime#137167 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
DbTransaction.SupportsSavepoints docs say Release/ReleaseAsync are expected to throw, but they are no-ops by designForse già presa @alaricd l’ha presa 4 giorni fa. Apertaarea-System.Transactions untriaged
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
dotnet/runtime#137040 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
FileSystemGlobbing: Matcher throws ArgumentOutOfRangeException when the rootDir is the same value as the fileForse già presa @makazeu l’ha presa 4 giorni fa. Apertaarea-Extensions-FileSystem
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
dotnet/runtime#136989 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
Configuration binder source generator emits unqualified List<T> when binding arrays without implicit usingsForse già presa @makazeu l’ha presa 4 giorni fa. Apertaarea-Extensions-Configuration bug source-generator
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
dotnet/runtime#136972 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
[wasi] .NET 10: WasmEnableSIMD with AOT fails because WasiApp.targets has -msimd128 commented outApertaarea-Build-mono untriaged
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
I maintainer di solito rispondono entro 1 giorno
Tutte le issue di dotnet/runtime
Issue simili
-
area/access-management Frontend onboarding candidate :handshake:
Difficoltà 2/5 1-3 ore Idoneità per principianti 65/100
Altinn/altinn-auth#4941 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
aws/aws-sdk-net#4586 ·
I maintainer di solito rispondono entro 1 giorno
-
30-minutes algorithm any-language beginner-friendly c community cpp csharp data-structures go good first issue hacktoberfest help wanted kotlin learning leetcode php ruby rust swift
Difficoltà 2/5 Meno di un'ora Idoneità per principianti 85/100
Huerte/algo-solutions-python#211 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
QuantConnect/Lean#10047 ·
I maintainer di solito rispondono entro 1 giorno
-
[Bug]: Windows Native Setup Fails on "Finishing setup" Due to 10s Gateway Health Check TimeoutApertabug bug:behavior impact:ux-release-blocker P0
Difficoltà 2/5 1-3 ore Idoneità per principianti 68/100
openclaw/openclaw#196251 · 2 commenti · 1 reazione ·
I maintainer di solito rispondono entro 1 giorno