Closed klimatr26 closed 2 months ago
I'm happy to rework this to support this scenario, I just don't know what is needed. Is it just a matter of putting that in the csproj? Because it builds for me.
Hello.
The <IlcDisableReflection>true</IlcDisableReflection>
switch is enabled by the programmer in the csproj of their program, if they want to publish with AOT and disable reflection.
I got this exception when trying to list the contents of a ZIP file from a Task:
Unhandled Exception: MT140698580042400: TypeInitialization_Type_NoTypeAvailable
---> MT140698580039448: Reflection_Disabled
at Internal.Reflection.RuntimeTypeInfo.get_Assembly() + 0x6f
at System.Text.BaseCodePageEncoding.GetEncodingDataStream(String) + 0x1d
at System.Text.BaseCodePageEncoding..cctor() + 0x5d
at System.Runtime.CompilerServices.ClassConstructorRunner.EnsureClassConstructorRun(StaticClassConstructionContext*) + 0xb9
Exception_EndOfInnerExceptionStack
at System.Runtime.CompilerServices.ClassConstructorRunner.EnsureClassConstructorRun(StaticClassConstructionContext*) + 0x14b
at System.Runtime.CompilerServices.ClassConstructorRunner.CheckStaticClassConstructionReturnGCStaticBase(StaticClassConstructionContext*, Object) + 0xd
at System.Text.BaseCodePageEncoding.GetCodePageByteSize(Int32) + 0x120
at System.Text.CodePagesEncodingProvider.GetEncoding(Int32) + 0x8b
at System.Text.CodePagesEncodingProvider.GetEncoding(Int32) + 0x1ed
at System.Text.EncodingProvider.GetEncodingFromProvider(Int32) + 0x32
at System.Text.Encoding.GetEncoding(Int32) + 0x11
at System.Text.EncodingHelper.GetSupportedConsoleEncoding(Int32) + 0xf
at System.Console.get_OutputEncoding() + 0x64
at System.ConsolePal.OpenStandardOutput() + 0x9
at System.Console.<get_Out>g__EnsureInitialized|26_0() + 0x37
at System.Console.WriteLine(String) + 0xd
at MyProgram.Program.<Main>d__0.MoveNext() + 0x4e5
--- End of stack trace from previous location ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + 0x20
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task) + 0x62
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task, ConfigureAwaitOptions) + 0x4b
at MyProgram.Program.<Main>(String[]) + 0x29
at MyProgram!<BaseAddress>+0x1af5f0
Does this mean the problem actually exists in System.Text?
Also, the code for listing the contents of the ZIP file is inside a try-catch block, so... ???????. BUT ALSO, the program was working without Reflection until I added SharpCompress, and the rest of the program still works correctly without Reflection (except for the ZIP listing part).
However, I don't understand why a similar program that creates 2 zip archives (one Deflate and one LZMA), lists the contents of one of them, and extracts one of them, works correctly with Reflection disabled.
I'm not sure if it is related to being run from a Task, because I remember that I got a similar Exception when I tried to list and extract the contents of a 7-zip archive -which cannot be opened in Windows 11 (maybe they forgot to enable LZMA in libarchive?)- which normally can be extracted fine by SharpCompress.
UPDATE: I tried the previously problematic code for extracting the 7z archive, and it worked fine without Reflection.
At this point, I'm REALLY confused. Maybe this isn't related to SharpCompress? It is weird that it only happens in (async) code that calls SharpCompress. I saw that you already replaced Activator calls with delegates.
Unrelated: Does SharpCompress load the entire solid 7z block to memory? Memory usage increases beyond the sliding window when I extract solid entries. 7zdec from the LZMA SDK also does this. Also unrelated: SharpCompress marks the minimum version for extracting LZMA entries of a ZIP file as 20 instead of 63. The Writer code doesn't seem to have any checks for this.
Have a good day.
there's a lot to unpack here
there could be a reference leak with 7z/LZMA but don't know, haven't tested. I don't load everything into memory other than that the file has to be random access.
LZMA minimum version is also something I haven't looked into
Hello.
I did more testing, and I have some code.
The following code throws an Unhandled Exception even inside a try-catch:
using SharpCompress.Archives.Zip;
namespace AsyncList
{
internal class Program
{
//static async Task Main(string[] args)
static void Main(string[] args)
{
if (args.Length == 0)
{
Console.WriteLine("Provide a file to list its contents.");
}
else
{
try
{
//Console.WriteLine("Try to create Reader");
var reader = new Reader(args[0]);
//string result = await reader.Read();
//string result = await Task.Run(() => reader.Read());
//Console.WriteLine("Try to read contents");
string result = reader.Read();
if (result.Length != 0)
{
Console.WriteLine(result);
Environment.Exit(1);
}
//var files = await Task.Run(() => reader.List());
//Console.WriteLine("Try to create list of contents");
string[] files = reader.List();
//Console.WriteLine("Try to list contents to console");
foreach (var file in files)
{
Console.WriteLine(file);
}
}
catch (Exception ex) //Still throws an Unhandled Exception
{
Console.WriteLine(ex.ToString());
}
}
}
}
internal class Reader(string filePath)
{
public string FilePath { get; } = filePath;
//public string Read(CancellationToken? cancellationToken = null, IProgress<string>? fileNameProgress = null, IProgress<int>? progress = null)
public string Read()
{
string result = string.Empty;
try
{
using var archive = ZipArchive.Open(FilePath);
}
catch (Exception e)
{
result = e.Message;
}
return result;
}
public string[] List()
{
string[] result = Array.Empty<string>();
try
{
using (var archive = ZipArchive.Open(FilePath))
{
int noOfEntries = archive.Entries.Count;
result = new string[noOfEntries];
var i = 0;
foreach (var entry in archive.Entries)
{
result[i] = entry.Key;
i++;
}
}
}
catch { }
return result;
}
}
}
However, simply removing the //
from Console.WriteLine("Try to create Reader");
seems to solve the issue. (Maybe should close the issue? I still don't understand why this happens specifically with SharpCompress) The program then behaves normally.
This is REALLY weird to me, and I don't think SharpCompress is the problem here.
My csproj contains
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<PublishAot>true</PublishAot>
<InvariantGlobalization>true</InvariantGlobalization>
<IlcDisableReflection>true</IlcDisableReflection>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="SharpCompress" Version="0.36.0" />
</ItemGroup>
</Project>
Sorry to bother you with this.
Have a good day.
Hello.
I have been trying to include sharpcompress in a NativeAOT application. It normally works fine.
However, when I disable Reflection via
<IlcDisableReflection>true</IlcDisableReflection>
, some parts stop working and throw and exception related to Reflection being disabled.I used the "ZipArchive with Writing API Example" from the wiki for one program with Reflection disabled and it seemed to work fine. However, using other code like the "Reader (forward-only streams) API Example" example throws an exception when Reflection is disabled (but works fine when Reflection is enabled in NativeAOT).
I know this only affects a very small number of users, since JIT always should support Reflection, and NativeAOT supports enough Reflection features to use sharpcompress without issue. However, disabling Reflection reduces the size of the resulting executable significantly, and that's why I was trying to use that mode.
Have a good day.