comp.lang.ada
 help / color / mirror / Atom feed
From: M E Leypold <development-2006-8ecbb5cc8aREMOVETHIS@ANDTHATm-e-leypold.de>
Subject: And a Workaround: Was: A smaller test case / Compiler Bug
Date: 23 Jun 2006 13:04:56 +0200
Date: 2006-06-23T13:04:56+02:00	[thread overview]
Message-ID: <u2veqsjfon.fsf_-_@hod.lan.m-e-leypold.de> (raw)
In-Reply-To: t3k678yz5g.fsf@hod.lan.m-e-leypold.de



Dear All,

Here is a workaround for the problem with reading/writing variant
records with finalizers which I reported before.

One should override the read/write attributes of the record in
question. The substituted procedures should 

  - write the discriminant first, then the appropriate variant part.

  - read the discriminant value, explicitly set the discriminant field
    in the buffer variable and then read the appropriate variant part.

"Fixed" test case has been attached.

Presently my idea about the source of the bug is, that the compiler
generates wrong code for reading records with discriminants.

Before it sets the discriminant field in the variable, it doesn't run
appropriate finalizers and initializers on possibly changed variant
parts, but just sets the discriminant field and the invokes the read
procedure for the appropriate variant part. Of course at that time the
bit patterns in record representation are not appropriate for the
discriminant (the representation is invalid) but mostly that doesn't
matter since the invalid representation is overwritten anyway. It does
matter though in the case that the variant part visible after changing
the discriminant value contains fields with controlled data types:
Then finalizers are run on invalid variable content. In my case that
triggered a problem in the underlying libc malloc().

The problem should only happen if there are variant parts where a
variant part has fields with finalizers _AND_ the representation
doesn't overlap with that of the other variant parts (in my test case
the problem goes away if the fields with finalizers are just 2
Unbounded_Strings, one at the beginning of every variant part, which
could be explained by the finalizer running as a finalizer of the
wrong variant part but still being a finalizer of Unbounded_String and
thus correctly finalizing the Unbounded_String in the now hidden
variant part.)

Depending on the finalizers all that leads to erronous memory
deallocation or that some finalization action is dropped (I've not
verfied this, but I predict that will probably happen).

The bug should in example result in memory leaks if the variant part
incoreectly hidden during reading contains finalizers concerned with
freeing memory which then are not run.

All that is conjecture at the moment but well in agreement with the
evidence so far.


Regards -- Markus


----

    with Ada.Streams.Stream_IO; use  Ada.Streams.Stream_IO;
    with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;

    procedure Demo.Bug3 is

       type Customer_Description( Is_Company : Boolean := True ) is record

          case Is_Company Is

             when  True   =>

                Foo                 : Integer := 0;       -- remove these and the
                Bar                 : Integer := 0;       -- SIGSEGV goes away
                Company_Name        : Unbounded_String ;

             when  False  =>

                Persons_Name        : Unbounded_String;

             when   others  =>  null;
          end case;
       end record;

       procedure Write_Customer_Description
         ( S : access Ada.Streams.Root_Stream_Type'Class;
           R : in Customer_Description
         );

       procedure Read_Customer_Description
         ( S : access Ada.Streams.Root_Stream_Type'Class;
           R : out Customer_Description
         );


       for Customer_Description'Write use Write_Customer_Description;
       for Customer_Description'Read  use Read_Customer_Description;


       procedure Set_Zugang ( D :  in out Customer_Description ; Z : Boolean ) is begin

          if Z /= D.Is_Company then

             case Z is

                when True      =>
                   declare New_D : Customer_Description(True);
                   begin
                      D := New_D ;
                   end;

                when False  =>
                   declare New_D : Customer_Description(False);
                   begin   D := New_D ; end;

             end case;
          end if;
       end;


       procedure Write_Customer_Description
         ( S : access Ada.Streams.Root_Stream_Type'Class;
           R : in Customer_Description
         )
       is begin
          Boolean'Write(S,R.Is_Company);
          case R.Is_Company is

             when True =>
                Integer'Write( S, R.Foo );
                Integer'Write( S, R.Bar );
                Unbounded_String'Write( S, R.Company_Name );

             when False =>
                Unbounded_String'Write( S, R.Persons_Name );
          end case;
       end;


       procedure Read_Customer_Description
         ( S : access Ada.Streams.Root_Stream_Type'Class;
           R : out Customer_Description
         )
       is
          B : Boolean;
       begin
          Boolean'Read(S,B);
          Set_Zugang( R, B);

          case R.Is_Company is

             when True =>
                Integer'Read( S, R.Foo );
                Integer'Read( S, R.Bar );
                Unbounded_String'Read( S, R.Company_Name );

             when False =>
                Unbounded_String'Read( S, R.Persons_Name );
          end case;
       end;


       procedure Write_Record
       is
         F : File_Type;
         S : Stream_Access;
         R : Customer_Description;
       begin
          Create( F , Name => "tmp-bug3" );
          S := Stream(F);
          Set_Zugang(R, False);                   -- remove this and the SIGSEGV goes away

          for I in 1 .. 400 loop
             Customer_Description'Write(S,R);     -- [1a]
          end loop;

          Close(F);
       end;


       procedure Get_Record
       is
          F : File_Type;
          S : Stream_Access;
       begin

          Open( F , Mode => In_File, Name => "tmp-bug3" );
          S := Stream(F);

          for I in 1 .. 400 loop
             declare R : Customer_Description;
             begin
                Customer_Description'Read(S,R);        -- [1b]
             end;
          end loop;

          Close( F );
       end;

       R : Customer_Description;

    begin
       Write_Record;
       Get_Record;
    end;



  parent reply	other threads:[~2006-06-23 11:04 UTC|newest]

