runtime: [NativeAOT] Could not load ICU data. UErrorCode: 2 Abortado
Description
I’m getting this error when running a server application that uses the dynamic library I created with C# .NET NativeAOT after I upgraded to Debian 11
Could not load ICU data. UErrorCode: 2
Abortado
Reproduction Steps
shared library code
using FellowOakDicom;
using FellowOakDicom.Imaging;
using Renci.SshNet;
using SixLabors.ImageSharp.Formats.Bmp;
using SixLabors.ImageSharp.Formats.Jpeg;
using SMBLibrary;
using SMBLibrary.Client;
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
namespace dicom_lib;
public enum ErrorCode : int
{
Success = 0,
Unknown = -1,
ConnectionLost = 400,
ServerLoginFailure = 401,
FailedAccessServer = 402,
FailedAccessShare = 403,
FailedAccessFile = 404,
InvalidInstance = 405,
UninitializedFileStore = 406
}
static class ErrorCodeExtensions
{
public static int AsInt(this ErrorCode v)
{
return (int)v;
}
}
public struct SmbInstanceNative
{
public int smbInstanceId;
public int errorCode;
}
public struct FileBytesNative
{
public IntPtr bytes;
public int length;
public int errorCode;
}
public class SmbInstance
{
public SMB2Client client;
public SMB2FileStore fileStore;
public int id;
}
public class DicomLib
{
private static int countSmbInstance = -1;
private static List<SmbInstance> smbInstances = new();
private static string erroMessage = "";
private static SmbInstance GetSmb(int id)
{
foreach (var item in smbInstances)
{
if (item.id == id)
{
return item;
}
}
return null;
}
[UnmanagedCallersOnly(EntryPoint = "initSmb")]
public static SmbInstanceNative InitSmb()
{
try
{
var client = new SMB2Client();
countSmbInstance++;
var instanceSmb = new SmbInstance()
{
client = client,
id = countSmbInstance,
};
smbInstances.Add(instanceSmb);
return new SmbInstanceNative() { smbInstanceId = countSmbInstance, errorCode = ErrorCode.Success.AsInt() };
}
catch (Exception e)
{
erroMessage = $"Unknown error: {e}";
Console.WriteLine(erroMessage);
return new SmbInstanceNative()
{
smbInstanceId = -1,
errorCode = ErrorCode.Unknown.AsInt()
};
}
}
[UnmanagedCallersOnly(EntryPoint = "connectSmb")]
public static int ConnectSmb(SmbInstanceNative smbInstanceNative, IntPtr pIpSmb,
IntPtr pDomainSmb,
IntPtr pUserSmb,
IntPtr pPassSmb)
{
try
{
string ipSmb = Marshal.PtrToStringAnsi(pIpSmb);
string domainSmb = Marshal.PtrToStringAnsi(pDomainSmb);
string userSmb = Marshal.PtrToStringAnsi(pUserSmb);
string passSmb = Marshal.PtrToStringAnsi(pPassSmb);
var instance = GetSmb(smbInstanceNative.smbInstanceId);
if (instance == null)
{
erroMessage = $"invalid instance id";
Console.WriteLine(erroMessage);
return ErrorCode.InvalidInstance.AsInt();
}
var client = instance.client;
var isSmbConnected = client.Connect(System.Net.IPAddress.Parse(ipSmb), SMBTransportType.DirectTCPTransport);
if (isSmbConnected)
{
var status = client.Login(domainSmb, userSmb, passSmb);
if (status == NTStatus.STATUS_SUCCESS)
{
return ErrorCode.Success.AsInt();
}
else
{
erroMessage = $"Failed to login {status}";
Console.WriteLine(erroMessage);
return ErrorCode.ServerLoginFailure.AsInt();
}
}
else
{
erroMessage = "Failed to access the server";
Console.WriteLine(erroMessage);
return ErrorCode.FailedAccessServer.AsInt();
}
}
catch (Exception ex)
{
erroMessage = $"Unknown error: {ex}";
Console.WriteLine(erroMessage);
return ErrorCode.Unknown.AsInt();
}
}
[UnmanagedCallersOnly(EntryPoint = "disconnectSmb")]
public static int DisconnectSmb(SmbInstanceNative smbInstanceNative)
{
try
{
var instance = GetSmb(smbInstanceNative.smbInstanceId);
if (instance == null)
{
erroMessage = $"invalid instance id";
Console.WriteLine(erroMessage);
return ErrorCode.InvalidInstance.AsInt();
}
var client = instance.client;
client.Disconnect();
return ErrorCode.Success.AsInt();
}
catch (Exception ex)
{
erroMessage = $"Unknown error: {ex}";
Console.WriteLine(erroMessage);
return ErrorCode.Unknown.AsInt();
}
}
[UnmanagedCallersOnly(EntryPoint = "freeSmb")]
public static int FreeSmb(SmbInstanceNative smbInstanceNative)
{
try
{
var instance = GetSmb(smbInstanceNative.smbInstanceId);
if (instance == null)
{
erroMessage = $"invalid instance id";
Console.WriteLine(erroMessage);
return ErrorCode.InvalidInstance.AsInt();
}
smbInstances.Remove(instance);
return ErrorCode.Success.AsInt();
}
catch (Exception ex)
{
erroMessage = $"Unknown error: {ex}";
Console.WriteLine(erroMessage);
return ErrorCode.Unknown.AsInt();
}
}
[UnmanagedCallersOnly(EntryPoint = "openShareSmb")]
public static int OpenShareSmb(SmbInstanceNative smbInstanceNative, IntPtr pShareSmb)
{
try
{
string shareSmb = Marshal.PtrToStringAnsi(pShareSmb);
// Console.WriteLine($"OpenShareSmb shareSmb {shareSmb}");
var instance = GetSmb(smbInstanceNative.smbInstanceId);
if (instance == null)
{
erroMessage = $"invalid instance id";
Console.WriteLine(erroMessage);
return ErrorCode.InvalidInstance.AsInt();
}
var client = instance.client;
var status = NTStatus.STATUS_SUCCESS;
var fileStore = client.TreeConnect(shareSmb, out status) as SMB2FileStore;
if (fileStore != null && status == NTStatus.STATUS_SUCCESS)
{
instance.fileStore = fileStore;
return ErrorCode.Success.AsInt();
}
erroMessage = $"Failed to Access Share {status}";
Console.WriteLine(erroMessage);
return ErrorCode.FailedAccessShare.AsInt();
}
catch (Exception ex)
{
erroMessage = $"Unknown error: {ex}";
Console.WriteLine(erroMessage);
return ErrorCode.Unknown.AsInt();
}
}
[UnmanagedCallersOnly(EntryPoint = "getLastError")]
public static IntPtr GetLastError()
{
// Assign pointer of the concatenated string to sumPointer
IntPtr sumPointer = Marshal.StringToHGlobalAnsi(erroMessage);
// Return pointer
return sumPointer;
}
[UnmanagedCallersOnly(EntryPoint = "downloadFileSmb")]
public static FileBytesNative DownloadFileSmb(SmbInstanceNative smbInstanceNative, IntPtr pRemotePathSmb, int pBufferLeng)
{
try
{
var retCode = ErrorCode.Success.AsInt();
string remotePathSmb = Marshal.PtrToStringAnsi(pRemotePathSmb);
// Console.WriteLine($"remotePathSmb: {remotePathSmb}");
// Console.WriteLine($"destLocalPath: {destLocalPath}");
var instance = GetSmb(smbInstanceNative.smbInstanceId);
if (instance == null)
{
erroMessage = $"invalid instance id";
Console.WriteLine(erroMessage);
return new FileBytesNative() { errorCode= ErrorCode.InvalidInstance.AsInt() };
}
if (instance.fileStore == null)
{
erroMessage = $"uninitialized fileStore use OpenShareSmb before";
Console.WriteLine(erroMessage);
return new FileBytesNative() { errorCode = ErrorCode.UninitializedFileStore.AsInt() };
}
object handle;
FileStatus fileStatus;
// Open existing file for reading
var status = instance.fileStore.CreateFile(out handle, out fileStatus, remotePathSmb,
AccessMask.GENERIC_READ, 0, ShareAccess.Read,
CreateDisposition.FILE_OPEN,
CreateOptions.FILE_NON_DIRECTORY_FILE, null);
if (status == NTStatus.STATUS_SUCCESS)
{
using (var memoryStream = new MemoryStream())
{
byte[] buffer;
int bufferLeng = pBufferLeng > 1 ? pBufferLeng : (int)instance.client.MaxReadSize;
long bytesRead = 0;
while (true)
{
status = instance.fileStore.ReadFile(out buffer, handle, bytesRead, bufferLeng);
if (status != NTStatus.STATUS_SUCCESS && status != NTStatus.STATUS_END_OF_FILE)
{
retCode = ErrorCode.FailedAccessFile.AsInt();
Console.WriteLine("Failed to access file");
break;
}
if (status == NTStatus.STATUS_END_OF_FILE || buffer.Length == 0)
{
break;
}
bytesRead += buffer.Length;
memoryStream.Write(buffer, 0, buffer.Length);
}
instance.fileStore.CloseFile(handle);
/*using (var file = new FileStream(destLocalPath, FileMode.Create, System.IO.FileAccess.Write))
{
memoryStream.Seek(0, SeekOrigin.Begin);
memoryStream.CopyTo(file);
memoryStream.Close();
file.Close();
Console.WriteLine($"end of file copy");
}*/
var data = GetBytes(memoryStream);
IntPtr unmanagedArray = Marshal.AllocHGlobal(data.Length);
Marshal.Copy(data, 0, unmanagedArray, data.Length);
//Marshal.FreeHGlobal(unmanagedArray);
Console.WriteLine($"end of file copy");
return new FileBytesNative() { bytes = unmanagedArray, length = data.Length, errorCode = 0 };
}
}
else
{
Console.WriteLine($"Failed to access file, {status}");
return new FileBytesNative() {errorCode= ErrorCode.FailedAccessFile.AsInt() };
}
return new FileBytesNative() { errorCode = retCode };
}
catch (Exception e)
{
Console.WriteLine($"Unknown error: {e}");
return new FileBytesNative() { errorCode = ErrorCode.Unknown.AsInt() };
}
}
// callbackDownload (bytesCopied, bytesTotal)
[UnmanagedCallersOnly(EntryPoint = "copyFileFromSMBtoSFTP")]
public unsafe static int CopyFileFromSMBtoSFTP(SmbInstanceNative smbInstanceNative,
IntPtr pRemotePathSmb,
IntPtr pDestSftpPath,
IntPtr pIpSftpServer,
int portSftpServer,
IntPtr pUserSftp,
IntPtr pPassSftp,
int pBufferLeng,
delegate* unmanaged<long, long, int> downloadCallback,
delegate* unmanaged<long, long, int> uploadCallback
)
{
try
{
var retCode = ErrorCode.Success.AsInt();
string remotePathSmb = Marshal.PtrToStringAnsi(pRemotePathSmb);
string destSftpPath = Marshal.PtrToStringAnsi(pDestSftpPath);
string ipSftpServer = Marshal.PtrToStringAnsi(pIpSftpServer);
string userSftp = Marshal.PtrToStringAnsi(pUserSftp);
string passSftp = Marshal.PtrToStringAnsi(pPassSftp);
//Console.WriteLine($"CopyFileFromSMBtoSFTP remotePathSmb: {remotePathSmb}");
//Console.WriteLine($"CopyFileFromSMBtoSFTP destSftpPath {destSftpPath}");
//Console.WriteLine($"CopyFileFromSMBtoSFTP ipSftpServer {ipSftpServer}");
var instance = GetSmb(smbInstanceNative.smbInstanceId);
if (instance == null)
{
erroMessage = $"invalid instance id";
Console.WriteLine(erroMessage);
return ErrorCode.InvalidInstance.AsInt();
}
if (instance.fileStore == null)
{
erroMessage = $"uninitialized fileStore use OpenShareSmb";
Console.WriteLine(erroMessage);
return ErrorCode.UninitializedFileStore.AsInt();
}
object handle;
FileStatus fileStatus;
// Open existing file for reading
var status = instance.fileStore.CreateFile(out handle, out fileStatus, remotePathSmb,
AccessMask.GENERIC_READ | AccessMask.SYNCHRONIZE,
SMBLibrary.FileAttributes.Normal, ShareAccess.Read,
CreateDisposition.FILE_OPEN,
CreateOptions.FILE_NON_DIRECTORY_FILE | CreateOptions.FILE_SYNCHRONOUS_IO_ALERT
, null);
//get File Informations
FileInformation fileInformationClass;
long bytesTotal = 0;
status = instance.fileStore.GetFileInformation(out fileInformationClass, handle, FileInformationClass.FileAllInformation);
if (status == NTStatus.STATUS_SUCCESS && fileInformationClass != null)
{
bytesTotal = fileInformationClass.Length;
if (downloadCallback != null)
{
//bytesCopied, bytesTotal
downloadCallback(0, bytesTotal);
}
}
if (status == NTStatus.STATUS_SUCCESS)
{
using (var memoryStream = new MemoryStream())
{
byte[] buffer;
int bufferLeng = pBufferLeng > 1 ? pBufferLeng : (int)instance.client.MaxReadSize;
long bytesRead = 0;
while (true)
{
status = instance.fileStore.ReadFile(out buffer, handle, bytesRead, bufferLeng);
if (downloadCallback != null)
{
//bytesCopied, bytesTotal
downloadCallback(bytesRead, bytesTotal);
}
if (status != NTStatus.STATUS_SUCCESS && status != NTStatus.STATUS_END_OF_FILE)
{
retCode = ErrorCode.FailedAccessFile.AsInt();
Console.WriteLine("Failed to access file");
break;
}
if (status == NTStatus.STATUS_END_OF_FILE || buffer.Length == 0)
{
break;
}
bytesRead += buffer.Length;
memoryStream.Write(buffer, 0, buffer.Length);
}
instance.fileStore.CloseFile(handle);
try
{
using (SftpClient sftp = new SftpClient(ipSftpServer, portSftpServer, userSftp, passSftp))
{
sftp.Connect();
CreateServerDirectoryIfItDoesntExist(destSftpPath, sftp);
memoryStream.Seek(0, SeekOrigin.Begin);
sftp.UploadFile(memoryStream, destSftpPath, delegate (ulong d)
{
if (uploadCallback != null)
{
uploadCallback((long)d, bytesTotal);
}
});
// chown -R dcm4chee-arc:dcm4chee-arc .
//change user and group dcm4chee-arc dcm4chee-arc
sftp.ChangePermissions(destSftpPath, 777);
Console.WriteLine($"end of file copy");
sftp.Disconnect();
}
}
catch (Exception ex)
{
Console.WriteLine($"Failed to copy file to SFTP server, {ex}");
return ErrorCode.FailedAccessFile.AsInt();
}
finally
{
memoryStream.Close();
}
}
}
else
{
Console.WriteLine($"Failed to access file, {status}");
return ErrorCode.FailedAccessFile.AsInt();
}
return retCode;
}
catch (Exception e)
{
Console.WriteLine($"Unknown error: {e}");
return ErrorCode.Unknown.AsInt();
}
}
private static void CreateServerDirectoryIfItDoesntExist(string serverDestinationPath, SftpClient sftpClient)
{
string[] directories = serverDestinationPath.Split('/');
//remove o ultimo elemento
Array.Resize(ref directories, directories.Length - 1);
// Console.WriteLine($"CreateServerDirectoryIfItDoesntExist: {string.Join("/", directories)}");
for (int i = 0; i < directories.Length; i++)
{
if (i > 0)
{
string dirName = string.Join("/", directories, 0, i + 1);
//Console.WriteLine($"CreateServerDirectoryIfItDoesntExist: {dirName}");
if (!sftpClient.Exists(dirName))
{
//Console.WriteLine($"CreateServerDirectoryIfItDoesntExist: {dirName}");
sftpClient.CreateDirectory(dirName);
// chown -R dcm4chee-arc:dcm4chee-arc .
//example user and group: dcm4chee-arc dcm4chee-arc
//How do I create a directory with 777 permission and a specific username and group
sftpClient.ChangePermissions(dirName, 777);
}
}
}
}
[UnmanagedCallersOnly(EntryPoint = "openDicomFromSmbAsJpeg")]
public static FileBytesNative OpenDicomFromSmbAsJpeg(SmbInstanceNative smbInstanceNative, IntPtr pRemotePathSmb, int pBufferLeng)
{
try
{
var retCode = ErrorCode.Success.AsInt();
string remotePathSmb = Marshal.PtrToStringAnsi(pRemotePathSmb);
var instance = GetSmb(smbInstanceNative.smbInstanceId);
if (instance == null)
{
erroMessage = $"invalid instance id";
Console.WriteLine(erroMessage);
return new FileBytesNative() { errorCode = ErrorCode.InvalidInstance.AsInt() };
}
if (instance.fileStore == null)
{
erroMessage = $"uninitialized fileStore use OpenShareSmb before";
Console.WriteLine(erroMessage);
return new FileBytesNative() { errorCode = ErrorCode.UninitializedFileStore.AsInt() };
}
object handle;
FileStatus fileStatus;
// Open existing file for reading
var status = instance.fileStore.CreateFile(out handle, out fileStatus, remotePathSmb,
AccessMask.GENERIC_READ, 0, ShareAccess.Read,
CreateDisposition.FILE_OPEN,
CreateOptions.FILE_NON_DIRECTORY_FILE, null);
if (status == NTStatus.STATUS_SUCCESS)
{
using (var memoryStream = new MemoryStream())
{
byte[] buffer;
int bufferLeng = pBufferLeng > 1 ? pBufferLeng : (int)instance.client.MaxReadSize;
long bytesRead = 0;
while (true)
{
status = instance.fileStore.ReadFile(out buffer, handle, bytesRead, bufferLeng);
if (status != NTStatus.STATUS_SUCCESS && status != NTStatus.STATUS_END_OF_FILE)
{
retCode = ErrorCode.FailedAccessFile.AsInt();
Console.WriteLine("Failed to access file");
break;
}
if (status == NTStatus.STATUS_END_OF_FILE || buffer.Length == 0)
{
break;
}
bytesRead += buffer.Length;
memoryStream.Write(buffer, 0, buffer.Length);
}
instance.fileStore.CloseFile(handle);
Console.WriteLine("end of file copy");
new DicomSetupBuilder()
.RegisterServices(s => s.AddFellowOakDicom().AddImageManager<ImageSharpImageManager>())
.Build();
memoryStream.Seek(0, SeekOrigin.Begin);
var dicomFile = new DicomImage(DicomFile.Open(memoryStream).Dataset);
var shartimage = dicomFile.RenderImage().AsSharpImage();
// render onto an Image
var stream = new MemoryStream();
shartimage.Save(stream, new JpegEncoder());
var data = GetBytes(stream);
memoryStream.Close();
IntPtr unmanagedArray = Marshal.AllocHGlobal(data.Length);
Marshal.Copy(data, 0, unmanagedArray, data.Length);
//Marshal.FreeHGlobal(unmanagedArray);
return new FileBytesNative() { bytes = unmanagedArray, length = data.Length, errorCode = 0 };
}
}
else
{
Console.WriteLine($"Failed to access file, {status}");
return new FileBytesNative() { errorCode = ErrorCode.FailedAccessFile.AsInt() };
}
return new FileBytesNative() { errorCode = retCode };
}
catch (Exception e)
{
Console.WriteLine($"Unknown error: {e}");
return new FileBytesNative() { errorCode = ErrorCode.Unknown.AsInt() };
}
}
[UnmanagedCallersOnly(EntryPoint = "dicomFileToBitmap")]
public static FileBytesNative DicomFileToBitmap(IntPtr pDicomFilePath,int frame)
{
string dicomFilePath = Marshal.PtrToStringAnsi(pDicomFilePath);
try
{
//Get the path of specified file
new DicomSetupBuilder()
.RegisterServices(s => s.AddFellowOakDicom().AddImageManager<ImageSharpImageManager>())
.Build();
//DicomFile.Open(stream);
var dicomFile = new DicomImage(dicomFilePath);
// Debug.WriteLine(dicomFile);
// Console.WriteLine(dicomFile.NumberOfFrames);
// Debug.WriteLine("teste");
//var file = DicomFile.Open(dicomFilePath);
//var patientid = file.Dataset.GetString(DicomTag.PatientID);
//var patientName = file.Dataset.GetString(DicomTag.PatientName);
var shartimage = dicomFile.RenderImage().AsSharpImage();
// render onto an Image
var stream = new MemoryStream();
shartimage.Save(stream, new JpegEncoder());
var data = GetBytes(stream);
IntPtr unmanagedArray = Marshal.AllocHGlobal(data.Length);
Marshal.Copy(data, 0, unmanagedArray, data.Length);
//Marshal.FreeHGlobal(unmanagedArray);
return new FileBytesNative() { bytes = unmanagedArray, length = data.Length, errorCode =0 };
}catch (Exception ex)
{
erroMessage = $"Unknown error: {ex}";
Console.WriteLine(erroMessage);
return new FileBytesNative() {errorCode= ErrorCode.Unknown.AsInt() };
}
}
public static byte[] GetBytes(Stream stream)
{
var bytes = new byte[stream.Length];
stream.Seek(0, SeekOrigin.Begin);
stream.ReadAsync(bytes, 0, bytes.Length);
stream.Dispose();
return bytes;
}
[UnmanagedCallersOnly(EntryPoint = "freeHGlobal")]
public static void FreeHGlobal(IntPtr hGlobal)
{
Marshal.FreeHGlobal(hGlobal);
}
}
Expected behavior
run normally
Actual behavior
does not run and displays this error
Regression?
No response
Known Workarounds
workaround As a workaround, I’m setting the environment variable DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1 as suggested here: https://stackoverflow.com/questions/59119904/process-terminated-couldnt-find-a-valid-icu-package-installed-on-the-system-in
Configuration
.NET 7 Debian 11 Architecture x64
Other information
No response
About this issue
- Original URL
- State: closed
- Created 2 years ago
- Comments: 21 (14 by maintainers)
@tarekgh I made a test console app as you suggested
Can you please reduce your code to the minimum required to reproduce the problem.
I am seeing the NativeAOT is just working with ICU too. So, now I am wondering if the actual problem is from your original repro app? I think the problem you have is how did you build the AOT app which showing the problem.
That is expected. Metadata required to support reflection are trimmed in NativeAOT by default to minimize binary sizes. Also, the warnings that you see in the output are trying to tell you that your app may not work due to problematic reflection use.