Bug in VB.NET Compiler (easy to reproduce) - with small correction to the readability of my explanat

M

Mark Walsh

The following is an explanation of a bug that exists in the VB.NET compiler.
I've tried to report it to Microsoft, but they've made it so difficult I've
given up:

MSDN help states that variables are initialised when they are created. This
seems to be true for the following code which produces "1","2","3","4","5".
(ie the variable is created when a procedure is entered and not when
for-loop is entered)

For i = 1 To 5
Dim x As Integer
x += 1
MsgBox(x.ToString)
Next

However, this is INCONSISTENT with the following code:

For i = 1 To 5
Dim x As Integer = 0
x += 1
MsgBox(x.ToString)
Next

which displays "1","1","1","1","1" implying that the variable is re-created
(if I believe the help) and consequently re-initialised each time the loop
iterates (ie: when it comes into scope)


If you disassemble a piece of code you will see that variables are created
when the PROCEDURE is entered NOT when a block (eg a "for loop") is entered:

For Example, the following code:

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button1.Click
Dim i As Integer
Dim W As Integer = 2
Dim A As Integer = 3
Dim C As Integer = 4
Dim R As Integer = 5
Dim T As Integer = 6
Dim F As Integer = 7

For i = 1 To 5
Dim x1 As Integer = 0
Dim x2 As Integer = 0
Dim x3 As Integer = 0
Dim x4 As Integer = 0
Dim x5 As Integer = 0
Dim x6 As Integer = 0
x1 += 1
Next
End Sub

Disassembles as:

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button1.Click
00000000 push ebp
00000001 mov ebp,esp
00000003 sub esp,3Ch
00000006 push edi
00000007 push esi
00000008 push ebx
00000009 mov dword ptr [ebp-4],ecx
0000000c mov dword ptr [ebp-8],edx
0000000f xor ebx,ebx
00000011 mov dword ptr [ebp-10h],0
00000018 mov dword ptr [ebp-14h],0
0000001f xor esi,esi
00000021 mov dword ptr [ebp-1Ch],0
00000028 mov dword ptr [ebp-20h],0
0000002f mov dword ptr [ebp-24h],0
00000036 xor edi,edi
00000038 mov dword ptr [ebp-2Ch],0
0000003f mov dword ptr [ebp-30h],0
00000046 mov dword ptr [ebp-34h],0
0000004d mov dword ptr [ebp-38h],0
00000054 mov dword ptr [ebp-3Ch],0
0000005b nop
Dim W As Integer = 2
0000005c mov dword ptr [ebp-24h],2
Dim A As Integer = 3
00000063 mov ebx,3
Dim C As Integer = 4
00000068 mov dword ptr [ebp-10h],4
Dim R As Integer = 5
0000006f mov dword ptr [ebp-1Ch],5
Dim T As Integer = 6
00000076 mov dword ptr [ebp-20h],6
Dim F As Integer = 7
0000007d mov dword ptr [ebp-14h],7
For i = 1 To 5
00000084 mov esi,1
Dim x1 As Integer = 0
00000089 xor edi,edi
Dim x2 As Integer = 0
0000008b mov dword ptr [ebp-2Ch],0
Dim x3 As Integer = 0
00000092 mov dword ptr [ebp-30h],0
Dim x4 As Integer = 0
00000099 mov dword ptr [ebp-34h],0
Dim x5 As Integer = 0
000000a0 mov dword ptr [ebp-38h],0
Dim x6 As Integer = 0
000000a7 mov dword ptr [ebp-3Ch],0
x1 += 1
000000ae add edi,1
000000b1 jno 000000BA
000000b3 xor ecx,ecx
000000b5 call 7847D2B4
Next
000000ba nop
000000bb add esi,1
000000be jno 000000C7
000000c0 xor ecx,ecx
000000c2 call 7847D2B4
000000c7 cmp esi,5
000000ca jle 00000089
End Sub

Notice that on line 00000092 for example (the code for Dim x3 As Integer =
0) that it is assigning zero to an address pointed to by register ebp-30h.
In other words the variable has already been created on the stack when the
procedure was entered, not when the loop is entered. This assignment is at
complete odds with the help which says that initialisation happens when a
variable is created.

The above behaviour is also inconsistent with the following code:

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button1.Click
Static x As Integer = 3
Dim i As Integer
For i = 1 To 5
x += 1
Next
MsgBox(x.ToString)
End Sub

This of code displays '8' the first time the procedure is
entered, and 13 the second time the procedure is entered. STATIC X is only
created once (the first time the procedure is entered) and initialised once,
when the variable is
created. Not every time the variable comes into scope.



"this behaviour is by design" ... I hope not, it's a shocker.

Mark (KAZ technology services, Australia).
 
D

David Pendleton

I suppose at the very least, you've found an inconsistency in the
documentation. It looks as if nothing has change from the VB days where
variables were initialized when the procedure was called, not as they were
Dim'med. As far as 'intended' behavior, I don't know.

Why would anyone declare a variable in a loop anyway? Declare it once, use
it as necessary. Since when is 'Dim i As Integer' the same as 'i = 0'?

Just my .02

--
ROT13 my email address to reply: (e-mail address removed)

Mark Walsh said:
The following is an explanation of a bug that exists in the VB.NET compiler.
I've tried to report it to Microsoft, but they've made it so difficult I've
given up:

MSDN help states that variables are initialised when they are created. This
seems to be true for the following code which produces "1","2","3","4","5".
(ie the variable is created when a procedure is entered and not when
for-loop is entered)

For i = 1 To 5
Dim x As Integer
x += 1
MsgBox(x.ToString)
Next

However, this is INCONSISTENT with the following code:

For i = 1 To 5
Dim x As Integer = 0
x += 1
MsgBox(x.ToString)
Next

which displays "1","1","1","1","1" implying that the variable is re-created
(if I believe the help) and consequently re-initialised each time the loop
iterates (ie: when it comes into scope)


If you disassemble a piece of code you will see that variables are created
when the PROCEDURE is entered NOT when a block (eg a "for loop") is entered:

For Example, the following code:

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button1.Click
Dim i As Integer
Dim W As Integer = 2
Dim A As Integer = 3
Dim C As Integer = 4
Dim R As Integer = 5
Dim T As Integer = 6
Dim F As Integer = 7

For i = 1 To 5
Dim x1 As Integer = 0
Dim x2 As Integer = 0
Dim x3 As Integer = 0
Dim x4 As Integer = 0
Dim x5 As Integer = 0
Dim x6 As Integer = 0
x1 += 1
Next
End Sub

Disassembles as:

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button1.Click
00000000 push ebp
00000001 mov ebp,esp
00000003 sub esp,3Ch
00000006 push edi
00000007 push esi
00000008 push ebx
00000009 mov dword ptr [ebp-4],ecx
0000000c mov dword ptr [ebp-8],edx
0000000f xor ebx,ebx
00000011 mov dword ptr [ebp-10h],0
00000018 mov dword ptr [ebp-14h],0
0000001f xor esi,esi
00000021 mov dword ptr [ebp-1Ch],0
00000028 mov dword ptr [ebp-20h],0
0000002f mov dword ptr [ebp-24h],0
00000036 xor edi,edi
00000038 mov dword ptr [ebp-2Ch],0
0000003f mov dword ptr [ebp-30h],0
00000046 mov dword ptr [ebp-34h],0
0000004d mov dword ptr [ebp-38h],0
00000054 mov dword ptr [ebp-3Ch],0
0000005b nop
Dim W As Integer = 2
0000005c mov dword ptr [ebp-24h],2
Dim A As Integer = 3
00000063 mov ebx,3
Dim C As Integer = 4
00000068 mov dword ptr [ebp-10h],4
Dim R As Integer = 5
0000006f mov dword ptr [ebp-1Ch],5
Dim T As Integer = 6
00000076 mov dword ptr [ebp-20h],6
Dim F As Integer = 7
0000007d mov dword ptr [ebp-14h],7
For i = 1 To 5
00000084 mov esi,1
Dim x1 As Integer = 0
00000089 xor edi,edi
Dim x2 As Integer = 0
0000008b mov dword ptr [ebp-2Ch],0
Dim x3 As Integer = 0
00000092 mov dword ptr [ebp-30h],0
Dim x4 As Integer = 0
00000099 mov dword ptr [ebp-34h],0
Dim x5 As Integer = 0
000000a0 mov dword ptr [ebp-38h],0
Dim x6 As Integer = 0
000000a7 mov dword ptr [ebp-3Ch],0
x1 += 1
000000ae add edi,1
000000b1 jno 000000BA
000000b3 xor ecx,ecx
000000b5 call 7847D2B4
Next
000000ba nop
000000bb add esi,1
000000be jno 000000C7
000000c0 xor ecx,ecx
000000c2 call 7847D2B4
000000c7 cmp esi,5
000000ca jle 00000089
End Sub

