www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - return *(cast(T*)vPtr) and OutOfMemoryException

reply TSalm <TSalm free.fr> writes:
Hello,

In the code below, why the first Stdout throws a Exception when the second  
doesn't ?

/*  -------- CODE --------   */
import tango.io.Stdout;


struct VoidPtr(T)
{
   void* vPtr;

   void value(T val)
   {
     vPtr = &val;
   }

   T value()
   {
     return *(cast(T*)vPtr);
   }
}


void main()
{
   VoidPtr!(char[][]) vPtr ;

   char[][]  arr = [ "hello" , "you" ];

   vPtr.value =  arr ;

   Stdout( vPtr.value ).newline; // <--  
[tango.core.Exception.OutOfMemoryException: Memory allocation failed

   Stdout( *(cast(char[][]*) vPtr.vPtr ) ); // <-- This works good
}

/*  ------ END CODE ------  */


Thanks in advance for your help,
TSalm
Feb 14 2009
parent reply Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
TSalm wrote:
 Hello,
 
 In the code below, why the first Stdout throws a Exception when the 
 second doesn't ?
 
 /*  -------- CODE --------   */
 import tango.io.Stdout;
 
 
 struct VoidPtr(T)
 {
   void* vPtr;
 
   void value(T val)
   {
     vPtr = &val;
Here you're storing a pointer to a non-ref parameter. This is the bug; the parameter itself is implicitly deallocated on returning from this function. Change to 'ref T val' to fix it. Essentially, an array is a struct { size_t length; T ptr; }. This means 'val' refers to a copy in the stack frame of this function, not to 'arr' in main().
   }
 
   T value()
   {
     return *(cast(T*)vPtr);
   }
 }
 
 
 void main()
 {
   VoidPtr!(char[][]) vPtr ;
 
   char[][]  arr = [ "hello" , "you" ];
 
   vPtr.value =  arr ;
 
   Stdout( vPtr.value ).newline; // <-- 
 [tango.core.Exception.OutOfMemoryException: Memory allocation failed
Here you're calling a new function, overwriting *vPtr with something else (probably vptr itself), resulting in a huge array when you try to read it later.
 
   Stdout( *(cast(char[][]*) vPtr.vPtr ) ); // <-- This works good
This reads the (implicitly deallocated) 'val' parameter before it gets overwritten, hiding the bug. It's still there: just because the code doesn't crash doesn't mean it's correct.
 }
 
 /*  ------ END CODE ------  */
 
 
 Thanks in advance for your help,
 TSalm
Feb 14 2009
parent TSalm <TSalm free.fr> writes:
Excellent explication !
Thank you Frits

Le Sat, 14 Feb 2009 17:58:35 +0100, Frits van Bommel  
<fvbommel remwovexcapss.nl> a écrit:

 TSalm wrote:
 Hello,
  In the code below, why the first Stdout throws a Exception when the  
 second doesn't ?
  /*  -------- CODE --------   */
 import tango.io.Stdout;
   struct VoidPtr(T)
 {
   void* vPtr;
    void value(T val)
   {
     vPtr = &val;
Here you're storing a pointer to a non-ref parameter. This is the bug; the parameter itself is implicitly deallocated on returning from this function. Change to 'ref T val' to fix it. Essentially, an array is a struct { size_t length; T ptr; }. This means 'val' refers to a copy in the stack frame of this function, not to 'arr' in main().
   }
    T value()
   {
     return *(cast(T*)vPtr);
   }
 }
   void main()
 {
   VoidPtr!(char[][]) vPtr ;
    char[][]  arr = [ "hello" , "you" ];
    vPtr.value =  arr ;
    Stdout( vPtr.value ).newline; // <--  
 [tango.core.Exception.OutOfMemoryException: Memory allocation failed
Here you're calling a new function, overwriting *vPtr with something else (probably vptr itself), resulting in a huge array when you try to read it later.
    Stdout( *(cast(char[][]*) vPtr.vPtr ) ); // <-- This works good
This reads the (implicitly deallocated) 'val' parameter before it gets overwritten, hiding the bug. It's still there: just because the code doesn't crash doesn't mean it's correct.
 }
  /*  ------ END CODE ------  */
   Thanks in advance for your help,
 TSalm
Feb 14 2009