Skip to content

Commit

Permalink
[release/5.0] Make sure we consider buffer length when marshalling ba…
Browse files Browse the repository at this point in the history
…ck Unicode ByValTStr fields (#54752)
  • Loading branch information
jkoritzinsky authored Jul 9, 2021
1 parent 9b6d3ab commit 9d5c191
Show file tree
Hide file tree
Showing 6 changed files with 59 additions and 5 deletions.
11 changes: 11 additions & 0 deletions src/coreclr/src/System.Private.CoreLib/src/System/StubHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,17 @@ internal static unsafe void ConvertToNative(string? strManaged, IntPtr nativeHom
managed.Slice(0, numChars).CopyTo(native);
native[numChars] = '\0';
}

internal static unsafe string ConvertToManaged(IntPtr nativeHome, int length)
{
int end = SpanHelpers.IndexOf(ref *(char*)nativeHome, '\0', length);
if (end != -1)
{
length = end;
}

return new string((char*)nativeHome, 0, length);
}
} // class WSTRBufferMarshaler
#if FEATURE_COMINTEROP

Expand Down
1 change: 1 addition & 0 deletions src/coreclr/src/vm/corelib.h
Original file line number Diff line number Diff line change
Expand Up @@ -1050,6 +1050,7 @@ DEFINE_METHOD(CSTRMARSHALER, CLEAR_NATIVE, ClearNative,

DEFINE_CLASS(FIXEDWSTRMARSHALER, StubHelpers, FixedWSTRMarshaler)
DEFINE_METHOD(FIXEDWSTRMARSHALER, CONVERT_TO_NATIVE, ConvertToNative, SM_Str_IntPtr_Int_RetVoid)
DEFINE_METHOD(FIXEDWSTRMARSHALER, CONVERT_TO_MANAGED, ConvertToManaged, SM_IntPtr_Int_RetStr)

DEFINE_CLASS(BSTRMARSHALER, StubHelpers, BSTRMarshaler)
DEFINE_METHOD(BSTRMARSHALER, CONVERT_TO_NATIVE, ConvertToNative, SM_Str_IntPtr_RetIntPtr)
Expand Down
7 changes: 2 additions & 5 deletions src/coreclr/src/vm/ilmarshalers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1909,11 +1909,8 @@ void ILFixedWSTRMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmi
STANDARD_VM_CONTRACT;

EmitLoadNativeHomeAddr(pslILEmit);
pslILEmit->EmitDUP();
pslILEmit->EmitCALL(METHOD__STRING__WCSLEN, 1, 1);
pslILEmit->EmitCALL(METHOD__STUBHELPERS__CHECK_STRING_LENGTH, 1, 0);

pslILEmit->EmitNEWOBJ(METHOD__STRING__CTOR_CHARPTR, 1);
pslILEmit->EmitLDC(m_pargs->fs.fixedStringLength);
pslILEmit->EmitCALL(METHOD__FIXEDWSTRMARSHALER__CONVERT_TO_MANAGED, 2, 1);
EmitStoreManagedValue(pslILEmit);
}

Expand Down
15 changes: 15 additions & 0 deletions src/tests/Interop/StringMarshalling/LPTSTR/LPTSTRTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,5 +60,20 @@ private static void RunByValTStrTests()
ReverseByValStringUni(ref uniStr);

Assert.AreEqual(Helpers.Reverse(InitialString), uniStr.str);

ReverseCopyByValStringAnsi(new ByValStringInStructAnsi { str = LongString }, out ByValStringInStructSplitAnsi ansiStrSplit);

Assert.AreEqual(Helpers.Reverse(LongString[^10..]), ansiStrSplit.str1);
Assert.AreEqual(Helpers.Reverse(LongString[..^10]), ansiStrSplit.str2);

ReverseCopyByValStringUni(new ByValStringInStructUnicode { str = LongString }, out ByValStringInStructSplitUnicode uniStrSplit);

Assert.AreEqual(Helpers.Reverse(LongString[^10..]), uniStrSplit.str1);
Assert.AreEqual(Helpers.Reverse(LongString[..^10]), uniStrSplit.str2);

ReverseCopyByValStringUni(new ByValStringInStructUnicode { str = LongUnicodeString }, out ByValStringInStructSplitUnicode uniStrSplit2);

Assert.AreEqual(Helpers.Reverse(LongUnicodeString[^10..]), uniStrSplit2.str1);
Assert.AreEqual(Helpers.Reverse(LongUnicodeString[..^10]), uniStrSplit2.str2);
}
}
12 changes: 12 additions & 0 deletions src/tests/Interop/StringMarshalling/LPTSTR/LPTStrTestNative.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,15 @@ extern "C" DLL_EXPORT void STDMETHODCALLTYPE ReverseByValStringUni(ByValStringIn
{
StringMarshalingTests<LPWSTR, TP_slen>::ReverseInplace(str->str);
}

extern "C" DLL_EXPORT void STDMETHODCALLTYPE ReverseCopyByValStringAnsi(ByValStringInStructAnsi str, ByValStringInStructAnsi* out)
{
*out = str;
StringMarshalingTests<char*, default_callconv_strlen>::ReverseInplace(out->str);
}

extern "C" DLL_EXPORT void STDMETHODCALLTYPE ReverseCopyByValStringUni(ByValStringInStructUnicode str, ByValStringInStructUnicode* out)
{
*out = str;
StringMarshalingTests<LPWSTR, TP_slen>::ReverseInplace(out->str);
}
18 changes: 18 additions & 0 deletions src/tests/Interop/StringMarshalling/LPTSTR/LPTStrTestNative.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,31 @@ public struct ByValStringInStructAnsi
public string str;
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct ByValStringInStructSplitAnsi
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]
public string str1;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]
public string str2;
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct ByValStringInStructUnicode
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
public string str;
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct ByValStringInStructSplitUnicode
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]
public string str1;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]
public string str2;
}

[DllImport(nameof(LPTStrTestNative), CharSet = CharSet.Unicode)]
public static extern bool Verify_NullTerminators_PastEnd(StringBuilder builder, int length);

Expand Down

0 comments on commit 9d5c191

Please sign in to comment.