Thread overview: 52+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2006-06-20 16:56 Compiler Bug or what I'm doing wrong? M E Leypold
2006-06-21  7:44 ` Ludovic Brenta
2006-06-21 12:29   ` M E Leypold
2006-06-21 12:46     ` Alex R. Mosteo
2006-06-21 13:23       ` M E Leypold
2006-06-22 19:10         ` Simon Wright
2006-06-23  8:24         ` Ludovic Brenta
2006-06-23 13:14         ` Alex R. Mosteo
2006-06-23 13:24           ` Alex R. Mosteo
2006-06-24 20:33             ` Simon Wright
2006-06-24 20:56               ` M E Leypold
2006-06-26  7:32                 ` Ludovic Brenta
2006-06-26 11:16                   ` M E Leypold
2006-06-26 12:13                     ` [Ada in Debian] GtkAda and GNAT versions Ludovic Brenta
2006-06-26 12:25                       ` M E Leypold
2006-06-27 20:55                   ` Compiler Bug or what I'm doing wrong? Simon Wright
2006-06-27 22:26                     ` Ludovic Brenta
2006-06-22  2:07       ` James Dennett
2006-06-22  6:37         ` Duncan Sands
2006-06-22 16:53           ` M E Leypold
2006-06-22 19:01             ` Pascal Obry
2006-06-23  8:37               ` M E Leypold
2006-06-22 19:05             ` Dmitry A. Kazakov
2006-06-23  4:47               ` Jeffrey R. Carter
2006-06-23 12:26               ` Stephen Leake
2006-06-23 13:11                 ` Dmitry A. Kazakov
2006-06-23 13:15                 ` Alex R. Mosteo
2006-06-23  9:55 ` A smaller self contained test case. Was: " M E Leypold
2006-06-23 10:03   ` M E Leypold
2006-06-23 11:04   ` M E Leypold [this message]
2006-06-23 11:12     ` Possible memory leaks when reading/writing variant records M E Leypold
2006-06-24 11:46   ` A smaller self contained test case. Was: Compiler Bug or what I'm doing wrong? Dmitry A. Kazakov
2006-06-24 12:27     ` M E Leypold
2006-06-24 12:52       ` Dmitry A. Kazakov
2006-06-24 13:53         ` M E Leypold
2006-06-24 19:58           ` Dmitry A. Kazakov
2006-06-24 20:22             ` M E Leypold
2006-06-25  7:59               ` Dmitry A. Kazakov
2006-06-25 10:51                 ` M E Leypold
2006-06-26  6:22                   ` Martin Dowie
2006-06-24 21:21             ` M E Leypold
2006-06-25 21:36   ` M E Leypold
2006-06-26 21:53   ` Possibly fixed in gcc 4.1.1, but bug box -- Was: Re: A smaller self contained test case M E Leypold
2006-06-27 18:24     ` Alex R. Mosteo
2006-06-27 22:58       ` M E Leypold
2006-06-28 10:32         ` Alex R. Mosteo
2006-07-03  1:38         ` Steve Whalen
2006-07-03 10:36           ` M E Leypold
2006-06-28  8:41       ` Ludovic Brenta
2006-06-28  8:51         ` Georg Bauhaus
2006-06-28 10:43         ` Alex R. Mosteo
2006-06-23 10:00 ` Compiler Bug or what I'm doing wrong? M E Leypold
replies disabled

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox