Skip to content

Commit

Permalink
Fix race conditions in native methods
Browse files Browse the repository at this point in the history
The containers for caching native method delegates must not be
initialized at runtime without locking. This allows for race
conditions and can lead to NullRefException when calling two
methods simultaneously which require the same methods container.
  • Loading branch information
cbersch authored and ermshiperete committed Apr 20, 2022
1 parent b18febc commit bb1a46e
Show file tree
Hide file tree
Showing 13 changed files with 23 additions and 64 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Include `icu.net.dll.config` file in nuget package. This is important for running on MacOSX.
- Fix construction of locale with language and keywords (cbersch)
- Fix passing locale to ubrk_open (cbersch)
- Fix race condition during initialization of native methods container (cbersch)

## [2.7.1] - 2021-03-04

Expand Down
22 changes: 11 additions & 11 deletions source/icu.net/NativeMethods/NativeMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -369,17 +369,17 @@ public static void Cleanup()
_IcuI18NLibHandle = IntPtr.Zero;

Methods = new MethodsContainer();
_BiDiMethods = null;
_BreakIteratorMethods = null;
_CodepageConversionMethods = null;
_CollatorMethods = null;
_LocalesMethods = null;
_MessageFormatMethods = null;
_NormalizeMethods = null;
_RegexMethods = null;
_ResourceBundleMethods = null;
_TransliteratorMethods = null;
_UnicodeSetMethods = null;
BiDiMethods = new BiDiMethodsContainer();
BreakIteratorMethods = new BreakIteratorMethodsContainer();
CodepageConversionMethods = new CodepageConversionMethodsContainer();
CollatorMethods = new CollatorMethodsContainer();
LocalesMethods = new LocalesMethodsContainer();
MessageFormatMethods = new MessageFormatMethodsContainer();
NormalizeMethods = new NormalizeMethodsContainer();
RegexMethods = new RegexMethodsContainer();
ResourceBundleMethods = new ResourceBundleMethodsContainer();
TransliteratorMethods = new TransliteratorMethodsContainer();
UnicodeSetMethods = new UnicodeSetMethodsContainer();
ResetIcuVersionInfo();
}
}
Expand Down
4 changes: 1 addition & 3 deletions source/icu.net/NativeMethods/NativeMethods_BiDi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -148,9 +148,7 @@ private class BiDiMethodsContainer
internal ubidi_getBaseDirectionDelegate ubidi_getBaseDirection;
}

private static BiDiMethodsContainer _BiDiMethods;

private static BiDiMethodsContainer BiDiMethods => _BiDiMethods ?? (_BiDiMethods = new BiDiMethodsContainer());
private static BiDiMethodsContainer BiDiMethods = new BiDiMethodsContainer();

/// <summary>
/// Create a UBiDi structure.
Expand Down
6 changes: 1 addition & 5 deletions source/icu.net/NativeMethods/NativeMethods_BreakIterator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,7 @@ internal delegate void ubrk_setTextDelegate(IntPtr bi, string text, int textLeng
internal ubrk_setTextDelegate ubrk_setText;
}

private static BreakIteratorMethodsContainer _BreakIteratorMethods;

private static BreakIteratorMethodsContainer BreakIteratorMethods =>
_BreakIteratorMethods ??
(_BreakIteratorMethods = new BreakIteratorMethodsContainer());
private static BreakIteratorMethodsContainer BreakIteratorMethods = new BreakIteratorMethodsContainer();

#region Break iterator

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,7 @@ internal delegate IntPtr ucnv_getStandardNameDelegate(string name, string standa
internal ucnv_getStandardNameDelegate ucnv_getStandardName;
}

private static CodepageConversionMethodsContainer _CodepageConversionMethods;

private static CodepageConversionMethodsContainer CodepageConversionMethods =>
_CodepageConversionMethods ??
(_CodepageConversionMethods = new CodepageConversionMethodsContainer());
private static CodepageConversionMethodsContainer CodepageConversionMethods = new CodepageConversionMethodsContainer();

