2

Please have a look at the following c# code:

    double* ptr;

    fixed(double* vrt_ptr = &vertices[0])
    {
        fixed(int* tris_ptr = &tris[0])
        {
            ptr = compute(vrt_ptr, 5, (double*)tris_ptr, 5);
// compute() is a native C++ function 
        }
    }

    Debug.Log("Vertices Recieved: " + *ptr);
/* and so on */

I am having garbage value from *ptr. I have a suspicion that the array assigned to ptr by compute doesn't retain outside fixed block. Is it so?? Or is it due to some other problem?

Steven
  • 166,672
  • 24
  • 332
  • 435
Cashif Ilyas
  • 1,619
  • 2
  • 14
  • 22
  • 3
    Probably, `compute` returns a pointer to a local variable, destroyed when the function returns. But there's no way to know without seeing the function. – Mike Seymour Nov 26 '13 at 10:52
  • @MikeSeymour Local variable's pointer won't be destroyed as soon as the method returns. isn't it? – Sriram Sakthivel Nov 26 '13 at 10:54
  • Oh.. yes, that's a vector. How can I retain that memory? Using Dynamic allocation?? – Cashif Ilyas Nov 26 '13 at 10:55
  • 1
    @SriramSakthivel: A local variable will be destroyed when the program leaves its scope, and any pointers to it will be left pointing to garbage. – Mike Seymour Nov 26 '13 at 10:55
  • @CashifIlyas: In standard C++, you'd return the vector. I've no idea whether that's possible in whatever mixture of languages you're using. – Mike Seymour Nov 26 '13 at 10:58
  • 1
    @MikeSeymour It seems `compute` is c++ method. I think this is [relevant](http://stackoverflow.com/a/6445794/2530848). I may be wrong. Correct me if am wrong. – Sriram Sakthivel Nov 26 '13 at 10:58
  • Does `compute` allocate memory? If so, how? Does it take GC into consideration? – JeffRSon Nov 26 '13 at 10:58
  • @JeffRSon compute is a c++ function, and it returns a reference to a vector, which now I have known will be pointing to garbage on return. So I think I should allocate memory inside compute. right? – Cashif Ilyas Nov 26 '13 at 11:02
  • 1
    I think it would be better to allocate it before calling `compute` and hand it over to it. Such you could get rid of the spurious `ptr` and it would be more clear if you release the memory later on (in order to prevent a memory leak). – JeffRSon Nov 26 '13 at 11:08
  • @JeffRSon Thanks, gonna try it :) – Cashif Ilyas Nov 26 '13 at 11:11

1 Answers1

3

This is not valid code, the garbage collector can only update the value of the vrt_ptr and tris_ptr variables. But the unmanaged code uses a copy of these pointers, the value of the copy cannot be updated by the GC. So if a garbage collection occurs while the unmanaged code is running, possible for example when other threads in the program trigger a collection, then the unmanaged code will read garbage data through the pointer copy. Very hard to diagnose, it doesn't happen very often.

You must pin the vertices and tris arrays. In your case already ably done by the pinvoke marshaller, simply by passing the arrays directly without using fixed. Fix:

   double* ptr = compute(vertices, 5, tris, 5);

Adjust the pinvoke declaration accordingly, replacing double* with double[].

You'll now also have to the deal with the likely reason you wrote this code in the first place. There is no scenario where casting an int[] to double[] is ever valid, the likely reason you got a garbage result early before that GC disaster could strike. If you can't update the declaration of tris for some reason then you must create a double[] before the call.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536