Skip to content

[Bug] Codegen generates a NRE #1369

Description

@JustArion

Actual behavior

Methods generated by CsWin32 that use Unsafe.NullRef throw a NRE when used regardless of parameters

Expected behavior

Methods generated by CsWin32 that use Unsafe.NullRef should not throw a NRE

Repro steps

  1. NativeMethods.txt content:
MiniDumpWriteDump
  1. NativeMethods.json content (if present): N/A

  2. Any of your own code that should be shared?

Bear in mind this type of bug is a bit more nuanced.

CsWin32 generates the following:

winmdroot.Foundation.BOOL __result = PInvoke.MiniDumpWriteDump(hProcessLocal, ProcessId, hFileLocal, DumpType, ExceptionParam.HasValue ? &ExceptionParamLocal : null, UserStreamParam.HasValue ? &UserStreamParamLocal : null, CallbackParam.HasValue ? CallbackParamLocal : Unsafe.NullRef<winmdroot.System.Diagnostics.Debug.MINIDUMP_CALLBACK_INFORMATION >());

Broken down to more readable terms:

var __result = PInvoke.MiniDumpWriteDump(hProcessLocal, ProcessId, hFileLocal, DumpType, ExceptionParam.HasValue ? &ExceptionParamLocal : null, UserStreamParam.HasValue ? &UserStreamParamLocal : null, 
  CallbackParam.HasValue 
    ? CallbackParamLocal 
    : Unsafe.NullRef<Windows.Win32.System.Diagnostics.Debug.MINIDUMP_CALLBACK_INFORMATION >());

tl;dr:

int* nul = (int*)0;
int example = 0;

int s = condition ? example : *nul;

SomeMethod(&s);

One variable is ref while the other isn't so C# lowers the modifiers till common ground is achieved.
ref + non-ref = non-ref
fix: ref + ref = ref

The issue is that CallbackParamLocal is not a ref variable. C# tries to find the most common type to send into the method that both Unsafe.NullRef and CallbackParamLocal share, so C# drops the ref attribute which causes C# to "dereference" the Unsafe.NullRef, causing an exception.

A SharpLab PoC can be found here

string str = (flag ? text : Unsafe.NullRef<string>());

the example is "dereferenced" there.

A proposed fix for this would be something like:

ref var CallbackParamReference = ref CallbackParam.HasValue
	? ref CallbackParamLocal
	: ref Unsafe.NullRef<Windows.Win32.System.Diagnostics.Debug.MINIDUMP_CALLBACK_INFORMATION>();

var __result = PInvoke.MiniDumpWriteDump(hProcessLocal, ProcessId, hFileLocal, DumpType, ExceptionParam.HasValue ? &ExceptionParamLocal : null, UserStreamParam.HasValue ? &UserStreamParamLocal : null, CallbackParamReference);

Context

  • CsWin32 version: 0.3.183
  • Win32Metadata version (if explicitly set by project): N/A
  • Target Framework: net9.0-windows
  • LangVersion preview

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions