From 72955d1aa49f25fc0650d2c431016f317cdf1471 Mon Sep 17 00:00:00 2001 From: KeatonTheBot Date: Mon, 9 Mar 2026 17:58:10 -0500 Subject: [PATCH] LibKenjinx: Fix possible NullReferenceExceptions --- src/LibKenjinx/Android/JniExportedMethods.cs | 6 +- src/LibKenjinx/LibKenjinx.Device.cs | 6 +- src/LibKenjinx/LibKenjinx.User.cs | 20 +++--- src/LibKenjinx/LibKenjinx.cs | 65 +++++++++++--------- src/LibKenjinx/VulkanLoader.cs | 8 +-- 5 files changed, 57 insertions(+), 48 deletions(-) diff --git a/src/LibKenjinx/Android/JniExportedMethods.cs b/src/LibKenjinx/Android/JniExportedMethods.cs index 3219349fe..7bb982cb4 100644 --- a/src/LibKenjinx/Android/JniExportedMethods.cs +++ b/src/LibKenjinx/Android/JniExportedMethods.cs @@ -61,7 +61,7 @@ namespace LibKenjinx }; // Try call method with single bool - private static bool TryCallBool(object target, string[] names, bool arg) + private static bool TryCallBool(object? target, string[] names, bool arg) { if (target == null) return false; var t = target.GetType(); @@ -77,7 +77,7 @@ namespace LibKenjinx } // Try call method with single float - private static bool TryCallFloat(object target, string[] names, float arg) + private static bool TryCallFloat(object? target, string[] names, float arg) { if (target == null) return false; var t = target.GetType(); @@ -93,7 +93,7 @@ namespace LibKenjinx } // Try set property (float/double) - private static bool TrySetFloatProp(object target, string[] names, float value) + private static bool TrySetFloatProp(object? target, string[] names, float value) { if (target == null) return false; var t = target.GetType(); diff --git a/src/LibKenjinx/LibKenjinx.Device.cs b/src/LibKenjinx/LibKenjinx.Device.cs index 4ccdc242b..6580d0d84 100644 --- a/src/LibKenjinx/LibKenjinx.Device.cs +++ b/src/LibKenjinx/LibKenjinx.Device.cs @@ -54,12 +54,12 @@ namespace LibKenjinx public static void InstallFirmware(Stream stream, bool isXci) { - SwitchDevice?.ContentManager.InstallFirmware(stream, isXci); + SwitchDevice?.ContentManager?.InstallFirmware(stream, isXci); } public static string GetInstalledFirmwareVersion() { - var version = SwitchDevice?.ContentManager.GetCurrentFirmwareVersion(); + var version = SwitchDevice?.ContentManager?.GetCurrentFirmwareVersion(); if (version != null) { @@ -71,7 +71,7 @@ namespace LibKenjinx public static SystemVersion? VerifyFirmware(Stream stream, bool isXci) { - return SwitchDevice?.ContentManager.VerifyFirmwarePackage(stream, isXci) ?? null; + return SwitchDevice?.ContentManager?.VerifyFirmwarePackage(stream, isXci) ?? null; } public static bool LoadApplication(Stream stream, FileType type, Stream? updateStream = null) diff --git a/src/LibKenjinx/LibKenjinx.User.cs b/src/LibKenjinx/LibKenjinx.User.cs index 021e29995..e86dedf9f 100644 --- a/src/LibKenjinx/LibKenjinx.User.cs +++ b/src/LibKenjinx/LibKenjinx.User.cs @@ -8,7 +8,7 @@ namespace LibKenjinx { public static string GetOpenedUser() { - var lastProfile = SwitchDevice?.AccountManager.LastOpenedUser; + var lastProfile = SwitchDevice?.AccountManager?.LastOpenedUser; return lastProfile?.UserId.ToString() ?? ""; } @@ -17,7 +17,7 @@ namespace LibKenjinx { var uid = new UserId(userId); - var user = SwitchDevice?.AccountManager.GetAllUsers().FirstOrDefault(x => x.UserId == uid); + var user = SwitchDevice?.AccountManager?.GetAllUsers().FirstOrDefault(x => x.UserId == uid); if (user == null) return ""; @@ -31,14 +31,14 @@ namespace LibKenjinx { var uid = new UserId(userId); - SwitchDevice?.AccountManager.SetUserImage(uid, Convert.FromBase64String(picture)); + SwitchDevice?.AccountManager?.SetUserImage(uid, Convert.FromBase64String(picture)); } public static string GetUserName(string userId) { var uid = new UserId(userId); - var user = SwitchDevice?.AccountManager.GetAllUsers().FirstOrDefault(x => x.UserId == uid); + var user = SwitchDevice?.AccountManager?.GetAllUsers().FirstOrDefault(x => x.UserId == uid); return user?.Name ?? ""; } @@ -47,36 +47,36 @@ namespace LibKenjinx { var uid = new UserId(userId); - SwitchDevice?.AccountManager.SetUserName(uid, name); + SwitchDevice?.AccountManager?.SetUserName(uid, name); } public static string[] GetAllUsers() { - return SwitchDevice?.AccountManager.GetAllUsers().Select(x => x.UserId.ToString()).ToArray() ?? + return SwitchDevice?.AccountManager?.GetAllUsers().Select(x => x.UserId.ToString()).ToArray() ?? []; } public static void AddUser(string userName, string picture) { - SwitchDevice?.AccountManager.AddUser(userName, Convert.FromBase64String(picture)); + SwitchDevice?.AccountManager?.AddUser(userName, Convert.FromBase64String(picture)); } public static void DeleteUser(string userId) { var uid = new UserId(userId); - SwitchDevice?.AccountManager.DeleteUser(uid); + SwitchDevice?.AccountManager?.DeleteUser(uid); } public static void OpenUser(string userId) { var uid = new UserId(userId); - SwitchDevice?.AccountManager.OpenUser(uid); + SwitchDevice?.AccountManager?.OpenUser(uid); } public static void CloseUser(string userId) { var uid = new UserId(userId); - SwitchDevice?.AccountManager.CloseUser(uid); + SwitchDevice?.AccountManager?.CloseUser(uid); } } } diff --git a/src/LibKenjinx/LibKenjinx.cs b/src/LibKenjinx/LibKenjinx.cs index 4fde167e8..1f08154e8 100644 --- a/src/LibKenjinx/LibKenjinx.cs +++ b/src/LibKenjinx/LibKenjinx.cs @@ -523,7 +523,7 @@ namespace LibKenjinx if (File.Exists(updatePath)) { FileStream file = new(updatePath, FileMode.Open, FileAccess.Read); - IFileSystem pfs = null; + IFileSystem pfs; if (Path.GetExtension(updatePath).ToLower() == ".xci") { @@ -616,8 +616,7 @@ namespace LibKenjinx partitionFileSystem.OpenFile(ref ncaFile.Ref, ncaPath.ToU8Span(), OpenMode.Read).ThrowIfFailure(); - Nca nca = TryOpenNca(ncaFile.Get.AsStorage(), ncaPath); - if (nca != null) + if (TryOpenNca(ncaFile.Get.AsStorage(), ncaPath) is { } nca) { return nca.Header.TitleId.ToString("X16"); } @@ -627,7 +626,7 @@ namespace LibKenjinx } - private static Nca TryOpenNca(IStorage ncaStorage, string containerPath) + private static Nca? TryOpenNca(IStorage ncaStorage, string containerPath) { try { @@ -661,7 +660,7 @@ namespace LibKenjinx partitionFileSystem.OpenFile(ref ncaFile.Ref, fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure(); - Nca nca = TryOpenNca(ncaFile.Get.AsStorage(), path); + Nca? nca = TryOpenNca(ncaFile.Get.AsStorage(), path); if (nca == null) { continue; @@ -698,7 +697,7 @@ namespace LibKenjinx } // ===== Amiibo Helpers (Kenjinx) ===== - public static bool AmiiboLoadFromBytes(byte[] data) + public static bool AmiiboLoadFromBytes(byte[]? data) { if (data == null || data.Length == 0) { @@ -755,13 +754,13 @@ namespace LibKenjinx public class SwitchDevice : IDisposable { - private readonly SystemVersion _firmwareVersion; + private readonly SystemVersion? _firmwareVersion; private int _contextDisposeState; public VirtualFileSystem VirtualFileSystem { get; set; } - public ContentManager ContentManager { get; set; } - public AccountManager AccountManager { get; set; } - public LibHacHorizonManager LibHacHorizonManager { get; set; } - public UserChannelPersistence UserChannelPersistence { get; set; } + public ContentManager? ContentManager { get; set; } + public AccountManager? AccountManager { get; set; } + public LibHacHorizonManager? LibHacHorizonManager { get; set; } + public UserChannelPersistence? UserChannelPersistence { get; set; } public InputManager? InputManager { get; set; } public Switch? EmulationContext { get; set; } public IHostUIHandler? HostUiHandler { get; set; } @@ -949,7 +948,7 @@ namespace LibKenjinx // --- Prepare paths for the physical save directory (Android sandbox) string savesRoot = Path.Combine( AppDataManager.BaseDirPath, - Ryujinx.HLE.FileSystem.VirtualFileSystem.UserNandPath, + VirtualFileSystem.UserNandPath, "save" ); @@ -963,17 +962,24 @@ namespace LibKenjinx catch { /* ignore */ } // Call existing Horizon APIs to create/secure the saves - var rc = LibHacHorizonManager.RyujinxClient.Fs.EnsureApplicationCacheStorage(out _, out _, applicationId, in control); - if (rc.IsFailure()) + if (LibHacHorizonManager != null) { - Logger.Error?.Print(LogClass.Application, $"Error calling EnsureApplicationCacheStorage. Result code {rc.ToStringWithName()}"); - } + var rc = LibHacHorizonManager.RyujinxClient.Fs.EnsureApplicationCacheStorage(out _, out _, applicationId, in control); + if (rc.IsFailure()) + { + Logger.Error?.Print(LogClass.Application, $"Error calling EnsureApplicationCacheStorage. Result code {rc.ToStringWithName()}"); + } - Uid userId = AccountManager.LastOpenedUser.UserId.ToLibHacUid(); - rc = LibHacHorizonManager.RyujinxClient.Fs.EnsureApplicationSaveData(out _, applicationId, in control, in userId); - if (rc.IsFailure()) - { - Logger.Error?.Print(LogClass.Application, $"Error calling EnsureApplicationSaveData. Result code {rc.ToStringWithName()}"); + if (AccountManager != null) + { + Uid userId = AccountManager.LastOpenedUser.UserId.ToLibHacUid(); + rc = LibHacHorizonManager.RyujinxClient.Fs.EnsureApplicationSaveData(out _, applicationId, in control, in userId); + } + + if (rc.IsFailure()) + { + Logger.Error?.Print(LogClass.Application, $"Error calling EnsureApplicationSaveData. Result code {rc.ToStringWithName()}"); + } } // Get the after-list of save dirs and calculate the difference @@ -1013,7 +1019,10 @@ namespace LibKenjinx File.WriteAllText(markerFile, $"{titleIdHex}\n{titleName}"); } - UpsertTitleMapNdjson(savesRoot, titleIdHex, titleName, createdSaveDirName); + if (createdSaveDirName != null) + { + UpsertTitleMapNdjson(savesRoot, titleIdHex, titleName, createdSaveDirName); + } } catch (Exception ex) { @@ -1038,7 +1047,7 @@ namespace LibKenjinx /// - Completely rewrites the file (no unlimited size increase) /// - NEVER overwrites the folder with an empty value; attempts to determine it via markers /// - private static void UpsertTitleMapNdjson(string savesRoot, string titleIdHex, string titleName, string createdFolder) + private static void UpsertTitleMapNdjson(string savesRoot, string? titleIdHex, string? titleName, string createdFolder) { Directory.CreateDirectory(savesRoot); string mapPath = Path.Combine(savesRoot, "titleid_map.ndjson"); @@ -1092,7 +1101,7 @@ namespace LibKenjinx string effectiveFolder = createdFolder; if (string.IsNullOrWhiteSpace(effectiveFolder)) { - effectiveFolder = ResolveSaveFolderByMarker(savesRoot, titleIdLc); + effectiveFolder = ResolveSaveFolderByMarker(savesRoot, titleIdLc) ?? string.Empty; } if (string.IsNullOrWhiteSpace(effectiveFolder) && !string.IsNullOrWhiteSpace(existingFolder)) { @@ -1122,7 +1131,7 @@ namespace LibKenjinx string finalFolder = string.IsNullOrWhiteSpace(effectiveFolder) ? (existing.Folder ?? "") : effectiveFolder; string finalTs = nowIso; - byTitleId[titleIdLc] = (finalName ?? "", finalFolder ?? "", finalTs); + byTitleId[titleIdLc] = (finalName, finalFolder, finalTs); // 5) rewrite file (stable: sort by titleId) try @@ -1145,7 +1154,7 @@ namespace LibKenjinx /// /// Scans save subfolders for a TITLEID.txt whose first line equals the titleId; returns folder name or null. /// - private static string ResolveSaveFolderByMarker(string savesRoot, string titleIdLc) + private static string? ResolveSaveFolderByMarker(string savesRoot, string titleIdLc) { try { @@ -1159,7 +1168,7 @@ namespace LibKenjinx try { using var sr = new StreamReader(marker, Encoding.UTF8, true); - string first = sr.ReadLine()?.Trim()?.ToLowerInvariant(); + string? first = sr.ReadLine()?.Trim().ToLowerInvariant(); if (first == titleIdLc) { return Path.GetFileName(dir); @@ -1210,7 +1219,7 @@ namespace LibKenjinx { VirtualFileSystem.ReloadKeySet(); ContentManager = new ContentManager(VirtualFileSystem); - AccountManager = new AccountManager(LibHacHorizonManager.RyujinxClient); + AccountManager = new AccountManager(LibHacHorizonManager?.RyujinxClient); } } diff --git a/src/LibKenjinx/VulkanLoader.cs b/src/LibKenjinx/VulkanLoader.cs index fadc4b5c9..803b6c752 100644 --- a/src/LibKenjinx/VulkanLoader.cs +++ b/src/LibKenjinx/VulkanLoader.cs @@ -55,14 +55,14 @@ namespace LibKenjinx byte* xp = (byte*)xPtr; try { - nint ptr = default; + nint ptr; ptr = _getInstanceProcAddr(ret.CurrentInstance.GetValueOrDefault().Handle, xPtr); - if (ptr == default) + if (ptr == 0) { ptr = _getInstanceProcAddr(nint.Zero, xPtr); - if (ptr == default) + if (ptr == 0) { var currentDevice = ret.CurrentDevice.GetValueOrDefault().Handle; if (currentDevice != nint.Zero) @@ -70,7 +70,7 @@ namespace LibKenjinx ptr = _getDeviceProcAddr(currentDevice, xPtr); } - if (ptr == default) + if (ptr == 0) { Logger.Warning?.Print(LogClass.Gpu, $"Failed to get function pointer: {x}"); }