By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
440,304 Members | 3,172 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 440,304 IT Pros & Developers. It's quick & easy.

Nasty bug in the C# compiler, it truncates values on the stack

P: n/a
I managed to narrow this down to a very simple expression. try this:

private void Bug()
{
bool b = false;
Test(3, (b || b) && b && !b);
}

private void Works()
{
bool b = true;
Test(3, (b || b) && b && !b);
}

private void Test(decimal v, bool b)
{
MessageBox.Show(v.ToString());
}

The value of the argument v in Test() is 0!

If you change the function Bug() and make bool b = true it works fine. I
checked the MSIL code and it appears that the compiler chocked on the
expression "(b || b) && b && !b" and silently truncated the previous
argument to bool (1 byte). Since the argument is a decimal it will show zero
because the truncation occurs on the decimal structure.

You can try this with any struct and any value as the first argument, the
compiler will always truncate the struct on the stack to 1 byte. If you try
with your own struct you will lose all the data after the first byte.

Strangely enough, if you remove the parenthesis "b || b && b && !b" is works
fine.

Plese don't focus on the expression, it's a simplification of a real
expression. The nastiest part is that there is no compiler error or warning,
it simply generates wrong MSIL code.

Is this a known bug? If not, how do I report this to Microsoft and to the
..NET team?

I tried in the past to report a bug with the shortcircuit operators specs
and compiler but didn't suceeded and the defect is still there.

I also tried with the latest service pack, the version shown in the .NET
Configuration module is version 1.1.4322.573.
Nov 17 '05 #1
Share this Question
Share on Google+
19 Replies


P: n/a

"Jerry" <je**********@yandex.ru> wrote in message
news:q68ee.10$fQ2.2@trnddc05...
I managed to narrow this down to a very simple expression. try this:

private void Bug()
{
bool b = false;
Test(3, (b || b) && b && !b);
}

private void Works()
{
bool b = true;
Test(3, (b || b) && b && !b);
}

private void Test(decimal v, bool b)
{
MessageBox.Show(v.ToString());
}

The value of the argument v in Test() is 0!

If you change the function Bug() and make bool b = true it works fine. I
checked the MSIL code and it appears that the compiler chocked on the
expression "(b || b) && b && !b" and silently truncated the previous
argument to bool (1 byte). Since the argument is a decimal it will show
zero
because the truncation occurs on the decimal structure.

You can try this with any struct and any value as the first argument, the
compiler will always truncate the struct on the stack to 1 byte. If you
try
with your own struct you will lose all the data after the first byte.

Strangely enough, if you remove the parenthesis "b || b && b && !b" is
works
fine.

Plese don't focus on the expression, it's a simplification of a real
expression. The nastiest part is that there is no compiler error or
warning,
it simply generates wrong MSIL code.

Is this a known bug? If not, how do I report this to Microsoft and to the
.NET team?

I tried in the past to report a bug with the shortcircuit operators specs
and compiler but didn't suceeded and the defect is still there.

I also tried with the latest service pack, the version shown in the .NET
Configuration module is version 1.1.4322.573.


Yep, looks like a bug.

You can report bugs/issues to
http://lab.msdn.microsoft.com/produc...k/default.aspx

Willy.
Nov 17 '05 #2

P: n/a
Might I suggest that this gets escalated to the C# guys via our internal
route too..

--
Bob Powell [MVP]
Visual C#, System.Drawing

Find great Windows Forms articles in Windows Forms Tips and Tricks
http://www.bobpowell.net/tipstricks.htm

Answer those GDI+ questions with the GDI+ FAQ
http://www.bobpowell.net/faqmain.htm

All new articles provide code in C# and VB.NET.
Subscribe to the RSS feeds provided and never miss a new article.

"Willy Denoyette [MVP]" <wi*************@telenet.be> wrote in message
news:%2******************@TK2MSFTNGP15.phx.gbl...

"Jerry" <je**********@yandex.ru> wrote in message
news:q68ee.10$fQ2.2@trnddc05...
I managed to narrow this down to a very simple expression. try this:

private void Bug()
{
bool b = false;
Test(3, (b || b) && b && !b);
}

private void Works()
{
bool b = true;
Test(3, (b || b) && b && !b);
}

private void Test(decimal v, bool b)
{
MessageBox.Show(v.ToString());
}

The value of the argument v in Test() is 0!

If you change the function Bug() and make bool b = true it works fine. I
checked the MSIL code and it appears that the compiler chocked on the
expression "(b || b) && b && !b" and silently truncated the previous
argument to bool (1 byte). Since the argument is a decimal it will show
zero
because the truncation occurs on the decimal structure.

You can try this with any struct and any value as the first argument, the
compiler will always truncate the struct on the stack to 1 byte. If you
try
with your own struct you will lose all the data after the first byte.

Strangely enough, if you remove the parenthesis "b || b && b && !b" is
works
fine.