Notice that on line 00000092 for example (the code for Dim x3 As Integer =
0) that it is assigning zero to an address pointed to by register ebp-30h.
In other words the variable has already been created on the stack when the
procedure was entered, not when the loop is entered. This assignment is at
complete odds with the help which says that initialisation happens when a
variable is created.

The above behaviour is also inconsistent with the following code:

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button1.Click
Static x As Integer = 3
Dim i As Integer
For i = 1 To 5
x += 1
Next
MsgBox(x.ToString)
End Sub

This of code displays '8' the first time the procedure is
entered, and 13 the second time the procedure is entered. STATIC X is only
created once (the first time the procedure is entered) and initialised once,
when the variable is
created. Not every time the variable comes into scope.



"this behaviour is by design" ... I hope not, it's a shocker.

Mark (KAZ technology services, Australia).
 
E

Eduardo A. Morcillo [MS MVP]

STATIC X is
only created once (the first time the procedure is entered)

Actually a Static variable is declared as a member variable, using an instance of Microsoft.VisualBasic.CompilerServices.StaticLocalInitFlag to know if it was already initialized. Initializing a Static variable in it's declaration is something you want to avoid because adds a lot of overhead.
 
H

Herfried K. Wagner [MVP]

* "David Pendleton said:
I suppose at the very least, you've found an inconsistency in the
documentation. It looks as if nothing has change from the VB days where
variables were initialized when the procedure was called, not as they were
Dim'med. As far as 'intended' behavior, I don't know.

ACK, they are created at the procedure's start, but they are only
visible in the block they are declared in (this is a compiler feature).
 
H

Herfried K. Wagner [MVP]

* "Mark Walsh said:
The following is an explanation of a bug that exists in the VB.NET compiler.
I've tried to report it to Microsoft, but they've made it so difficult I've
given up:

MSDN help states that variables are initialised when they are created. This
seems to be true for the following code which produces "1","2","3","4","5".
(ie the variable is created when a procedure is entered and not when
for-loop is entered)

For i = 1 To 5
Dim x As Integer
x += 1
MsgBox(x.ToString)
Next

However, this is INCONSISTENT with the following code:

For i = 1 To 5
Dim x As Integer = 0
x += 1
MsgBox(x.ToString)
Next

which displays "1","1","1","1","1" implying that the variable is re-created
(if I believe the help) and consequently re-initialised each time the loop
iterates (ie: when it comes into scope)

\\\
Dim x As Integer = 0
///

can be written as

\\\
Dim x As Integer
x = 0
///

The compiler will take the 'Dim' at the beginning of the procedure, the
assignment will remain in the loop. That's by design.
 
C

Cor

Hi Herfried,

The question is in my eyes "why this is not the same with a declaration.
static x as integer = 0
dim x as integer = 0
\\\
Dim x As Integer
x = 0
///
It has to be than also
Static x as Integer
x = 0

That is consistently

I see answers here as "because it has always been so" that give my the idea
as "take a nail and a stone" and start writing with that.

Cor
 
H

Herfried K. Wagner [MVP]

* "Cor said:
The question is in my eyes "why this is not the same with a declaration.
static x as integer = 0
dim x as integer = 0

That is consistently

You are right, the behavior iof static variables is a little bit
inconsistent...

;-)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top