Static Pointers Do Not Work Properly in C#?

B

Bob Bryan

I am writing an app that uses static arrays in a base class that I only want
to define once and shared amongst all instances of that class. On my
laptop, that is using Visual Studio 2008 SP1 and running Vista, the
following code has a problem:

unsafe public partial class Test1

{
protected static int[] PowersOf2 = new int[12] { 1, 2, 4, 8, 16, 32, 64,
128, 256, 512, 1024, 2048 };
protected static int* pPowersOf2; // Pointer to the PowersOf2 array.
protected static GCHandle gchPowersOf2; // Handle to GCHandle object
used to pin the PowersOf2 array.
public Test1()
{
fixed (int* p = PowersOf2)
{
gchPowersOf2 = GCHandle.Alloc(PowersOf2, GCHandleType.Pinned);
IntPtr pAddr = Marshal.UnsafeAddrOfPinnedArrayElement(PowersOf2,
0);
pPowersOf2 = (int*)pAddr.ToPointer();
pPowersOf2 = p;
int* p2 = p;
}
}
}

When the first pPowersOf2 pointer assignment is tried, the address is not
set correctly. There is no exception thrown or any other kind of odd
behaviour. The 2nd assignment statement of pPowersOf2 also does not work
and is set to the same odd address as was returned by the ToPointer
function. I then tried setting it to p, which is set correctly and p2 is
set to the correct address. If I remove the static keyword from the
pPowersOf2 declaration, then it works perfectly. As a workaround, I can use
non-static pointers in my class - its a little extra code, however, I would
prefer to use a static pointer.

So, the question is - am I doing something wrong here, or is this a bug? I
hope someone from MS or an experienced MVP can provide some guidance.

Thanks,

Bob Bryan
 
A

Arne Vajhøj

I am writing an app that uses static arrays in a base class that I only
want to define once and shared amongst all instances of that class. On
my laptop, that is using Visual Studio 2008 SP1 and running Vista, the
following code has a problem:

unsafe public partial class Test1

{
protected static int[] PowersOf2 = new int[12] { 1, 2, 4, 8, 16, 32, 64,
128, 256, 512, 1024, 2048 };
protected static int* pPowersOf2; // Pointer to the PowersOf2 array.
protected static GCHandle gchPowersOf2; // Handle to GCHandle object
used to pin the PowersOf2 array.
public Test1()
{
fixed (int* p = PowersOf2)
{
gchPowersOf2 = GCHandle.Alloc(PowersOf2, GCHandleType.Pinned);
IntPtr pAddr = Marshal.UnsafeAddrOfPinnedArrayElement(PowersOf2, 0);
pPowersOf2 = (int*)pAddr.ToPointer();
pPowersOf2 = p;
int* p2 = p;
}
}
}

When the first pPowersOf2 pointer assignment is tried, the address is
not set correctly. There is no exception thrown or any other kind of odd
behaviour. The 2nd assignment statement of pPowersOf2 also does not work
and is set to the same odd address as was returned by the ToPointer
function. I then tried setting it to p, which is set correctly and p2 is
set to the correct address. If I remove the static keyword from the
pPowersOf2 declaration, then it works perfectly. As a workaround, I can
use non-static pointers in my class - its a little extra code, however,
I would prefer to use a static pointer.

So, the question is - am I doing something wrong here, or is this a bug?
I hope someone from MS or an experienced MVP can provide some guidance.

using System;
using System.Runtime.InteropServices;

namespace E
{
unsafe public class Test1
{
protected static int[] PowersOf2 = new int[12] { 1, 2, 4, 8,
16, 32, 64, 128, 256, 512, 1024, 2048 };
protected static int* pPowersOf2; // Pointer to the PowersOf2
array.
protected static GCHandle gchPowersOf2; // Handle to GCHandle
object used to pin the PowersOf2 array.
public Test1()
{
fixed (int* p = PowersOf2)
{
gchPowersOf2 = GCHandle.Alloc(PowersOf2,
GCHandleType.Pinned);
IntPtr pAddr =
Marshal.UnsafeAddrOfPinnedArrayElement(PowersOf2, 0);
pPowersOf2 = (int*)pAddr.ToPointer();
for(int i = 0; i < 5; i++)
{
Console.WriteLine(pPowersOf2);
}
pPowersOf2 = p;
for(int i = 0; i < 5; i++)
{
Console.WriteLine(pPowersOf2);
}
int* p2 = p;
}
}
}
public class Program
{
public static void Main(string[] args)
{
new Test1();
Console.ReadKey(true);
}
}
}

outputs:

1
2
4
8
16
1
2
4
8
16

here and that looks OK to me.

Can you explain what "the address is not set correctly"
means?

And maybe provide a small compilable example illustrating
the problem?

Arne
 
P

Peter Duniho