Plese don't focus on the expression, it's a simplification of a real
expression. The nastiest part is that there is no compiler error or
warning,
it simply generates wrong MSIL code.

Is this a known bug? If not, how do I report this to Microsoft and to the
.NET team?

I tried in the past to report a bug with the shortcircuit operators specs
and compiler but didn't suceeded and the defect is still there.

I also tried with the latest service pack, the version shown in the .NET
Configuration module is version 1.1.4322.573.


Yep, looks like a bug.

You can report bugs/issues to
http://lab.msdn.microsoft.com/produc...k/default.aspx

Willy.

Nov 17 '05 #3

P: n/a
Plese don't focus on the expression, it's a simplification of a real
expression. The nastiest part is that there is no compiler error or
warning,
it simply generates wrong MSIL code.

What did you find wrong with the MSIL? I can't see a specific problem with
it(Manual trace doesn't cause a truncation that I can see). Are you sure
this is the C# compiler and not the JIT?

Is this a known bug? If not, how do I report this to Microsoft and to the
.NET team?

I tried in the past to report a bug with the shortcircuit operators specs
and compiler but didn't suceeded and the defect is still there.

I also tried with the latest service pack, the version shown in the .NET
Configuration module is version 1.1.4322.573.

Nov 17 '05 #4

P: n/a

"Bob Powell [MVP]" <bob@_spamkiller_bobpowell.net> wrote in message
news:Op**************@TK2MSFTNGP14.phx.gbl...
Might I suggest that this gets escalated to the C# guys via our internal
route too..

--
Bob Powell [MVP]
Visual C#, System.Drawing


Done.

Willy.
Nov 17 '05 #5

P: n/a
No, you are right. I was looking at a bool cast that my code applies. I was
checking the MSIL from the original code and it's more complex that the
sample expression. I just checked the MSIL from the test code and there is
no visible difference (other than the assigment) between the b = false (bug)
and the b = true (no bug) calls. Looking at the MSIL below is it possible
that when L_0019 is reached the first argument on the stack has been
truncated?

How can it be the JIT if the same code works when b = true?

// Code Size: 31 byte(s)
.maxstack 4
.locals (
bool flag1)
L_0000: ldc.i4.0 <---- when this is ldc.i4.1 the code works OK.
L_0001: stloc.0
L_0002: ldarg.0
L_0003: ldc.i4.3
L_0004: newobj instance void [mscorlib]System.Decimal::.ctor(int32)
L_0009: ldloc.0
L_000a: brtrue.s L_000f
L_000c: ldloc.0
L_000d: brfalse.s L_0018
L_000f: ldloc.0
L_0010: brfalse.s L_0018
L_0012: ldloc.0
L_0013: ldc.i4.0
L_0014: ceq
L_0016: br.s L_0019
L_0018: ldc.i4.0
L_0019: call instance void
CSCompilerBug.Form1::Test([mscorlib]System.Decimal, bool)
L_001e: ret

"Daniel O'Connell [C# MVP]" <onyxkirx@--NOSPAM--comcast.net> wrote in
message news:uv**************@TK2MSFTNGP15.phx.gbl...
Plese don't focus on the expression, it's a simplification of a real
expression. The nastiest part is that there is no compiler error or
warning,
it simply generates wrong MSIL code.


What did you find wrong with the MSIL? I can't see a specific problem with
it(Manual trace doesn't cause a truncation that I can see). Are you sure
this is the C# compiler and not the JIT?

Is this a known bug? If not, how do I report this to Microsoft and to the .NET team?

I tried in the past to report a bug with the shortcircuit operators specs and compiler but didn't suceeded and the defect is still there.

I also tried with the latest service pack, the version shown in the .NET
Configuration module is version 1.1.4322.573.


Nov 17 '05 #6

P: n/a

"Gianluca" <gi******@nospam.com> wrote in message
news:uX8ee.26042$lZ.22675@trnddc04...
No, you are right. I was looking at a bool cast that my code applies. I
was
checking the MSIL from the original code and it's more complex that the
sample expression. I just checked the MSIL from the test code and there
is
no visible difference (other than the assigment) between the b = false
(bug)
and the b = true (no bug) calls. Looking at the MSIL below is it possible
that when L_0019 is reached the first argument on the stack has been
truncated?

How can it be the JIT if the same code works when b = true?


I would guess its an optimization bug where the JIT spits out code based on
a stack value it already knows(its possible to determine what code will
execute statically after all), but the bug could just be somewhere on the
path that is followed when the boolean is false.

Has anyone tested this on any of the 2.0 betas?
Nov 17 '05 #7

P: n/a
>Has anyone tested this on any of the 2.0 betas?

I can't repro with beta 2.

Mattias

--
Mattias Sjögren [MVP] mattias @ mvps.org
http://www.msjogren.net/dotnet/ | http://www.dotnetinterop.com
Please reply only to the newsgroup.
Nov 17 '05 #8

P: n/a

"Daniel O'Connell [C# MVP]" <onyxkirx@--NOSPAM--comcast.net> wrote in
message news:OS*************@TK2MSFTNGP09.phx.gbl...

"Gianluca" <gi******@nospam.com> wrote in message
news:uX8ee.26042$lZ.22675@trnddc04...
No, you are right. I was looking at a bool cast that my code applies. I
was
checking the MSIL from the original code and it's more complex that the
sample expression. I just checked the MSIL from the test code and there
is
no visible difference (other than the assigment) between the b = false
(bug)
and the b = true (no bug) calls. Looking at the MSIL below is it possible
that when L_0019 is reached the first argument on the stack has been
truncated?

How can it be the JIT if the same code works when b = true?


I would guess its an optimization bug where the JIT spits out code based
on a stack value it already knows(its possible to determine what code will
execute statically after all), but the bug could just be somewhere on the
path that is followed when the boolean is false.

Has anyone tested this on any of the 2.0 betas?


Works as expected in v2.0 Beta2.

Willy.
Nov 17 '05 #9

P: n/a
it sounds strange, it doesn't work even if the value of be is not knows at
compile time. also the same code works when b is true. I don't think the JIT
regenerates code in the fly. it would be interesting to dissassemble and
see.
"Daniel O'Connell [C# MVP]" <onyxkirx@--NOSPAM--comcast.net> wrote in
message news:OS*************@TK2MSFTNGP09.phx.gbl...

"Gianluca" <gi******@nospam.com> wrote in message
news:uX8ee.26042$lZ.22675@trnddc04...
No, you are right. I was looking at a bool cast that my code applies. I
was
checking the MSIL from the original code and it's more complex that the
sample expression. I just checked the MSIL from the test code and there
is
no visible difference (other than the assigment) between the b = false
(bug)
and the b = true (no bug) calls. Looking at the MSIL below is it possible that when L_0019 is reached the first argument on the stack has been
truncated?

How can it be the JIT if the same code works when b = true?
I would guess its an optimization bug where the JIT spits out code based

on a stack value it already knows(its possible to determine what code will
execute statically after all), but the bug could just be somewhere on the
path that is followed when the boolean is false.

Has anyone tested this on any of the 2.0 betas?

Nov 17 '05 #10

P: n/a
it doesn't work with v2.0.40607. what is the latest beta?

"Willy Denoyette [MVP]" <wi*************@telenet.be> wrote in message
news:O0**************@TK2MSFTNGP10.phx.gbl...

"Daniel O'Connell [C# MVP]" <onyxkirx@--NOSPAM--comcast.net> wrote in
message news:OS*************@TK2MSFTNGP09.phx.gbl...

"Gianluca" <gi******@nospam.com> wrote in message
news:uX8ee.26042$lZ.22675@trnddc04...
No, you are right. I was looking at a bool cast that my code applies. I
was
checking the MSIL from the original code and it's more complex that the
sample expression. I just checked the MSIL from the test code and there is
no visible difference (other than the assigment) between the b = false
(bug)
and the b = true (no bug) calls. Looking at the MSIL below is it possible that when L_0019 is reached the first argument on the stack has been
truncated?

How can it be the JIT if the same code works when b = true?


I would guess its an optimization bug where the JIT spits out code based
on a stack value it already knows(its possible to determine what code will execute statically after all), but the bug could just be somewhere on the path that is followed when the boolean is false.

Has anyone tested this on any of the 2.0 betas?


Works as expected in v2.0 Beta2.

Willy.

Nov 17 '05 #11

P: n/a
it doesn't work with v2.0.40607. what is the latest beta?


Beta 2, version 2.0.50215

Mattias

--
Mattias Sjögren [MVP] mattias @ mvps.org
http://www.msjogren.net/dotnet/ | http://www.dotnetinterop.com
Please reply only to the newsgroup.
Nov 17 '05 #12

P: n/a
Daniel O'Connell [C# MVP] wrote:
"Gianluca" <gi******@nospam.com> wrote in message
news:uX8ee.26042$lZ.22675@trnddc04...
No, you are right. I was looking at a bool cast that my code applies. I
was
checking the MSIL from the original code and it's more complex that the
sample expression. I just checked the MSIL from the test code and there
is
no visible difference (other than the assigment) between the b = false
(bug)
and the b = true (no bug) calls. Looking at the MSIL below is it possible
that when L_0019 is reached the first argument on the stack has been
truncated?

How can it be the JIT if the same code works when b = true?

I would guess its an optimization bug where the JIT spits out code based on
a stack value it already knows(its possible to determine what code will
execute statically after all), but the bug could just be somewhere on the
path that is followed when the boolean is


After reading this post, I think indeed it's the JIT and not the
compiler optimization (first thought the compiler was it)

I now also think it's jit optimization related where it knows that the
boolean expression can never be true, because b is false. It therefore
pops operators and operands from the stack (that's a guess) and it does
that wrong, so too less data is left on the stack.

making b is true fixes it, which means that the optimization trick '(b
|| b) &&.. can never be true' can't be used, and hte complete expression
has to be evaluated, avoiding the popping and therefore will result in
working code.

workaround: evaluate the expression into a variable, then pass that
variable.

FB

--
------------------------------------------------------------------------
Get LLBLGen Pro, productive O/R mapping for .NET: http://www.llblgen.com
My .NET blog: http://weblogs.asp.net/fbouma
Microsoft MVP (C#)
------------------------------------------------------------------------
Nov 17 '05 #13

P: n/a
the optmizer cannot know that b will never be true, the same code doesn't
work if b is evaluated at runtime.
actually it's enough to remove the parenthesis and the code works!
"Frans Bouma [C# MVP]" <pe******************@xs4all.nl> wrote in message
news:Ol**************@TK2MSFTNGP12.phx.gbl...
Daniel O'Connell [C# MVP] wrote:
"Gianluca" <gi******@nospam.com> wrote in message
news:uX8ee.26042$lZ.22675@trnddc04...
No, you are right. I was looking at a bool cast that my code applies. I
was
checking the MSIL from the original code and it's more complex that the
sample expression. I just checked the MSIL from the test code and there
is
no visible difference (other than the assigment) between the b = false
(bug)
and the b = true (no bug) calls. Looking at the MSIL below is it possiblethat when L_0019 is reached the first argument on the stack has been
truncated?

How can it be the JIT if the same code works when b = true?

I would guess its an optimization bug where the JIT spits out code based on a stack value it already knows(its possible to determine what code will
execute statically after all), but the bug could just be somewhere on the path that is followed when the boolean is


After reading this post, I think indeed it's the JIT and not the
compiler optimization (first thought the compiler was it)

I now also think it's jit optimization related where it knows that the
boolean expression can never be true, because b is false. It therefore
pops operators and operands from the stack (that's a guess) and it does
that wrong, so too less data is left on the stack.

making b is true fixes it, which means that the optimization trick '(b
|| b) &&.. can never be true' can't be used, and hte complete expression
has to be evaluated, avoiding the popping and therefore will result in
working code.

workaround: evaluate the expression into a variable, then pass that
variable.

FB

--
------------------------------------------------------------------------
Get LLBLGen Pro, productive O/R mapping for .NET: http://www.llblgen.com
My .NET blog: http://weblogs.asp.net/fbouma
Microsoft MVP (C#)
------------------------------------------------------------------------

Nov 17 '05 #14

P: n/a
I think it only can be the JIT - there are two reasons for this:

1. The generated IL seems to be correct to me.

2. Would it at all be possible to pop only part (remember, only 1 byte
remains according to Gianluca) of an argument from the stack using IL?

--
Greetings from Vienna,
Martin

fecher GmbH
good people - good software
"Frans Bouma [C# MVP]" <pe******************@xs4all.nl> schrieb im
Newsbeitrag news:Ol**************@TK2MSFTNGP12.phx.gbl...
Daniel O'Connell [C# MVP] wrote:
"Gianluca" <gi******@nospam.com> wrote in message
news:uX8ee.26042$lZ.22675@trnddc04...
No, you are right. I was looking at a bool cast that my code applies. I
was
checking the MSIL from the original code and it's more complex that the
sample expression. I just checked the MSIL from the test code and there
is
no visible difference (other than the assigment) between the b = false
(bug)
and the b = true (no bug) calls. Looking at the MSIL below is it possiblethat when L_0019 is reached the first argument on the stack has been
truncated?

How can it be the JIT if the same code works when b = true?

I would guess its an optimization bug where the JIT spits out code based on a stack value it already knows(its possible to determine what code will
execute statically after all), but the bug could just be somewhere on the path that is followed when the boolean is


After reading this post, I think indeed it's the JIT and not the
compiler optimization (first thought the compiler was it)

I now also think it's jit optimization related where it knows that the
boolean expression can never be true, because b is false. It therefore
pops operators and operands from the stack (that's a guess) and it does
that wrong, so too less data is left on the stack.

making b is true fixes it, which means that the optimization trick '(b
|| b) &&.. can never be true' can't be used, and hte complete expression
has to be evaluated, avoiding the popping and therefore will result in
working code.

workaround: evaluate the expression into a variable, then pass that
variable.

FB

--
------------------------------------------------------------------------
Get LLBLGen Pro, productive O/R mapping for .NET: http://www.llblgen.com
My .NET blog: http://weblogs.asp.net/fbouma
Microsoft MVP (C#)
------------------------------------------------------------------------

Nov 17 '05 #15

P: n/a
Gianluca wrote:
the optmizer cannot know that b will never be true, the same code doesn't
work if b is evaluated at runtime.
it knows b is false, it's set to false at the start. (b || b) &&...
will then evaluate to false, no matter what. If the code sets b to true,
no bug appears, which IMHO shows that the bug is likely in the shortcut
code to evaluate boolean expressions.
actually it's enough to remove the parenthesis and the code works!
Hmm... that's indeed strange.
you could argue that
b || b && exp
is different from
(b || b) && exp

as the JIT could see it as:
b || (b && exp)
vs.
(b || b) && exp

though that would trigger the question: why does it resolve (b || b)
but not b || b ?

FB


"Frans Bouma [C# MVP]" <pe******************@xs4all.nl> wrote in message
news:Ol**************@TK2MSFTNGP12.phx.gbl...
Daniel O'Connell [C# MVP] wrote:
"Gianluca" <gi******@nospam.com> wrote in message
news:uX8ee.26042$lZ.22675@trnddc04...
No, you are right. I was looking at a bool cast that my code applies. I
was
checking the MSIL from the original code and it's more complex that the
sample expression. I just checked the MSIL from the test code and there
is
no visible difference (other than the assigment) between the b = false
(bug)
and the b = true (no bug) calls. Looking at the MSIL below is it
possible
that when L_0019 is reached the first argument on the stack has been
truncated?

How can it be the JIT if the same code works when b = true?
I would guess its an optimization bug where the JIT spits out code based
on
a stack value it already knows(its possible to determine what code will
execute statically after all), but the bug could just be somewhere on
the
path that is followed when the boolean is


After reading this post, I think indeed it's the JIT and not the
compiler optimization (first thought the compiler was it)

I now also think it's jit optimization related where it knows that the
boolean expression can never be true, because b is false. It therefore
pops operators and operands from the stack (that's a guess) and it does
that wrong, so too less data is left on the stack.

making b is true fixes it, which means that the optimization trick '(b
|| b) &&.. can never be true' can't be used, and hte complete expression
has to be evaluated, avoiding the popping and therefore will result in
working code.

workaround: evaluate the expression into a variable, then pass that
variable.


--
------------------------------------------------------------------------
Get LLBLGen Pro, productive O/R mapping for .NET: http://www.llblgen.com
My .NET blog: http://weblogs.asp.net/fbouma
Microsoft MVP (C#)
------------------------------------------------------------------------
Nov 17 '05 #16

P: n/a
Well, I have been watching this thread to see what comes up. Tonight I took
a shot at it and after about 45min of playing around this is what I have
come up with. Unfortunately there is nothing conclusive other than it does
appear to be a JIT bug, but hey everyone guessed that already :). And my
evaluation of the code might be off since it was just a quick scan of what
is happening.

Below is the non-optimized JIT code generated for the expression. I have
included the IL instuctions that map to the JIT code and you will notice
that the ldloc instructions which load the variable b onto the evaluation
stack move data from the esi to the dsi. Now notice the ldloc at label
IL_000c in this case the JIT code loads the same value into the edi and esi
registers, this throws the evaluation stack out and causing the chaos.

For the other expressions the only difference is that this particular
section of the code is not executed and the problem is hidden, but still
exists. The bug does appear to be with the JIT, and it would appear that the
short circuit evaluation is in face hidding the problem rather than causing
it, I say this because of the short circuit evaluation the erroneous code is
not executed in cases where the variable is true. This is also true for the
case where the brackets are removed from the expression.

It would be very interesting to isolate the exact senarios where this
erroneous code is generated, but I have confirmed that it is when a
non-primitive value type (ie. Decimal, DateTime or User Defined value types)
exists on the evaluation stack prior to the expression that this code is
generated.

IL_0003: ldc.i4.3
0000001c mov esi,3
IL_0004: newobj instance void
[mscorlib]System.Decimal::.ctor(int32)
00000021 lea ecx,[ebp-18h]
00000024 mov edx,esi
00000026 call dword ptr ds:[79C41A78h]
IL_0009: ldloc.0
0000002c mov dword ptr [ebp-1Ch],ebx
0000002f mov dword ptr [ebp-20h],edi
00000032 lea edi,[ebp-30h]
00000035 lea esi,[ebp-18h]
00000038 movs dword ptr [edi],dword ptr [esi]
00000039 movs dword ptr [edi],dword ptr [esi]
0000003a movs dword ptr [edi],dword ptr [esi]
0000003b movs dword ptr [edi],dword ptr [esi]
IL_000a: brtrue.s IL_000f
0000003c cmp dword ptr [ebp-1Ch],0
00000040 jne 0000005B
//------------Here is here I believe the problem is in the JIT code
IL_000c: ldloc.0
00000042 mov dword ptr [ebp-64h],ebx
00000045 mov eax,dword ptr [ebp-20h]
00000048 mov dword ptr [ebp-20h],eax
0000004b lea edi,[ebp-30h] //<------- Prblem on this and next line,
edi/esi are loaded with same value so
0000004e lea esi,[ebp-30h] // evaluation stack is not adjusted
00000051 movs dword ptr [edi],dword ptr [esi]
00000052 movs dword ptr [edi],dword ptr [esi]
00000053 movs dword ptr [edi],dword ptr [esi]
00000054 movs dword ptr [edi],dword ptr [esi]
//---------------------------------------------------------------
IL_000d: brfalse.s IL_0018
00000055 cmp dword ptr [ebp-64h],0
00000059 je 000000CC
IL_000f: ldloc.0
0000005b mov dword ptr [ebp-34h],ebx
0000005e mov eax,dword ptr [ebp-20h]
00000061 mov dword ptr [ebp-38h],eax
00000064 lea edi,[ebp-48h]
00000067 lea esi,[ebp-30h]
0000006a movs dword ptr [edi],dword ptr [esi]
0000006b movs dword ptr [edi],dword ptr [esi]
0000006c movs dword ptr [edi],dword ptr [esi]
0000006d movs dword ptr [edi],dword ptr [esi]
IL_0010: brfalse.s IL_0018

--
Chris Taylor
http://dotnetjunkies.com/weblog/chris.taylor
"Frans Bouma [C# MVP]" <pe******************@xs4all.nl> wrote in message
news:#C**************@TK2MSFTNGP14.phx.gbl...
Gianluca wrote:
the optmizer cannot know that b will never be true, the same code doesn't work if b is evaluated at runtime.


it knows b is false, it's set to false at the start. (b || b) &&...
will then evaluate to false, no matter what. If the code sets b to true,
no bug appears, which IMHO shows that the bug is likely in the shortcut
code to evaluate boolean expressions.
actually it's enough to remove the parenthesis and the code works!


Hmm... that's indeed strange.
you could argue that
b || b && exp
is different from
(b || b) && exp

as the JIT could see it as:
b || (b && exp)
vs.
(b || b) && exp

though that would trigger the question: why does it resolve (b || b)
but not b || b ?

FB


"Frans Bouma [C# MVP]" <pe******************@xs4all.nl> wrote in message
news:Ol**************@TK2MSFTNGP12.phx.gbl...
Daniel O'Connell [C# MVP] wrote:

"Gianluca" <gi******@nospam.com> wrote in message
news:uX8ee.26042$lZ.22675@trnddc04...
>No, you are right. I was looking at a bool cast that my code applies. I>was
>checking the MSIL from the original code and it's more complex that the>sample expression. I just checked the MSIL from the test code and there>is
>no visible difference (other than the assigment) between the b = false
>(bug)
>and the b = true (no bug) calls. Looking at the MSIL below is it


possible
>that when L_0019 is reached the first argument on the stack has been
>truncated?
>
>How can it be the JIT if the same code works when b = true?
I would guess its an optimization bug where the JIT spits out code
based
on
a stack value it already knows(its possible to determine what code will
execute statically after all), but the bug could just be somewhere on


the
path that is followed when the boolean is

After reading this post, I think indeed it's the JIT and not the
compiler optimization (first thought the compiler was it)

I now also think it's jit optimization related where it knows that the
boolean expression can never be true, because b is false. It therefore
pops operators and operands from the stack (that's a guess) and it does
that wrong, so too less data is left on the stack.

making b is true fixes it, which means that the optimization trick '(b
|| b) &&.. can never be true' can't be used, and hte complete expression
has to be evaluated, avoiding the popping and therefore will result in
working code.

workaround: evaluate the expression into a variable, then pass that
variable.


--
------------------------------------------------------------------------
Get LLBLGen Pro, productive O/R mapping for .NET: http://www.llblgen.com
My .NET blog: http://weblogs.asp.net/fbouma
Microsoft MVP (C#)
------------------------------------------------------------------------

Nov 17 '05 #17

P: n/a
it's set at the start in the sample code. you can pass it as a parameter or
load it from a file or calculate it and it still does not work.

"Frans Bouma [C# MVP]" <pe******************@xs4all.nl> wrote in message
news:#C**************@TK2MSFTNGP14.phx.gbl...
Gianluca wrote:
the optmizer cannot know that b will never be true, the same code doesn't work if b is evaluated at runtime.


it knows b is false, it's set to false at the start. (b || b) &&...
will then evaluate to false, no matter what. If the code sets b to true,
no bug appears, which IMHO shows that the bug is likely in the shortcut
code to evaluate boolean expressions.
actually it's enough to remove the parenthesis and the code works!


Hmm... that's indeed strange.
you could argue that
b || b && exp
is different from
(b || b) && exp

as the JIT could see it as:
b || (b && exp)
vs.
(b || b) && exp

though that would trigger the question: why does it resolve (b || b)
but not b || b ?

FB


"Frans Bouma [C# MVP]" <pe******************@xs4all.nl> wrote in message
news:Ol**************@TK2MSFTNGP12.phx.gbl...
Daniel O'Connell [C# MVP] wrote:

"Gianluca" <gi******@nospam.com> wrote in message
news:uX8ee.26042$lZ.22675@trnddc04...
>No, you are right. I was looking at a bool cast that my code applies. I>was
>checking the MSIL from the original code and it's more complex that the>sample expression. I just checked the MSIL from the test code and there>is
>no visible difference (other than the assigment) between the b = false
>(bug)
>and the b = true (no bug) calls. Looking at the MSIL below is it


possible
>that when L_0019 is reached the first argument on the stack has been
>truncated?
>
>How can it be the JIT if the same code works when b = true?
I would guess its an optimization bug where the JIT spits out code
based
on
a stack value it already knows(its possible to determine what code will
execute statically after all), but the bug could just be somewhere on


the
path that is followed when the boolean is

After reading this post, I think indeed it's the JIT and not the
compiler optimization (first thought the compiler was it)

I now also think it's jit optimization related where it knows that the
boolean expression can never be true, because b is false. It therefore
pops operators and operands from the stack (that's a guess) and it does
that wrong, so too less data is left on the stack.

making b is true fixes it, which means that the optimization trick '(b
|| b) &&.. can never be true' can't be used, and hte complete expression
has to be evaluated, avoiding the popping and therefore will result in
working code.

workaround: evaluate the expression into a variable, then pass that
variable.


--
------------------------------------------------------------------------
Get LLBLGen Pro, productive O/R mapping for .NET: http://www.llblgen.com
My .NET blog: http://weblogs.asp.net/fbouma
Microsoft MVP (C#)
------------------------------------------------------------------------

Nov 17 '05 #18

P: n/a
Hi Jerry,

This issue was brought to my attention by a PM for C# that was reading
through this thread. I want to take this issue and formally bring this up
to our products team so we cna track it. Please email me directly with
your contact infomation and I can create a free support incident and we can
start debugging this issue. You can email me directly, remove the "online
.." in my email:

da****@online.microsoft.com

Once we have resolved this issue, I will make a final post to this thread
with the resolution.

Thanks,
Dat Bui
Microsoft Developer Support

This posting is provided "AS IS" with no warranties, and confers no rights.
© Microsoft Corporation. All rights reserved.

--------------------
Reply-To: "Jerry" <je**********@yandex.ru>
From: "Jerry" <je**********@yandex.ru>
Newsgroups: microsoft.public.dotnet.languages.csharp
Subject: Nasty bug in the C# compiler, it truncates values on the stack
Lines: 48
Organization: Goodman
X-Priority: 3
X-MSMail-Priority: Normal
X-Newsreader: Microsoft Outlook Express 6.00.2800.1106
X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2800.1106
Message-ID: <q68ee.10$fQ2.2@trnddc05>
Date: Wed, 04 May 2005 18:01:58 GMT
NNTP-Posting-Host: 70.21.88.43
X-Complaints-To: ab***@verizon.net
X-Trace: trnddc05 1115229718 70.21.88.43 (Wed, 04 May 2005 14:01:58 EDT)
NNTP-Posting-Date: Wed, 04 May 2005 14:01:58 EDT
Path: TK2MSFTNGXA01.phx.gbl!TK2MSFTNGP08.phx.gbl!newsfee d00.sul.t-online.de!t-onli
ne.de!border2.nntp.dca.giganews.com!nntp.giganews. com!cyclone1.gnilink.net!s
pamkiller.gnilink.net!gnilink.net!trnddc05.POSTED! 6c2ea718!not-for-mailXref: TK2MSFTNGXA01.phx.gbl microsoft.public.dotnet.languages.csharp:96289
X-Tomcat-NG: microsoft.public.dotnet.languages.csharp

I managed to narrow this down to a very simple expression. try this:

private void Bug()
{
bool b = false;
Test(3, (b || b) && b && !b);
}

private void Works()
{
bool b = true;
Test(3, (b || b) && b && !b);
}

private void Test(decimal v, bool b)
{
MessageBox.Show(v.ToString());
}

The value of the argument v in Test() is 0!

If you change the function Bug() and make bool b = true it works fine. I
checked the MSIL code and it appears that the compiler chocked on the
expression "(b || b) && b && !b" and silently truncated the previous
argument to bool (1 byte). Since the argument is a decimal it will show zerobecause the truncation occurs on the decimal structure.

You can try this with any struct and any value as the first argument, the
compiler will always truncate the struct on the stack to 1 byte. If you try
with your own struct you will lose all the data after the first byte.

Strangely enough, if you remove the parenthesis "b || b && b && !b" is worksfine.

Plese don't focus on the expression, it's a simplification of a real
expression. The nastiest part is that there is no compiler error or warning,it simply generates wrong MSIL code.

Is this a known bug? If not, how do I report this to Microsoft and to the
.NET team?

I tried in the past to report a bug with the shortcircuit operators specs
and compiler but didn't suceeded and the defect is still there.

I also tried with the latest service pack, the version shown in the .NET
Configuration module is version 1.1.4322.573.


Nov 17 '05 #19

P: n/a
Looks like this bug has been reported and is fixed in Whidbey. You can
review the bug here:

http://lab.msdn.microsoft.com/produc...x?feedbackid=9
439dd52-e87c-476b-a8fe-b04835dabff9

Hope this helps,
Dat Bui
Microsoft Developer Support

This posting is provided "AS IS" with no warranties, and confers no rights.
© Microsoft Corporation. All rights reserved.

--------------------
X-Tomcat-ID: 538564087
References: <q68ee.10$fQ2.2@trnddc05>
MIME-Version: 1.0
Content-Type: text/plain
Content-Transfer-Encoding: 7bit
From: da****@online.microsoft.com (Dat Bui [MSFT])
Organization: Microsoft
Date: Wed, 25 May 2005 20:53:04 GMT
Subject: RE: Nasty bug in the C# compiler, it truncates values on the stack
X-Tomcat-NG: microsoft.public.dotnet.languages.csharp
Message-ID: <PP**************@TK2MSFTNGXA01.phx.gbl>
Newsgroups: microsoft.public.dotnet.languages.csharp
Lines: 87
Path: TK2MSFTNGXA01.phx.gbl
Xref: TK2MSFTNGXA01.phx.gbl microsoft.public.dotnet.languages.csharp:100699
NNTP-Posting-Host: tomcatimport2.phx.gbl 10.201.218.182

Hi Jerry,

This issue was brought to my attention by a PM for C# that was readingthrough this thread. I want to take this issue and formally bring this up
to our products team so we cna track it. Please email me directly with
your contact infomation and I can create a free support incident and we canstart debugging this issue. You can email me directly, remove the "online
." in my email:

da****@online.microsoft.com

Once we have resolved this issue, I will make a final post to this thread
with the resolution.

Thanks,
Dat Bui
Microsoft Developer Support

This posting is provided "AS IS" with no warranties, and confers no rights. © Microsoft Corporation. All rights reserved.

--------------------
Reply-To: "Jerry" <je**********@yandex.ru>
From: "Jerry" <je**********@yandex.ru>
Newsgroups: microsoft.public.dotnet.languages.csharp
Subject: Nasty bug in the C# compiler, it truncates values on the stack
Lines: 48
Organization: Goodman
X-Priority: 3
X-MSMail-Priority: Normal
X-Newsreader: Microsoft Outlook Express 6.00.2800.1106
X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2800.1106
Message-ID: <q68ee.10$fQ2.2@trnddc05>
Date: Wed, 04 May 2005 18:01:58 GMT
NNTP-Posting-Host: 70.21.88.43
X-Complaints-To: ab***@verizon.net
X-Trace: trnddc05 1115229718 70.21.88.43 (Wed, 04 May 2005 14:01:58 EDT)
NNTP-Posting-Date: Wed, 04 May 2005 14:01:58 EDT
Path:TK2MSFTNGXA01.phx.gbl!TK2MSFTNGP08.phx.gbl!newsfe ed00.sul.t-online.de!t-onl

ine.de!border2.nntp.dca.giganews.com!nntp.giganews .com!cyclone1.gnilink.net! spamkiller.gnilink.net!gnilink.net!trnddc05.POSTED !6c2ea718!not-for-mail
Xref: TK2MSFTNGXA01.phx.gbl microsoft.public.dotnet.languages.csharp:96289
X-Tomcat-NG: microsoft.public.dotnet.languages.csharp

I managed to narrow this down to a very simple expression. try this:

private void Bug()
{
bool b = false;
Test(3, (b || b) && b && !b);
}

private void Works()
{
bool b = true;
Test(3, (b || b) && b && !b);
}

private void Test(decimal v, bool b)
{
MessageBox.Show(v.ToString());
}

The value of the argument v in Test() is 0!

If you change the function Bug() and make bool b = true it works fine. I
checked the MSIL code and it appears that the compiler chocked on the
expression "(b || b) && b && !b" and silently truncated the previous
argument to bool (1 byte). Since the argument is a decimal it will show

zero
because the truncation occurs on the decimal structure.

You can try this with any struct and any value as the first argument, the
compiler will always truncate the struct on the stack to 1 byte. If you trywith your own struct you will lose all the data after the first byte.

Strangely enough, if you remove the parenthesis "b || b && b && !b" is

works
fine.

Plese don't focus on the expression, it's a simplification of a real
expression. The nastiest part is that there is no compiler error or

warning,
it simply generates wrong MSIL code.

Is this a known bug? If not, how do I report this to Microsoft and to the
.NET team?

I tried in the past to report a bug with the shortcircuit operators specs
and compiler but didn't suceeded and the defect is still there.

I also tried with the latest service pack, the version shown in the .NET
Configuration module is version 1.1.4322.573.



Nov 17 '05 #20

This discussion thread is closed

Replies have been disabled for this discussion.