How easy is it to accidentally not use pin_ptr where you ought to?

  • Thread starter Thread starter David Lowndes
  • Start date Start date
D

David Lowndes

I've got a project with a fair bit of mixed C++/CLI calling native
code, often passing raw pointers - and I'm worrying that we may have
occasions where we don't use pin_ptr when we need to.

However, after a few experiments I was unable to compile code (VS2005)
that casually tried to do the wrong thing.

So, is anyone aware of any common gotchas where you can have code that
compiles cleanly (and works in all tests) that's not using pin_ptr
where it ought to?

Dave
 
I've got a project with a fair bit of mixed C++/CLI calling native
code, often passing raw pointers - and I'm worrying that we may have
occasions where we don't use pin_ptr when we need to.

However, after a few experiments I was unable to compile code (VS2005)
that casually tried to do the wrong thing.

So, is anyone aware of any common gotchas where you can have code that
compiles cleanly (and works in all tests) that's not using pin_ptr
where it ought to?

I know that there were a number of cases in MC++ that gave you enough rope
to hang yourself.
From what I understood, C++/CLI was designed to prevent you from messing up
like that.
I have not yet encountered a situation where I messed up that part.
Of course, that still doesn't really prove that it is impossible.
 
I know that there were a number of cases in MC++ that gave you enough rope
to hang yourself.
From what I understood, C++/CLI was designed to prevent you from messing up
like that.
I have not yet encountered a situation where I messed up that part.
Of course, that still doesn't really prove that it is impossible.

Hi Bruno,

That's the sort of response I was hoping for :)

In the cases where I tried to do it wrong, I got a compiler error - so
I was hoping that short of something wildly underhand that it was
unlikely to be an issue that could be missed.

Cheers
Dave
 
I know that there were a number of cases in MC++ that gave you enough
Hi Bruno,

That's the sort of response I was hoping for :)

In the cases where I tried to do it wrong, I got a compiler error - so
I was hoping that short of something wildly underhand that it was
unlikely to be an issue that could be missed.

Hi David,
Short of purposely doing something very ugly in a multithreaded environment,
I don't think you can mess up. And even then, the runtime and compiler
should prevent you from doing something that bad.
 
David Lowndes said:
Hi Bruno,

That's the sort of response I was hoping for :)

In the cases where I tried to do it wrong, I got a compiler error - so
I was hoping that short of something wildly underhand that it was
unlikely to be an issue that could be missed.

As long as you are using safe_cast and static_cast, not reinterpret_cast or
old-style casts, the compiler should protect you.
 
As long as you are using safe_cast and static_cast, not reinterpret_cast or
old-style casts, the compiler should protect you.

In the attempt I had, I couldn't even fool it with those - though I
didn't try too hard. Let me rephrase that - I could get something to
compile with the heavy handed casts - but not something that worked.

What I couldn't do was get something to compile that worked (and would
have been susceptible to the managed heap movements that pin_ptr
prevents) - it was those specific situations I was worried about since
they'd pass casual tests but would likely fail in weird unpredictable
ways in the real world.

Dave
 
Hi David,

David Lowndes said:
In the attempt I had, I couldn't even fool it with those - though I
didn't try too hard. Let me rephrase that - I could get something to
compile with the heavy handed casts - but not something that worked.

What I couldn't do was get something to compile that worked (and would
have been susceptible to the managed heap movements that pin_ptr
prevents) - it was those specific situations I was worried about since
they'd pass casual tests but would likely fail in weird unpredictable
ways in the real world.

Dave

I do not necessarily agree with the other statements. IMO there *is* a need
for special care with pin pointers:

Let's start with a dumb scenario:

unsigned char* NeverDoThis(array<unsigned char>^ arr)
{
pin_ptr<unsigned char> pp(&arr[0]);
return pp;
}

In this case, you pin a pointer to a managed array, use the standard
conversion to get a native pointer, and return the native pointer to the
caller. After the method has returned, the array is no longer pinned and
could be relocated, but the native pointer would still refer to the old
location. Let's have a look at a less dumb scenario:

Assume you have a managed array:
array<unsinged char>^ arr = GetArrayFromSomeWhere();

Further assume you want to pass a native pointer to the array to a native
function like this one:

void DoSth(unsigned char*);

To achieve this, you could write:
{
pin_ptr<unsigned char> pp(&arr[0]);
DoSth(pp);
}

Is this code safe? Well that depends on the implementation of DoSth. If
DoSth stores the native pointer to access the array after the call, this
code as a problem, because the pinnng time ends after the pointer left
scope.

Marcus Heege
 
Hi Markus,

Thanks for the comments.
Let's start with a dumb scenario:

I sincerely hope we don't have any of those :) I'm pretty sure we
don't in fact.
Assume you have a managed array:
...
{
pin_ptr<unsigned char> pp(&arr[0]);
DoSth(pp);
}

Is this code safe? Well that depends on the implementation of DoSth. If
DoSth stores the native pointer to access the array after the call, this
code as a problem, because the pinnng time ends after the pointer left
scope.

Yeah, they're both examples of the same situation really - using the
pinned native pointer outside the pinning scope.

I was really more concerned with any more direct situations where you
could fail to use pin_ptr where it was really necessary.

The first example is fairly easy to check for, but as you say the
second one isn't (as we're using a 3'rd party library that we don't
have the source to).

Are there any diagnostic tools that would help flush out problems
where the managed heap moves? Something that explicitly causes lots of
managed heap movements?

Dave
 
Back
Top