Arne said:
[...]
When the first pPowersOf2 pointer assignment is tried, the address is
not set correctly. There is no exception thrown or any other kind of odd
behaviour. The 2nd assignment statement of pPowersOf2 also does not work
and is set to the same odd address as was returned by the ToPointer
function. [...]

[...]
Can you explain what "the address is not set correctly"
means?

And maybe provide a small compilable example illustrating
the problem?

The code he provided does demonstrate the problem (all you have to do is
write a bit of extra code to actually create an instance of his class),
but he didn't provide specific enough details.

I believe he may have run across a debugger bug, or at the very least, a
limitation. In particular, while the compiled and executing code will
do what you expect (as you've shown), if you try to examine the value of
the variable "pPowersOf2" while stepping through the code he posted, you
do indeed get what appear to be wrong values (or rather, I do…obviously
I don't know what happens on your computer).

In fact, I don't even get 100% reproducible results. One time stepping
through, when I evaluate the variable the debugger showed me what looked
like a pointer, but well past the beginning of the array (i.e. the value
was about 64K past the start of the array as shown by the other
variables, not actually the same). Other times stepping through, the
debugger just shows me 0x00000000.

But, in spite of all that, I was unable to reproduce any incorrect
output from the program itself. If I simply assign "*pPowersOf2" to a
local int variable (e.g. "int i = *pPowersOf2;") it works fine (i.e. the
variable "i" is shown by the debugger to have the value of "1" after the
assignment). And yet, immediately after stepping over that line of
code, I can examine "pPowersOf2" in the debugger and it's _still_ incorrect.

Note also that this is a DEBUG build, no optimizations. Looking at the
disassembly, the code seems to be just fine. It's just that the
debugger has gotten confused for some reason.

To the OP: I would say that, assuming your experience matches Arne's and
mind – that is, the code runs fine, it's just the debugger that seems to
be misbehaving – that you ought to post your bug on the Connect web
site, against Visual Studio. If you have a chance, try to double-check
that it reproduces in the 2010 version (it does for me), but if you can
only test it in 2008, that's fine.

Pete
 
B

Bob Bryan

The code that I provided was a small subset of the code that I'm working on,
and I had thought that it was not working properly. I tried adding in your
print statements to the output window, and the results that you obtained are
also duplicated on my machine as well. So, this particular case does appear
to work. I will have to go back and re-examine the problem again. It might
not have anything to do with static pointers. In answer to your question
about what was wrong with the pointer - sometimes the pointer returned was
zero and when any operation was tried on that pointer it would throw an
exception. I have some sbyte arrays and when I looked at the value of the
sbyte pointer in the intermediate window, it would show a different value
than what was actually in the array - which led me to think that the pointer
was not set properly. However, when I declared an sbyte variable and moved
the value of the pointer into this variable, it was correct.

Thanks for your help,

Bob Bryan

Arne Vajhøj said:
I am writing an app that uses static arrays in a base class that I only
want to define once and shared amongst all instances of that class. On
my laptop, that is using Visual Studio 2008 SP1 and running Vista, the
following code has a problem:

unsafe public partial class Test1

{
protected static int[] PowersOf2 = new int[12] { 1, 2, 4, 8, 16, 32, 64,
128, 256, 512, 1024, 2048 };
protected static int* pPowersOf2; // Pointer to the PowersOf2 array.
protected static GCHandle gchPowersOf2; // Handle to GCHandle object
used to pin the PowersOf2 array.
public Test1()
{
fixed (int* p = PowersOf2)
{
gchPowersOf2 = GCHandle.Alloc(PowersOf2, GCHandleType.Pinned);
IntPtr pAddr = Marshal.UnsafeAddrOfPinnedArrayElement(PowersOf2, 0);
pPowersOf2 = (int*)pAddr.ToPointer();
pPowersOf2 = p;
int* p2 = p;
}
}
}

When the first pPowersOf2 pointer assignment is tried, the address is
not set correctly. There is no exception thrown or any other kind of odd
behaviour. The 2nd assignment statement of pPowersOf2 also does not work
and is set to the same odd address as was returned by the ToPointer
function. I then tried setting it to p, which is set correctly and p2 is
set to the correct address. If I remove the static keyword from the
pPowersOf2 declaration, then it works perfectly. As a workaround, I can
use non-static pointers in my class - its a little extra code, however,
I would prefer to use a static pointer.

So, the question is - am I doing something wrong here, or is this a bug?
I hope someone from MS or an experienced MVP can provide some guidance.

using System;
using System.Runtime.InteropServices;

namespace E
{
unsafe public class Test1
{
protected static int[] PowersOf2 = new int[12] { 1, 2, 4, 8, 16,
32, 64, 128, 256, 512, 1024, 2048 };
protected static int* pPowersOf2; // Pointer to the PowersOf2
array.
protected static GCHandle gchPowersOf2; // Handle to GCHandle
object used to pin the PowersOf2 array.
public Test1()
{
fixed (int* p = PowersOf2)
{
gchPowersOf2 = GCHandle.Alloc(PowersOf2,
GCHandleType.Pinned);
IntPtr pAddr =
Marshal.UnsafeAddrOfPinnedArrayElement(PowersOf2, 0);
pPowersOf2 = (int*)pAddr.ToPointer();
for(int i = 0; i < 5; i++)
{
Console.WriteLine(pPowersOf2);
}
pPowersOf2 = p;
for(int i = 0; i < 5; i++)
{
Console.WriteLine(pPowersOf2);
}
int* p2 = p;
}
}
}
public class Program
{
public static void Main(string[] args)
{
new Test1();
Console.ReadKey(true);
}
}
}

outputs:

1
2
4
8
16
1
2
4
8
16

here and that looks OK to me.

Can you explain what "the address is not set correctly"
means?

And maybe provide a small compilable example illustrating
the problem?

Arne
 
A

Arne Vajhøj

The code that I provided was a small subset of the code that I'm working
on, and I had thought that it was not working properly. I tried adding
in your print statements to the output window, and the results that you
obtained are also duplicated on my machine as well. So, this particular
case does appear to work. I will have to go back and re-examine the
problem again. It might not have anything to do with static pointers. In
answer to your question about what was wrong with the pointer -
sometimes the pointer returned was zero and when any operation was tried
on that pointer it would throw an exception. I have some sbyte arrays
and when I looked at the value of the sbyte pointer in the intermediate
window, it would show a different value than what was actually in the
array - which led me to think that the pointer was not set properly.
However, when I declared an sbyte variable and moved the value of the
pointer into this variable, it was correct.

Apparently something funky is going on.

But until we have some code that can reproduce the problem, then
it is rather hard for us to help troubleshoot.

Arne
 
A

Arne Vajhøj

Arne said:
[...]
When the first pPowersOf2 pointer assignment is tried, the address is
not set correctly. There is no exception thrown or any other kind of odd
behaviour. The 2nd assignment statement of pPowersOf2 also does not work
and is set to the same odd address as was returned by the ToPointer
function. [...]

[...]
Can you explain what "the address is not set correctly"
means?

And maybe provide a small compilable example illustrating
the problem?

The code he provided does demonstrate the problem (all you have to do is
write a bit of extra code to actually create an instance of his class),
but he didn't provide specific enough details.

Well - the code I posed did in fact create an instance of the class.
I believe he may have run across a debugger bug, or at the very least, a
limitation. In particular, while the compiled and executing code will do
what you expect (as you've shown), if you try to examine the value of
the variable "pPowersOf2" while stepping through the code he posted, you
do indeed get what appear to be wrong values (or rather, I do…obviously
I don't know what happens on your computer).

In fact, I don't even get 100% reproducible results. One time stepping
through, when I evaluate the variable the debugger showed me what looked
like a pointer, but well past the beginning of the array (i.e. the value
was about 64K past the start of the array as shown by the other
variables, not actually the same). Other times stepping through, the
debugger just shows me 0x00000000.

But, in spite of all that, I was unable to reproduce any incorrect
output from the program itself. If I simply assign "*pPowersOf2" to a
local int variable (e.g. "int i = *pPowersOf2;") it works fine (i.e. the
variable "i" is shown by the debugger to have the value of "1" after the
assignment). And yet, immediately after stepping over that line of code,
I can examine "pPowersOf2" in the debugger and it's _still_ incorrect.

Note also that this is a DEBUG build, no optimizations. Looking at the
disassembly, the code seems to be just fine. It's just that the debugger
has gotten confused for some reason.

To the OP: I would say that, assuming your experience matches Arne's and
mind – that is, the code runs fine, it's just the debugger that seems to
be misbehaving – that you ought to post your bug on the Connect web
site, against Visual Studio. If you have a chance, try to double-check
that it reproduces in the 2010 version (it does for me), but if you can
only test it in 2008, that's fine.

A debugger error is a bit different.

I did not even try to run it under the debugger.

But original poster in his reply to my post stated that:

#In answer to your question about what was wrong with the pointer -
#sometimes the pointer returned was zero and when any operation was
#tried on that pointer it would throw an exception.

which seems as if he have some other code where it is not just
a debugger problem.

But until we have an example of that code then we are stuck.

Arne
 
B

Bob Bryan

Thank you Peter and Arne for your thoughts about this problem. I take back
what I said about the code throwing an exception. This was due to something
else which I unfortunately attributed to static pointers since the pointer
does show up as zero or some other illegitimate value in the debugger, and
the debug Immediate window also shows the pointer as invalid or pointing to
random memory. The actual execution of the code is working properly with
static pointers both in debug mode and release mode. Peter is right when he
said that this is a debugger problem with displaying or handling the address
of a static pointer. I am going to submit a bug report about this issue to
Microsoft.

Bob Bryan
 

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