public static SafeEnumeratorHandle ucnv_openAllNames(out ErrorCode err)
{
Expand Down
6 changes: 1 addition & 5 deletions source/icu.net/NativeMethods/NativeMethods_Locales.cs
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,7 @@ internal delegate int uloc_canonicalizeDelegate(string localeID, IntPtr name,
internal uloc_canonicalizeDelegate uloc_canonicalize;
}

private static LocalesMethodsContainer _LocalesMethods;

private static LocalesMethodsContainer LocalesMethods =>
_LocalesMethods ??
(_LocalesMethods = new LocalesMethodsContainer());
private static LocalesMethodsContainer LocalesMethods = new LocalesMethodsContainer();

/// <summary>Get the ICU LCID for a locale</summary>
public static int uloc_getLCID([MarshalAs(UnmanagedType.LPStr)] string localeID)
Expand Down
6 changes: 1 addition & 5 deletions source/icu.net/NativeMethods/NativeMethods_MessageFormat.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,7 @@ internal delegate int umsg_toPatternDelegate(IntPtr format, IntPtr result,

}

private static MessageFormatMethodsContainer _MessageFormatMethods;

private static MessageFormatMethodsContainer MessageFormatMethods =>
_MessageFormatMethods ??
(_MessageFormatMethods = new MessageFormatMethodsContainer());
private static MessageFormatMethodsContainer MessageFormatMethods = new MessageFormatMethodsContainer();

/// <summary/>
public static IntPtr umsg_open(string pattern, int patternLen, string locale, out ParseError parseError, out ErrorCode status)
Expand Down
6 changes: 1 addition & 5 deletions source/icu.net/NativeMethods/NativeMethods_Normalize.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,7 @@ internal delegate int unorm2_getRawDecompositionDelegate(IntPtr norm2, int c,
internal unorm2_getCombiningClassDelegate unorm2_getCombiningClass;
}

private static NormalizeMethodsContainer _NormalizeMethods;

private static NormalizeMethodsContainer NormalizeMethods =>
_NormalizeMethods ??
(_NormalizeMethods = new NormalizeMethodsContainer());
private static NormalizeMethodsContainer NormalizeMethods = new NormalizeMethodsContainer();

#region normalize

Expand Down
6 changes: 1 addition & 5 deletions source/icu.net/NativeMethods/NativeMethods_Regex.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,7 @@ internal delegate void uregex_setTextDelegate(IntPtr regexp,
internal uregex_closeDelegate uregex_close;
}

private static RegexMethodsContainer _RegexMethods;

private static RegexMethodsContainer RegexMethods =>
_RegexMethods ??
(_RegexMethods = new RegexMethodsContainer());
private static RegexMethodsContainer RegexMethods = new RegexMethodsContainer();

/// <summary>
/// Open (compile) an ICU regular expression.
Expand Down
6 changes: 1 addition & 5 deletions source/icu.net/NativeMethods/NativeMethods_ResourceBundle.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,7 @@ internal delegate IntPtr ures_getNextResourceDelegate(IntPtr resourceBundle,
internal ures_getNextResourceDelegate ures_getNextResource;
}

private static ResourceBundleMethodsContainer _ResourceBundleMethods;

private static ResourceBundleMethodsContainer ResourceBundleMethods =>
_ResourceBundleMethods ??
(_ResourceBundleMethods = new ResourceBundleMethodsContainer());
private static ResourceBundleMethodsContainer ResourceBundleMethods = new ResourceBundleMethodsContainer();

/// <summary/>
public static IntPtr ures_open(string packageName, string locale, out ErrorCode status)
Expand Down
6 changes: 1 addition & 5 deletions source/icu.net/NativeMethods/NativeMethods_Transliterator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,7 @@ internal delegate void utrans_transUCharsDelegate(
internal utrans_transUCharsDelegate utrans_transUChars;
}

private static TransliteratorMethodsContainer _TransliteratorMethods;

private static TransliteratorMethodsContainer TransliteratorMethods =>
_TransliteratorMethods ??
(_TransliteratorMethods = new TransliteratorMethodsContainer());
private static TransliteratorMethodsContainer TransliteratorMethods = new TransliteratorMethodsContainer();

/// <summary/>
public static SafeEnumeratorHandle utrans_openIDs(out ErrorCode errorCode)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,11 +87,7 @@ internal delegate int ucol_getBoundDelegate(byte[] source, int sourceLength,
internal ucol_getBoundDelegate ucol_getBound;
}

private static CollatorMethodsContainer _CollatorMethods;

private static CollatorMethodsContainer CollatorMethods =>
_CollatorMethods ??
(_CollatorMethods = new CollatorMethodsContainer());
private static CollatorMethodsContainer CollatorMethods = new CollatorMethodsContainer();

#region Unicode collator

Expand Down
6 changes: 1 addition & 5 deletions source/icu.net/NativeMethods/NativeMethods_UnicodeSet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,7 @@ internal delegate int uset_getItemDelegate(IntPtr set, int itemIndex, out int st
internal uset_getItemCountDelegate uset_getItemCount;
}

private static UnicodeSetMethodsContainer _UnicodeSetMethods;

private static UnicodeSetMethodsContainer UnicodeSetMethods =>
_UnicodeSetMethods ??
(_UnicodeSetMethods = new UnicodeSetMethodsContainer());
private static UnicodeSetMethodsContainer UnicodeSetMethods = new UnicodeSetMethodsContainer();

/// <summary>
/// Disposes of the storage used by Unicode set. This function should be called exactly once for objects returned by uset_open()
Expand Down

0 comments on commit bb1a46e

Please sign in to comment.