[DUG] [computing] Sizeof record gives error

Rohit Gupta rohit at cfl.co.nz
Tue Aug 30 09:10:19 NZST 2011


Joylon,

Good point.  But I dont think it applies here.  Sizeof returns an 
incorrect result... Its a compiler flaw.

Rohit



On 29/08/2011 8:10 p.m., Jolyon Smith wrote:
> Having just looked up the references for New/GetMem it may not 
> actually be a question of amount of memory allocated after all, but 
> rather one of correct initialization of the allocated memory.
>
> GetMem() does not initialize the allocated memory, New() does.
>
> This is explained in the documentation for the "Initialize()" 
> procedure (it might have been helpful if the documentation for 
> GetMem() had mentioned this - or the lack there-of - too - LOL)
>
> So you might find that GetMem() would have worked had you also called 
> Initialise() on the pointer afterward (and Finalize() before calling 
> FreeMem()).  But whatever the underlying reasons it is obviously 
> simply much easier and safer (less to remember to have to do, less to 
> get wrong in doing it :)) to use New/Dispose when working with 
> allocations of variables/structured(typed) memory and use 
> GetMem/FreeMem when it is strictly speaking *just* unstructured memory 
> you need (e.g. i/o buffers etc), rather than space for variables.
>
> Glad it helped with your problem in any event.  :)
>
>
> On 29 August 2011 17:40, David Moorhouse <delphi at moorhouse.net.nz 
> <mailto:delphi at moorhouse.net.nz>> wrote:
>
>     I'm aware of the compiler layout behind the scene - and the fact
>     that regardless of the length of the dynamic array, my call to
>     GetMem (or New) does NOT have to allocate memory for the dynamic
>     array's contents, just it's overhead :)
>
>     However, the compiler gets the size right using New rather than
>     GetMem :) So thanks for the tip.
>
>     Cheers
>
>     D
>
>
>
>
>
>     On 29/08/11 16:23, Jolyon Smith wrote:
>>     Is it a compiler *error* or just a compiler _behaviour_ ?
>>
>>     I haven't looked into it in detail, but dynamic arrays are
>>     notoriously slippery when you are working with them at a low
>>     level and alarm bells started ringing as soon as I saw they were
>>     involved.
>>
>>     In particular, a dynamic array is a reference type, like a
>>     string.  So whilst their may be additional RTTI at a negative
>>     offset from the base address of the array, the "array" itself may
>>     well be a pointer, hence "sizeof()" will return 4 - the size of a
>>     pointer - no matter how many items may be in the array (as
>>     opposed to Length(), obviously).
>>
>>     NOTE:   sizeof(String) also yields "4" even though we all know
>>     that a String variable requires many more bytes than that.
>>
>>
>>     As far as this particular example goes, do you get any better
>>     results using the typed New() function rather than GetMem() which
>>     knows nothing about the "type" of memory required by the pointer
>>     you are initialising and just blithely allocates the specified
>>     number of bytes...:
>>
>>     Instead of >>   LogData := GetMem( ... );
>>
>>     Use >>   New( LogData );
>>
>>     And see if you get better results.  :)
>>
>>     (Also, don't forget to use "Dispose()" to deallocate the memory
>>     obtained with "New()", rather than FreeMem())
>>
>>
>>     On 28 August 2011 21:33, David Moorhouse (DUG)
>>     <delphi at moorhouse.net.nz <mailto:delphi at moorhouse.net.nz>> wrote:
>>
>>         I believe it is a compiler error and will raise a QA ticket
>>
>>         Thanks for your  help
>>
>>
>>         D
>>
>>
>>         On 26/08/11 08:17, Peter Ingham wrote:
>>         > Try filling LogData with binary zeros after the Getmem&
>>          before the assign.
>>         >
>>         > FillChar (LogData^, sizeof(TLogData), 0);
>>         >
>>         > I believe the uninitialized memory is messing up the
>>         compiler magic
>>         > associated with the dynamic array.
>>         >
>>         >
>>         > Any reason the local Tlogdata record is referenced via a
>>         pointer?
>>         >
>>         > I suspect the following will also work:
>>         > procedure TUserClass.Log(const LogType: TLogType; const
>>         Args: array of
>>         > const );
>>         >    var
>>         >       LogData: TLogData;
>>         >     begin
>>         >       LogData.LogType := LogType;
>>         >       LogData.LogArgs := CreateConstArray(Args);
>>         >       //  ... do some other stuff with the LogData item
>>         finally calling
>>         >     end;
>>         >
>>         > Cheers
>>         >
>>         > On 26/08/2011 1:49 a.m., David Moorhouse wrote:
>>         >> Hi Peter
>>         >>
>>         >> Been there done that :)
>>         >>
>>         >> The function call is fine.  It is the assignment that
>>         causes the AV -
>>         >> because the "bucket" is too small.
>>         >> Assigning it with 16 bytes fixes the problem, regardless
>>         of how many
>>         >> items the array holds.
>>         >>
>>         >> I smell compiler magic in the background.
>>         >>
>>         >> Cheers
>>         >
>>         >> D
>>         >>
>>         >> On 25/08/11 17:29, Peter Ingham wrote:
>>         >>> Another attempt to reply...
>>         >>>
>>         >>> First thing to do is determine if the crash occurs in the
>>         procedure call,
>>         >>> on the subsequent assign, or in between.
>>         >>>
>>         >>> Give this a try:
>>         >>>    procedure TUserClass.Log(const LogType: TLogType;
>>         const Args: array of
>>         >>>    const );
>>         >>>    var
>>         >>>      LogData: PLogData;
>>         >>>     TempArgs : TConstArray;
>>         >>>    begin
>>         >>>        // size of record TLogData does not work
>>         >>>        GetMem(LogData, sizeof(TLogData));
>>         >>>        LogData.LogType := LogType;
>>         >>>    // blows up on one of these lines
>>         >>>        TempArgs  := CreateConstArray(Args);
>>         >>>        LogData.LogArgs := TempArgs;
>>         >>>    //  ... do some other stuff with the LogData item
>>         finally calling
>>         >>> FreeMem
>>         >>>    end;
>>         >>>
>>         >>>
>>         >>> Regarding the size of a dynamic array,  like a string
>>         variable,  the
>>         >>> variable (LogArgs in this case) is the size of a pointer
>>         (i.e. 4 bytes
>>         >>> for Win32).  If the pointer is non-zero, it points to a
>>         structure which
>>         >>> includes the adjacent array elements preceded by a length.
>>         >>>
>>         >>> One thing to watch out for is that Getmem does not clear
>>         the allocated
>>         >>> memory, so LogData after the Getmem call will contain any
>>         old rubbish.
>>         >>> The reference to LogData.LogArgs in the assignment may be
>>         >>> dereferencing a non-zero pointer&   attempting to use
>>         whatever it
>>         >>> contains.
>>         >>>
>>         >>> Cheers
>>         >>>
>>         >>>
>>         >>> On 25/08/2011 11:40 a.m., David Moorhouse (DUG) wrote:
>>         >>>> I have the following code snippet
>>         >>>>
>>         >>>> <code>
>>         >>>> type
>>         >>>>      PConstArray = ^TConstArray;
>>         >>>>      TConstArray = array of TVarRec;
>>         >>>>
>>         >>>> function CreateConstArray(const Elements: array of
>>         const): TConstArray;
>>         >>>>
>>         >>>> type
>>         >>>>      TLogType = (ltError, ltWarn, ltInfo);
>>         >>>>      PLogData = ^TLogData;
>>         >>>>      TLogData = record
>>         >>>>        LogType: TLogType;
>>         >>>>        LogArgs: TConstArray;
>>         >>>>      end;
>>         >>>>
>>         >>>> ....
>>         >>>>
>>         >>>> procedure TUserClass.Log(const LogType: TLogType; const
>>         Args: array of
>>         >>>> const );
>>         >>>> var
>>         >>>>      LogData: PLogData;
>>         >>>> begin
>>         >>>>        // size of record TLogData does not work
>>         >>>>        GetMem(LogData, sizeof(TLogData));
>>         >>>>        LogData.LogType := LogType;
>>         >>>> // blows up on next line
>>         >>>>        LogData.LogArgs := CreateConstArray(Args);
>>         >>>> //  ... do some other stuff with the LogData item
>>         finally calling
>>         >>>> FreeMem
>>         >>>> end;
>>         >>>>
>>         >>>> function CreateConstArray(const Elements: array of
>>         const): TConstArray;
>>         >>>> var
>>         >>>>      I: Integer;
>>         >>>> begin
>>         >>>>      SetLength(Result, Length(Elements));
>>         >>>>      for I := Low(Elements) to High(Elements) do
>>         >>>>        Result[I] :=  // assign a TVarRec here
>>         >>>> end;
>>         >>>> </code>
>>         >>>>
>>         >>>> The code that assigns the memory only assigns 8 bytes -
>>         and an access
>>         >>>> violation ensues.  If I replace the call to "sizeof"
>>         with the number 16,
>>         >>>> the code works fine.
>>         >>>>
>>         >>>> My understanding of dynamic arrays was that the compiler
>>         created a 4
>>         >>>> byte
>>         >>>> field before the first element that contained the length
>>         of the array.
>>         >>>>
>>         >>>> So why does the sizeof  function not reflect this ?  And
>>         why do I
>>         >>>> need 16
>>         >>>> bytes not 12  (4 for LogType + 4 for length of array + 4
>>         for array
>>         >>>> pointer)?
>>         >>>> Also regardless of the number of items in the open array
>>         parameter, 16
>>         >>>> bytes works, so it does not relate the length of the
>>         TConstArray.
>>         >>>>
>>         >>>> Your thoughts ?
>>         >>>>
>>         >>>> David
>>         >>>>
>>         >>>>
>>

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://listserver.123.net.nz/pipermail/delphi/attachments/20110830/56e2dbba/attachment-0001.html 


More information about the Delphi mailing list