This is Xamarin's bug tracking system. For product support, please use the support links listed in your Xamarin Account.
Bug 30360 - Error in handling of /etc/localtime file to retrieve time zone on Linux
Summary: Error in handling of /etc/localtime file to retrieve time zone on Linux
Status: NEW
Alias: None
Product: Runtime
Classification: Mono
Component: General (show other bugs)
Version: 4.0.0
Hardware: Other Linux
: --- normal
Target Milestone: ---
Assignee: Bugzilla
URL:
: 30839 (view as bug list)
Depends on:
Blocks:
 
Reported: 2015-05-22 12:04 UTC by Bill Seurer
Modified: 2015-10-29 15:08 UTC (History)
6 users (show)

See Also:
Tags:
Is this bug a regression?: ---
Last known good build:


Attachments

Description Bill Seurer 2015-05-22 12:04:38 UTC
On Linux Mono uses the /etc/localtime file to figure out the time zone.  If appears that if /etc/localtime is an actual file instead of a symbolic link to the file building mono fails with a System.TimeZoneNotFoundException when mdoc is run:

MDOC    [net_4_5] cs-errors.tree
mdoc: System.TimeZoneNotFoundException: Exception of type 'System.TimeZoneNotFoundException' was thrown.
  at System.TimeZoneInfo.get_Local () <0x100003bd0930 + 0x00134> in <filename unknown>:0 
  at System.TimeZoneInfo.GetDateTimeNowUtcOffsetFromUtc (DateTime time, System.Boolean& isAmbiguousLocalDst) <0x100003bd0848 + 0x00038> in <filename unknown>:0 
  at System.DateTime.get_Now () <0x100003bcff98 + 0x00084> in <filename unknown>:0 
  at ICSharpCode.SharpZipLib.Zip.ZipEntry..ctor (System.String name, Int32 versionRequiredToExtract, Int32 madeByInfo) <0x100003bcfcd0 + 0x00088> in <filename unknown>:0 
  at ICSharpCode.SharpZipLib.Zip.ZipEntry..ctor (System.String name) <0x100003bcfbb8 + 0x0003c> in <filename unknown>:0 
  at Monodoc.Storage.ZipStorage.SetupEntry (ICSharpCode.SharpZipLib.Zip.ZipOutputStream zipOutput, System.String& id) <0x100003bcf9d8 + 0x000fc> in <filename unknown>:0 
  at Monodoc.Storage.ZipStorage.Store (System.String id, System.IO.Stream stream) <0x100003bcc808 + 0x00064> in <filename unknown>:0 
  at Monodoc.Providers.ErrorProvider.CloseTree (Monodoc.HelpSource hs, Monodoc.Tree tree) <0x100003ba7f50 + 0x00278> in <filename unknown>:0 
  at Mono.Documentation.MDocAssembler.Run (IEnumerable`1 args) <0x100002c3b0f8 + 0x014c4> in <filename unknown>:0 
  at Mono.Documentation.MDoc.Run (System.String[] args) <0x100002bd4688 + 0x00d64> in <filename unknown>:0 
  at Mono.Documentation.MDoc.Main (System.String[] args) <0x100002bd3af0 + 0x00084> in <filename unknown>:0 

Various test cases also fail with the same exception when doing a make check as well.


If I set the TZ environment variable then everything works OK.  For example this works:

export TZ="/usr/share/zoneinfo/US/Central"


On different Linux varieties /etc/localtime is either an actual file or a symbolic link to a file.  Some varieties require it to be one or the other.  On Ubuntu it is an actual file for instance.  On the Ubuntu system I am using:

seurer@genoa:~/mono-git/mono$ ls -l /etc/localtime
-rw-r--r-- 1 root root 3559 Apr 27 08:16 /etc/localtime

That is an actual file.  It is a copy of another file from the zoneinfo directory tree:

seurer@genoa:~/mono-git/mono$ ls -l /usr/share/zoneinfo/US/Central
-rw-r--r-- 1 root root 3559 Apr 26 17:57 /usr/share/zoneinfo/US/Central

If I compare the two they are the same:

seurer@genoa:~/mono-git/mono$ diff --binary /etc/localtime /usr/share/zoneinfo/US/Central
seurer@genoa:~/mono-git/mono$

Note that this is the same file that worked when I set the TZ environment variable.
Comment 1 Marcin Cieślak 2015-06-04 19:20:22 UTC
It is the same is no /etc/localtime file is present (and no TZ is set) - for the machines that run in the UTC.
Comment 2 Bill Seurer 2015-06-05 10:29:20 UTC
Here is another example when running some compiled code through mono:

seurer@genoa:~/mono-git/mono-ppc64le/mono/tests$ export TZ="/usr/share/zoneinfo/US/Central"
seurer@genoa:~/mono-git/mono-ppc64le/mono/tests$ printenv TZ
/usr/share/zoneinfo/US/Central
seurer@genoa:~/mono-git/mono-ppc64le/mono/tests$ ../mini/mono bug-10127.exe
Starting cache testers
seurer@genoa:~/mono-git/mono-ppc64le/mono/tests$ unset TZ
seurer@genoa:~/mono-git/mono-ppc64le/mono/tests$ ../mini/mono bug-10127.exe
Starting cache testers

Unhandled Exception:
System.TypeInitializationException: The type initializer for 'WeakReferenceTest.Tester' threw an exception. ---> System.TimeZoneNotFoundException: Exception of type 'System.TimeZoneNotFoundException' was thrown.
  at System.TimeZoneInfo.get_Local () <0x3fffad26b738 + 0x00134> in <filename unknown>:0 
  at System.TimeZoneInfo.GetDateTimeNowUtcOffsetFromUtc (DateTime time, System.Boolean& isAmbiguousLocalDst) <0x3fffad26b650 + 0x00038> in <filename unknown>:0 
  at System.DateTime.get_Now () <0x3fffad26ad40 + 0x00084> in <filename unknown>:0 
  at WeakReferenceTest.Tester..cctor () <0x3fffad26ac50 + 0x00030> in <filename unknown>:0 
  --- End of inner exception stack trace ---
  at WeakReferenceTest.MainClass.Main (System.String[] args) <0x3fffad243ac0 + 0x00128> in <filename unknown>:0 
[ERROR] FATAL UNHANDLED EXCEPTION: System.TypeInitializationException: The type initializer for 'WeakReferenceTest.Tester' threw an exception. ---> System.TimeZoneNotFoundException: Exception of type 'System.TimeZoneNotFoundException' was thrown.
  at System.TimeZoneInfo.get_Local () <0x3fffad26b738 + 0x00134> in <filename unknown>:0 
  at System.TimeZoneInfo.GetDateTimeNowUtcOffsetFromUtc (DateTime time, System.Boolean& isAmbiguousLocalDst) <0x3fffad26b650 + 0x00038> in <filename unknown>:0 
  at System.DateTime.get_Now () <0x3fffad26ad40 + 0x00084> in <filename unknown>:0 
  at WeakReferenceTest.Tester..cctor () <0x3fffad26ac50 + 0x00030> in <filename unknown>:0 
  --- End of inner exception stack trace ---
  at WeakReferenceTest.MainClass.Main (System.String[] args) <0x3fffad243ac0 + 0x00128> in <filename unknown>:0
Comment 3 Jo Shields 2015-06-05 10:29:27 UTC
*** Bug 30839 has been marked as a duplicate of this bug. ***
Comment 4 Marcin Cieślak 2015-06-05 16:21:45 UTC
line 123 of mcs/class/corlib/System/TimeZoneInfo.cs

should be changed to "return Utc;" instead of "return null;"

or maybe better:

one could differentiate between InvalidTimeZoneException being thrown from BuildFromStream() and plain TimeZoneNotFoundException from FindSystemTimeZoneByFileName() which should just "return Utc" in line 485 instead of throwing an exception
Comment 5 Marcin Cieślak 2015-06-07 17:49:46 UTC
I'd like to propose a fix:

https://github.com/mono/mono/pull/1860
Comment 6 Jo Shields 2015-06-08 03:18:56 UTC
(In reply to comment #5)
> I'd like to propose a fix:
> 
> https://github.com/mono/mono/pull/1860

This is a workaround for the issue at hand (and not necessarily wrong) - but given the issue here only happens on ppc64el, on systems with a valid /etc/localtime, then there are other problems to consider
Comment 7 Marcin Cieślak 2015-06-08 03:22:56 UTC
Can you test this patch on ppc64? I have had this on x64 FreeBSD, pretty standard setup when no timezone is set.
Comment 8 Marcin Cieślak 2015-06-08 04:20:41 UTC
I cannot reproduce the original report (using this simple code):

----------------
using System;
namespace timezoneinforepro1
{
    class Program
    {
        static void Main(string[] args)
        {
            DateTime now = DateTime.Now;
            Console.WriteLine("It is now: " + now);
        }
    }
}
----------------

Having https://github.com/mono/mono/pull/1860 applied and no $TZ set I get the current date and time printed correctly, regardless whether /etc/localtime is a copy of the timezone data or a symbolic link.
Comment 9 Bill Seurer 2015-08-10 17:16:43 UTC
A couple of notes:

The problem is not that the time zone files do not exist.  They do exist.

In ParseTransitions in TimeZoneInfo.cs when this line

   var list = new List<KeyValuePair<DateTime, TimeType>> (count);

is hit it throws this exception:

System.OverflowException: Arithmetic operation resulted in an overflow.
  at (wrapper alloc) System.Object:AllocVector (intptr,intptr)
  at System.Collections.Generic.List`1[T]..ctor (Int32 capacity) <0x3fffb1f78028 + 0x000c4> in <filename unknown>:0 
  at System.TimeZoneInfo.ParseTransitions (System.Byte[] buffer, Int32 index, Int32 count, System.Collections.Generic.Dictionary`2 time_types) <0x3fffb1f77c20 + 0x00104> in <filename unknown>:0 .

"count" is 235 here.

When an exception is thrown here it is caught all the way back in CreateLocal().  This occurs whether the TZ env var is set or not.  

But note the difference in what happens when the exception is caught.  When TZ is set the exception causes "Utc" to be returned.  When TZ is not set then null is returned which then causes some code further upstream to throw the System.TimeZoneNotFoundException.


From CreateLocal in TimeZoneInfo.cs:
			var tz = Environment.GetEnvironmentVariable ("TZ");
			if (tz != null) {
				if (tz == String.Empty)
					return Utc;
				try {
					return FindSystemTimeZoneByFileName (tz, Path.Combine (TimeZoneDirectory, tz));
				} catch {
					return Utc;
				}
			}

			try {
				return FindSystemTimeZoneByFileName ("Local", "/etc/localtime");	
			} catch {
				try {
					return FindSystemTimeZoneByFileName ("Local", Path.Combine (TimeZoneDirectory, "localtime"));	
				} catch {
					return null;
				}
			}
Comment 10 Marcin Cieślak 2015-08-10 17:25:47 UTC
So the latter problem (catching the exception) has been fixed in

https://github.com/saper/mono/commit/cf4e7339e31d19e6934d7b8130f82697212ea39e

(now in Mono git master) - see the discussion related to this bug in https://github.com/mono/mono/pull/1860

The exception should be propagated correctly.

No idea about the collections bug though. Can you publish your timezone files somewhere so that someone may try to reproduce it?
Comment 11 Bill Seurer 2015-08-10 17:30:47 UTC
As an experiment I changed that line in ParseTransitions to not provide an initial element count for the call to "new List".  Without the count the code properly reads the timezone file and works just fine.

So I'd say there is some issue in the List constructor.

The timezone files do not appear to have anything to do with it but are the standard ones that come with Ubuntu 14.04.
Comment 12 Marcin Cieślak 2015-08-10 17:37:01 UTC
Just wondering, can you reproduce it with a minimal C# test case? It might be worth filling a dedicated bug.

Is this running on PPC64? Do you see this issue on any other platform?

(re files: sorry no Ubuntu here, running FreeBSD :)
Comment 13 Bill Seurer 2015-08-10 19:07:37 UTC
The following will reproduce it.  I am on a power LE system but will try on a power BE system and see what happens.

using System;

public class Test
{

	public static int Main (String[] args) {
		TimeZoneInfo tzinfo = TimeZoneInfo.Local;
		return 0;
	}
}
Comment 14 Marcin Cieślak 2015-08-10 19:12:12 UTC
Any chance to reproduce it with 

   var list = new List<KeyValuePair<DateTime, TimeType>> (count);

instead? 

Not sure how large those DateTime and TimeType should be to reproduce though.
Comment 15 Bill Seurer 2015-08-11 10:56:09 UTC
I tried the following but that worked (though I had to copy TimeType locally).  I will look into List to see where the exception is coming from.

	public static int Main (String[] args) {
		int count=235;
		var list = new List<KeyValuePair<DateTime, TimeType>> (count);
//		TimeZoneInfo tzinfo = TimeZoneInfo.Local;
		return 0;
	}
Comment 16 Marcin Cieślak 2015-08-11 11:00:45 UTC
Another additional idea: can you run it under gdb and dump a disassembly of around the place where it crashes? Long time I have read PowerPC code but maybe some JIT developers could jump in.
Comment 17 Bill Seurer 2015-08-12 10:47:19 UTC
What appears to be happening is that the code generated by create_allocator from sgen-mono.c is signaling the overflow exception.  If you look around line 1145 (in my copy) there's some code with this comment:

		/*
		 * n > MONO_ARRAY_MAX_INDEX => OutOfMemoryException
		 * n < 0                    => OverflowException
		 *
		 * We can do an unsigned comparison to catch both cases, then in the error
		 * case compare signed to distinguish between them.
		 */

A little ways down you an see where it checks for the overflow.  I am going to try to catch this in the debugger in the actual generated code to see if I can figure out what is going haywire here.
Comment 18 Bill Seurer 2015-08-12 12:41:43 UTC
When it gets into the actual allocation code one of the parms has been corrupted.

(gdb) print mono_pmip($pc)
$16 = 0x1089c650 " (wrapper alloc) object:AllocVector (intptr,intptr) + 0x0 (0x3fffb5645270 0x3fffb56454c8) [0x10563e50 - hello.exe]"

(gdb) print/x $r4
$20 = 0xffeb0000000000eb

Register 4 should have 235 in it which is the number of elements being allocated.  0xeb is 235 but something either overwrote part of or more likely didn't properly save/restore the register along the way.  0xffeb0000000000eb has the sign bit set and so looks negative to the code that I mentioned above.  I stepped all the way through the call sequence so I should be able to find the problem spot.
Comment 19 Bill Seurer 2015-08-12 17:13:42 UTC
The problem is not in the count parameter but in how AllocVector treats it.  The parameter is an int (32 bits) and so word instructions are used to manipulate it up to the point where it is in AllocVector.  AllocVector generates doubleword (64 bit) instructions while using word operands without converting them to doublewords first.

I changed the code in List.cs to convert the integer (32 bit) capacity parameter it uses to a long (64 bit) before it allocates the array.  Then AllocVector works OK and the timezone problem vanishes.  This is just a workaround to the actual problem in AllocVector of course.

This probably causes problems elsewhere but here the leftover bits in the upper (unused) part of the parameter register just happened to trigger the exception and so it was caught.
Comment 20 Bill Seurer 2015-08-13 14:43:10 UTC
Working on this some more I found the ultimate problem.

When the timezone information is read from the file in TimeZoneInfo.cs it is mishandling a big-endian little-endian int32 on a 64-bit platform conversion.

In this case ParseTZBuffer is trying to read an int32 from the file (actually, a buffer read from the file).  At offset 32 the buffer contains 0xeb000000, i.e., 235.

int timecnt = ReadBigEndianInt32 (buffer, 32);

ReadBigEndianInt32 calls BitConverter.ToInt32 which reads the value into a register as 0xffffffffeb000000 because it generates a load with sign extension on the buffer containing 0xeb000000.

Then because this is little endian it calls SwapInt32.

		static int SwapInt32 (int i)
		{
			return (((i >> 24) & 0xff)
				| ((i >> 8) & 0xff00)
				| ((i << 8) & 0xff0000)
				| ((i << 24)));
		}

The "i<<24" is the problem spot which produces "0xffeb000000000000" in this case.  When put together with the rest it comes out as 0xffeb0000000000eb.  That value if it was stored would actually be OK (a store word will ignore the upper 4 bytes) but if it stays in registers it causes problems.  Mono manages to keep this value in registers the whole time it is being used.

I believe that changing SwapInt32 to the following will fix that:

		static int SwapInt32 (int i)
		{
			return (((i >> 24) & 0xff)
				| ((i >> 8) & 0xff00)
				| ((i << 8) & 0xff0000)
				| (((i & 0xff) << 24)));
		}
Comment 21 Marcin Cieślak 2015-08-13 15:23:54 UTC
Bill,

reads like a good book.

I wonder if this is a problem also on other big-endian platforms!
Comment 22 Bill Seurer 2015-08-13 15:37:27 UTC
Heh.  I like to put some details in so that if anyone else is looking at something similar they can get a head start in figuring out what is wrong.

As for other architectures it depends on what instruction(s) they generate for this line in bitconverter.cs

                    return *((int *) pbyte);

Power generates a load-with-sign-extension (actually an "lwa") and anything similar would probably have similar problems all else being equal.
Comment 23 Marcin Cieślak 2015-08-13 16:05:28 UTC
What happens if you change "int" to "uint" and BitConverter.Int32 (and maybe Int16 as well) to UInt32?

No wonder it's told to use lwa instead of lwz
Comment 24 Bill Seurer 2015-08-13 17:38:04 UTC
The timezone file description says:

"Six four-byte values of type long, written in a "standard" byte
order (the high-order byte of the value is written first)."

The values are all counts of one sort of another but given the type in theory they could be negative.
Comment 25 Marcin Cieślak 2015-08-13 17:51:11 UTC
I think that number of items is unsigned. Maybe SwapUInt32 (the "new" one) should have an additional & 0xFFFFFFFF in the end?
Comment 26 Marcin Cieślak 2015-08-13 17:54:02 UTC
And yet, SwapInt32 (signed) is too simplistic - shouldn't it try harder to preserve the sign?
Comment 27 Marcin Cieślak 2015-08-13 19:45:00 UTC
....scratch the last one... from the quick look around nobody is doing "signed" byte order transfomation - it makes no sense.... what should be done is probably always to have uint transformation and then cast signed values to int where necessary.
Comment 28 Bill Seurer 2015-08-14 10:34:31 UTC
Yeah, that code is messed up and does not actually handle signed numbers properly.

I may just fix it for now so it works and add a FIXME to clean it up properly later.
Comment 29 Marcin Cieślak 2015-08-16 15:40:01 UTC
Bill,

I have converted most of the values to unsigned ints.

From my reading of the tzfile(5) manpage[1] it seems
that only the timezone offset is signed long to indicate
west/east GMT offsets.

This one gets an explicit conversion.

Does this:

    https://github.com/mono/mono/pull/1982

fix the issue for you?

[1] http://www.freebsd.org/cgi/man.cgi?query=tzfile&apropos=0&sektion=5&manpath=FreeBSD+10.2-RELEASE&arch=default&format=html
Comment 30 Bill Seurer 2015-09-03 16:09:11 UTC
Marcin, did you ever get your changes to use unsigned ints to fully work?  This is still failing for me with code I just checked out.
Comment 31 Marcin Cieślak 2015-09-03 16:29:17 UTC
There is something strange about https://github.com/mono/mono/pull/1982 

Original (unchanged) code fails tests on my FreeBSD system for few reasons,
one is some tests assuming UTC cannot be "local" time :) https://bugzilla.xamarin.com/show_bug.cgi?id=33471

but most importantly attempts to read timezone files fail with:

14) MonoTests.System.TimeZoneInfoTest+FindSystemTimeZoneByIdTests.BrusselsSupportsDST : System.InvalidTimeZoneException : Index (zero based) must be greater than or equal to zero and less than the size of the argument list.
at System.TimeZoneInfo.BuildFromStream (System.String id, System.IO.Stream stream) [0x0003f] in /home/saper/sw/mono/mcs/class/corlib/System/TimeZoneInfo.cs:1153
at System.TimeZoneInfo.FindSystemTimeZoneByFileName (System.String id, System.String filepath) [0x00018] in /home/saper/sw/mono/mcs/class/corlib/System/TimeZoneInfo.cs:488
at System.TimeZoneInfo.FindSystemTimeZoneByIdCore (System.String id) [0x0000c] in /home/saper/sw/mono/mcs/class/corlib/System/TimeZoneInfo.cs:132
at System.TimeZoneInfo.FindSystemTimeZoneById (System.String id) [0x00069] in /home/saper/sw/mono/mcs/class/corlib/System/TimeZoneInfo.cs:478
at MonoTests.System.TimeZoneInfoTest+FindSystemTimeZoneByIdTests.BrusselsSupportsDST () [0x0001a] in /home/saper/sw/mono/mcs/class/corlib/Test/System/TimeZoneInfoTest.cs:755
at (wrapper managed-to-native) System.Reflection.MonoMethod:InternalInvoke (System.Reflection.MonoMethod,object,object[],System.Exception&)
at System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x00038] in /home/saper/sw/mono/mcs/class/corlib/System.Reflection/MonoMethod.cs:295


which indicates something is wrong with converting integers on my amd64 FreeBSD system as it stands now.

After my patch those errors are gone, but I start getting:

System.InvalidTimeZoneException: adjustment rules specified in adjustmentRules parameter are not in chronological order

Assuming zdump is doing it in order stored:


Europe/Brussels  Sun Jan  0 00:00:00 1900 UTC = Sun Jan  0 00:00:00 1900 LMT isdst=0 gmtoff=0
Europe/Brussels  Sun Jan  0 00:00:00 1900 UTC = Sun Jan  0 00:00:00 1900 LMT isdst=0 gmtoff=0
Europe/Brussels  Wed Dec 31 23:42:29 1879 UTC = Wed Dec 31 23:59:59 1879 LMT isdst=0 gmtoff=1050
Europe/Brussels  Wed Dec 31 23:42:30 1879 UTC = Thu Jan  1 00:00:00 1880 BMT isdst=0 gmtoff=1050
Europe/Brussels  Sun May  1 11:42:29 1892 UTC = Sun May  1 11:59:59 1892 BMT isdst=0 gmtoff=1050
Europe/Brussels  Sun May  1 11:42:30 1892 UTC = Sun May  1 11:42:30 1892 WET isdst=0 gmtoff=0
Europe/Brussels  Sat Nov  7 23:59:59 1914 UTC = Sat Nov  7 23:59:59 1914 WET isdst=0 gmtoff=0
Europe/Brussels  Sun Nov  8 00:00:00 1914 UTC = Sun Nov  8 01:00:00 1914 CET isdst=0 gmtoff=3600

... then indeed adjustmentRules are not sorted in the file and the assumption in the code is wrong.
Comment 32 Marcin Cieślak 2015-09-03 16:43:48 UTC
Bill, 

What failures are you seeing after applying the patch?
Comment 33 Bill Seurer 2015-09-04 10:11:09 UTC
I initially didn't try it after I saw you were having problems.  I have been checking in some other fixes and just noticed that the timezone problem was still there so I wondered if you were still working on your fix.

I just tried with your change and there were 30-some test case failures.  I ran one by hand and it got:

Unhandled Exception:
System.InvalidTimeZoneException: Arithmetic operation resulted in an overflow.
  at System.TimeZoneInfo.BuildFromStream (System.String id, System.IO.Stream stream) <0x3fffb57dc1f0 + 0x00140> in <filename unknown>:0 
  at System.TimeZoneInfo.FindSystemTimeZoneByFileName (System.String id, System.String filepath) <0x3fffb57d7b78 + 0x00090> in <filename unknown>:0 
  at System.TimeZoneInfo.CreateLocal () <0x3fffb57b67a8 + 0x004b8> in <filename unknown>:0 
  at System.TimeZoneInfo.get_Local () <0x3fffb57b6630 + 0x00040> in <filename unknown>:0 
  at System.TimeZoneInfo.GetDateTimeNowUtcOffsetFromUtc (DateTime time, System.Boolean& isAmbiguousLocalDst) <0x3fffb57b6548 + 0x00038> in <filename unknown>:0 
  at System.DateTime.get_Now () <0x3fffb57b56f8 + 0x00084> in <filename unknown>

...etc...
Comment 34 Marcin Cieślak 2015-09-04 10:17:51 UTC
Would be great to have a mono --debug output with a full stacktrace (with filenames and line numbers)...
Comment 35 Bill Seurer 2015-09-04 10:43:44 UTC
The full trace is this.  It doesn't help all that much because an earlier exception is being caught and re-rethrown:


seurer@genoa:~/mono-git/mono-checkin/mono/tests$ MONO_PATH="/home/seurer/mono-git/mono-checkin/mcs/class/lib/net_4_x" MONO_CFG_DIR=/home/seurer/mono-git/mono-checkin/runtime/etc /home/seurer/mono-git/mono-checkin/mono/mini/mono --debug --config /home/seurer/mono-git/mono-checkin/runtime/etc/mono/config loader.exe

Unhandled Exception:
System.InvalidTimeZoneException: Arithmetic operation resulted in an overflow.
  at System.TimeZoneInfo.BuildFromStream (System.String id, System.IO.Stream stream) [0x0003f] in /home/seurer/mono-git/mono-checkin/mcs/class/corlib/System/TimeZoneInfo.cs:1213 
  at System.TimeZoneInfo.FindSystemTimeZoneByFileName (System.String id, System.String filepath) [0x00018] in /home/seurer/mono-git/mono-checkin/mcs/class/corlib/System/TimeZoneInfo.cs:548 
  at System.TimeZoneInfo.CreateLocal () [0x000ed] in /home/seurer/mono-git/mono-checkin/mcs/class/corlib/System/TimeZoneInfo.cs:179 
  at System.TimeZoneInfo.get_Local () [0x0000c] in /home/seurer/mono-git/mono-checkin/mcs/class/corlib/System/TimeZoneInfo.cs:76 
  at System.TimeZoneInfo.GetDateTimeNowUtcOffsetFromUtc (DateTime time, System.Boolean& isAmbiguousLocalDst) [0x00000] in /home/seurer/mono-git/mono-checkin/mcs/class/corlib/System/TimeZoneInfo.cs:487 
  at System.DateTime.get_Now () [0x00008] in /home/seurer/mono-git/mono-checkin/external/referencesource/mscorlib/system/datetime.cs:950 
  at TestDriver.RunTests (System.Type type, System.String[] args) [0x00011] in /home/seurer/mono-git/mono-checkin/mono/mini/TestDriver.cs:29 
  at Tests.Main (System.String[] args) [0x0000c] in /home/seurer/mono-git/mono-checkin/mono/tests/loader.cs:15 
[ERROR] FATAL UNHANDLED EXCEPTION: System.InvalidTimeZoneException: Arithmetic operation resulted in an overflow.
  at System.TimeZoneInfo.BuildFromStream (System.String id, System.IO.Stream stream) [0x0003f] in /home/seurer/mono-git/mono-checkin/mcs/class/corlib/System/TimeZoneInfo.cs:1213 
  at System.TimeZoneInfo.FindSystemTimeZoneByFileName (System.String id, System.String filepath) [0x00018] in /home/seurer/mono-git/mono-checkin/mcs/class/corlib/System/TimeZoneInfo.cs:548 
  at System.TimeZoneInfo.CreateLocal () [0x000ed] in /home/seurer/mono-git/mono-checkin/mcs/class/corlib/System/TimeZoneInfo.cs:179 
  at System.TimeZoneInfo.get_Local () [0x0000c] in /home/seurer/mono-git/mono-checkin/mcs/class/corlib/System/TimeZoneInfo.cs:76 
  at System.TimeZoneInfo.GetDateTimeNowUtcOffsetFromUtc (DateTime time, System.Boolean& isAmbiguousLocalDst) [0x00000] in /home/seurer/mono-git/mono-checkin/mcs/class/corlib/System/TimeZoneInfo.cs:487 
  at System.DateTime.get_Now () [0x00008] in /home/seurer/mono-git/mono-checkin/external/referencesource/mscorlib/system/datetime.cs:950 
  at TestDriver.RunTests (System.Type type, System.String[] args) [0x00011] in /home/seurer/mono-git/mono-checkin/mono/mini/TestDriver.cs:29 
  at Tests.Main (System.String[] args) [0x0000c] in /home/seurer/mono-git/mono-checkin/mono/tests/loader.cs:15
Comment 36 Bill Seurer 2015-09-04 11:11:33 UTC
I commented out the rethrow and the error is coming from here:


		static List<KeyValuePair<DateTime, TimeType>> ParseTransitions (byte [] buffer, uint index, uint count, Dictionary<uint, TimeType> time_types)
		{
			var list = new List<KeyValuePair<DateTime, TimeType>> ((int)count);   // Line 1409


which is called from here 

		private static TimeZoneInfo ParseTZBuffer (string id, byte [] buffer, int length)
		{
. . .
			uint timecnt = ReadBigEndianUInt32 (buffer, 32);

. . .
			List<KeyValuePair<DateTime, TimeType>> transitions = ParseTransitions (buffer, 44, timecnt, time_types);  // Line 1270

timecnt is (as expected) 235.


[ERROR] FATAL UNHANDLED EXCEPTION: System.OverflowException: Arithmetic operation resulted in an overflow.
  at (wrapper alloc) System.Object:AllocVector (intptr,intptr)
  at System.Collections.Generic.List`1[T]..ctor (Int32 capacity) [0x0001b] in /home/seurer/mono-git/mono-checkin/external/referencesource/mscorlib/system/collections/generic/list.cs:71 
  at System.TimeZoneInfo.ParseTransitions (System.Byte[] buffer, UInt32 index, UInt32 count, System.Collections.Generic.Dictionary`2 time_types) [0x00000] in /home/seurer/mono-git/mono-checkin/mcs/class/corlib/System/TimeZoneInfo.cs:1409 
  at System.TimeZoneInfo.ParseTZBuffer (System.String id, System.Byte[] buffer, Int32 length) [0x00087] in /home/seurer/mono-git/mono-checkin/mcs/class/corlib/System/TimeZoneInfo.cs:1270 
  at System.TimeZoneInfo.BuildFromStream (System.String id, System.IO.Stream stream) [0x00030] in /home/seurer/mono-git/mono-checkin/mcs/class/corlib/System/TimeZoneInfo.cs:1211 
  at System.TimeZoneInfo.FindSystemTimeZoneByFileName (System.String id, System.String filepath) [0x00018] in /home/seurer/mono-git/mono-checkin/mcs/class/corlib/System/TimeZoneInfo.cs:548 
...etc...
Comment 37 Bill Seurer 2015-09-04 11:24:09 UTC
I looked through the generated code and this unit code has the same problem with registers that the int code did.  When mono manages to keep everything in registers the shift code:

		static uint SwapUInt32 (uint i)
		{
			return (((i >> 24) & 0xff)
				| ((i >> 8) & 0xff00)
				| ((i << 8) & 0xff0000)
				| ((i << 24)));
		}


once again ends up with some stuff in the upper parts of the 64 bit register.  This may be a problem in code gen (perhaps a missing mask operation somewhere?) but can easily be solved by changes the last left shift to:

				| (((i & 0xff) << 24)));

Hmmm.  Looking at what ToUint32 does in bitconverter.cs it just does this:

            return (uint)ToInt32(value, startIndex);

I am not sure about C# but in C code that is problematic in this sort of situation.  The cast probably doesn't actually generate any code and thus using ToUInt32 has exactly the same issue that ToInt32 does.
Comment 38 Bill Seurer 2015-09-24 10:18:21 UTC
I pushed a change and created a pull request to fix the problem in SwapInt32.

https://github.com/mono/mono/pull/2045

That will take care of the immediate issue but I think that changing everything to unsigned (where appropriate) is better.
Comment 39 Marcin Cieślak 2015-10-29 14:42:38 UTC
One question Bill, what does BitConverter.IsLittleEndian return for your platform?
Comment 40 Bill Seurer 2015-10-29 15:08:23 UTC
I tried the little test program here:

https://msdn.microsoft.com/en-us/library/system.bitconverter.islittleendian%28v=vs.110%29.aspx

And it reported:

IsLittleEndian:  True

Note You need to log in before you can comment on or make changes to this bug.