Skip to content

Commit

Permalink
Merge pull request #83404 from vseanreesermsft/internal-merge-6.0-202…
Browse files Browse the repository at this point in the history
…3-03-14-1014

Merging internal commits for release/6.0
  • Loading branch information
carlossanlop authored Mar 14, 2023
2 parents 1a1a8d3 + adc4201 commit 43bb599
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2617,6 +2617,9 @@
<data name="InvalidProgram_Default" xml:space="preserve">
<value>Common Language Runtime detected an invalid program.</value>
</data>
<data name="InvalidTimeZone_InvalidId" xml:space="preserve">
<value>The time zone ID '{0}' is invalid.</value>
</data>
<data name="InvalidTimeZone_InvalidFileData" xml:space="preserve">
<value>The time zone ID '{0}' was found on the local computer, but the file at '{1}' was corrupt.</value>
</data>
Expand All @@ -2641,6 +2644,9 @@
<data name="IO_NoFileTableInInMemoryAssemblies" xml:space="preserve">
<value>This assembly does not have a file table because it was loaded from memory.</value>
</data>
<data name="IO_UnseekableFile" xml:space="preserve">
<value>Unsupported unseekable file.</value>
</data>
<data name="IO_EOF_ReadBeyondEOF" xml:space="preserve">
<value>Unable to read beyond the end of the stream.</value>
</data>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,83 @@ private static TimeZoneInfo GetLocalTimeZoneCore()
return GetLocalTimeZoneFromTzFile();
}

internal static byte[] ReadAllBytesFromSeekableNonZeroSizeFile(string path, int maxFileSize)
{
using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize: 1, FileOptions.SequentialScan))
{
if (!fs.CanSeek)
{
throw new IOException(SR.IO_UnseekableFile);
}

long fileLength = fs.Length;
if (fileLength > maxFileSize)
{
throw new IOException(SR.IO_FileTooLong);
}

if (fileLength == 0)
{
throw new IOException(SR.IO_InvalidReadLength);
}

int index = 0;
int count = (int)fileLength;
byte[] bytes = new byte[count];
while (count > 0)
{
int n = fs.Read(bytes, index, count);
if (n == 0)
{
ThrowHelper.ThrowEndOfFileException();
}
index += n;
count -= n;
}
return bytes;
}
}

// Bitmap covering the ASCII range. The bits is set for the characters [a-z], [A-Z], [0-9], '/', '-', and '_'.
private static byte[] asciiBitmap = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0xA8, 0xFF, 0x03, 0xFE, 0xFF, 0xFF, 0x87, 0xFE, 0xFF, 0xFF, 0x07 };

private static bool IdContainsAnyDisallowedChars(string zoneId)
{
for (int i = 0; i < zoneId.Length; i++)
{
int c = zoneId[i];
if (c > 0x7F)
{
return true;
}

int value = c >> 3;
if ((asciiBitmap[value] & (ulong)(1UL << (c - (value << 3)))) == 0)
{
return true;
}
}

return false;
}

private static TimeZoneInfoResult TryGetTimeZoneFromLocalMachineCore(string id, out TimeZoneInfo? value, out Exception? e)
{
value = null;
e = null;

if (Path.IsPathRooted(id) || IdContainsAnyDisallowedChars(id))
{
e = new TimeZoneNotFoundException(SR.Format(SR.InvalidTimeZone_InvalidId, id));
return TimeZoneInfoResult.TimeZoneNotFoundException;
}

string timeZoneDirectory = GetTimeZoneDirectory();
string timeZoneFilePath = Path.Combine(timeZoneDirectory, id);
byte[] rawData;
try
{
rawData = File.ReadAllBytes(timeZoneFilePath);
rawData = ReadAllBytesFromSeekableNonZeroSizeFile(timeZoneFilePath, maxFileSize: 20 * 1024 * 1024 /* 20 MB */); // timezone files usually less than 1 MB.
}
catch (UnauthorizedAccessException ex)
{
Expand All @@ -51,7 +117,7 @@ private static TimeZoneInfoResult TryGetTimeZoneFromLocalMachineCore(string id,
e = ex;
return TimeZoneInfoResult.TimeZoneNotFoundException;
}
catch (IOException ex)
catch (Exception ex) when (ex is IOException || ex is OutOfMemoryException)
{
e = new InvalidTimeZoneException(SR.Format(SR.InvalidTimeZone_InvalidFileData, id, timeZoneFilePath), ex);
return TimeZoneInfoResult.InvalidTimeZoneException;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2091,14 +2091,20 @@ public static IEnumerable<object[]> ConvertTime_DateTimeOffset_InvalidDestinatio
yield return new object[] { s_strPacific + "\\Display" };
yield return new object[] { s_strPacific + "\n" }; // no trailing newline
yield return new object[] { new string('a', 100) }; // long string
yield return new object[] { "/dev/random" };
yield return new object[] { "Invalid Id" };
yield return new object[] { "Invalid/Invalid" };
yield return new object[] { $"./{s_strPacific}" };
yield return new object[] { $"{s_strPacific}/../{s_strPacific}" };
}

[Theory]
[MemberData(nameof(ConvertTime_DateTimeOffset_InvalidDestination_TimeZoneNotFoundException_MemberData))]
public static void ConvertTime_DateTimeOffset_InvalidDestination_TimeZoneNotFoundException(string destinationId)
{
DateTimeOffset time1 = new DateTimeOffset(2006, 5, 12, 0, 0, 0, TimeSpan.Zero);
VerifyConvertException<TimeZoneNotFoundException>(time1, destinationId);
Exception ex = Record.Exception(() => TimeZoneInfo.ConvertTime(time1, TimeZoneInfo.FindSystemTimeZoneById(destinationId)));
Assert.True(ex is InvalidTimeZoneException || ex is TimeZoneNotFoundException);
}

[Fact]
Expand Down

0 comments on commit 43bb599

Please sign in to comment.