|
From: stefan-lucks on 4 Apr 2008 05:33 Hi, I have written a little program to demonstrate finalisation. The idea is to locally declare a singelton object of a class derived from Ada.Finalization.Limited_Controlled, and to override the Finalize method. When the sigelton object leaves scope, Finalize than cleans up whatever needs to be cleaned up. At a first look this appeared to work nicely. But when done in a recursive subprogram, Finalize rather unexpectedly seems to always read the local parameters of the innermost scope. Here is a test case: ---begin fin_test_case.adb with Ada.Text_IO, Ada.Finalization; procedure Fin_Test_Case is type Fin is new Ada.Finalization.Limited_Controlled with null record; procedure Do_Something (I: Natural) is type My_Fin is new Fin with null record; overriding procedure Finalize(Self: in out My_Fin) is S: String := Natural'Image(I); begin Ada.Text_IO.Put_Line(" Do_Something Finalization " & S); end Finalize; Singleton: My_Fin; begin -- Do_Something Ada.Text_IO.Put_Line(" I = " & Natural'Image(I)); if I>0 then Do_Something(I-1); Do_Something(I-1); end if; end Do_Something; begin Ada.Text_IO.Put_Line("Start Do_Something (2)"); Do_Something(2); Ada.Text_IO.Put_Line("Stop Do_Something (2)"); end Fin_Test_Case; ---end fin_test_case.adb This is what I got: ---begin output Start Do_Something (2) I = 2 I = 1 I = 0 Do_Something Finalization 0 I = 0 Do_Something Finalization 0 Do_Something Finalization 0 I = 1 I = 0 Do_Something Finalization 0 I = 0 Do_Something Finalization 0 Do_Something Finalization 0 Do_Something Finalization 0 Stop Do_Something (2) ---end output Somehow, the local parameter I is always 0 when finalize is called. What I expected was the following: ---begin expected output Start Do_Something (2) I = 2 I = 1 I = 0 Do_Something Finalization 0 I = 0 Do_Something Finalization 0 Do_Something Finalization 1 I = 1 I = 0 Do_Something Finalization 0 I = 0 Do_Something Finalization 0 Do_Something Finalization 1 Do_Something Finalization 2 Stop Do_Something (2) ---end expected output Now, is my expectation wrong? Or is this a compiler bug? I am using GNAT GPL 2007 (20070405-41). So long Stefan -- ------ Stefan Lucks -- Bauhaus-University Weimar -- Germany ------ Stefan dot Lucks at uni minus weimar dot de ------ I love the taste of Cryptanalysis in the morning! ------
From: Adam Beneschan on 4 Apr 2008 12:08 On Apr 4, 2:33 am, stefan-lu...(a)see.the.signature wrote: > Hi, > > I have written a little program to demonstrate finalisation. The idea is > to locally declare a singelton object of a class derived from > Ada.Finalization.Limited_Controlled, and to override the Finalize method. > When the sigelton object leaves scope, Finalize than cleans up whatever > needs to be cleaned up. At a first look this appeared to work nicely. But > when done in a recursive subprogram, Finalize rather unexpectedly seems to > always read the local parameters of the innermost scope. > > Here is a test case: > > ---begin fin_test_case.adb > > with Ada.Text_IO, Ada.Finalization; > > procedure Fin_Test_Case is > type Fin is new Ada.Finalization.Limited_Controlled with null record; > > procedure Do_Something (I: Natural) is > > type My_Fin is new Fin with null record; > > overriding procedure Finalize(Self: in out My_Fin) is > S: String := Natural'Image(I); > begin > Ada.Text_IO.Put_Line(" Do_Something Finalization " & S); > end Finalize; > > Singleton: My_Fin; > > begin -- Do_Something > Ada.Text_IO.Put_Line(" I = " & Natural'Image(I)); > if I>0 then > Do_Something(I-1); > Do_Something(I-1); > end if; > end Do_Something; > > begin > Ada.Text_IO.Put_Line("Start Do_Something (2)"); > Do_Something(2); > Ada.Text_IO.Put_Line("Stop Do_Something (2)"); > end Fin_Test_Case; > > ---end fin_test_case.adb > > This is what I got: > > ---begin output > > Start Do_Something (2) > I = 2 > I = 1 > I = 0 > Do_Something Finalization 0 > I = 0 > Do_Something Finalization 0 > Do_Something Finalization 0 > I = 1 > I = 0 > Do_Something Finalization 0 > I = 0 > Do_Something Finalization 0 > Do_Something Finalization 0 > Do_Something Finalization 0 > Stop Do_Something (2) > > ---end output > > Somehow, the local parameter I is always 0 when finalize is called. What I > expected was the following: > > ---begin expected output > > Start Do_Something (2) > I = 2 > I = 1 > I = 0 > Do_Something Finalization 0 > I = 0 > Do_Something Finalization 0 > Do_Something Finalization 1 > I = 1 > I = 0 > Do_Something Finalization 0 > I = 0 > Do_Something Finalization 0 > Do_Something Finalization 1 > Do_Something Finalization 2 > Stop Do_Something (2) > > ---end expected output > > Now, is my expectation wrong? Or is this a compiler bug? I am using > GNAT GPL 2007 (20070405-41). This looks like a pretty clear compiler bug, especially since by the time Finalize is called by the outermost Do_Something, it's using, for the value of I, the parameter from a Do_Something call that is no longer active. It shouldn't be hard to modify this slightly, using (say) a string or record as a parameter to Do_Something, to create a test where utter garbage is displayed; then it would be clearer that this is a compiler bug. -- Adam
From: george.priv on 4 Apr 2008 13:34 On Apr 4, 12:08 pm, Adam Beneschan <a...(a)irvine.com> wrote: > On Apr 4, 2:33 am, stefan-lu...(a)see.the.signature wrote: > > > > > Hi, > > > I have written a little program to demonstrate finalisation. The idea is > > to locally declare a singelton object of a class derived from > > Ada.Finalization.Limited_Controlled, and to override the Finalize method. > > When the sigelton object leaves scope, Finalize than cleans up whatever > > needs to be cleaned up. At a first look this appeared to work nicely. But > > when done in a recursive subprogram, Finalize rather unexpectedly seems to > > always read the local parameters of the innermost scope. > > > Here is a test case: > > > ---begin fin_test_case.adb > > > with Ada.Text_IO, Ada.Finalization; > > > procedure Fin_Test_Case is > > type Fin is new Ada.Finalization.Limited_Controlled with null record; > > > procedure Do_Something (I: Natural) is > > > type My_Fin is new Fin with null record; > > > overriding procedure Finalize(Self: in out My_Fin) is > > S: String := Natural'Image(I); > > begin > > Ada.Text_IO.Put_Line(" Do_Something Finalization " & S); > > end Finalize; > > > Singleton: My_Fin; > > > begin -- Do_Something > > Ada.Text_IO.Put_Line(" I = " & Natural'Image(I)); > > if I>0 then > > Do_Something(I-1); > > Do_Something(I-1); > > end if; > > end Do_Something; > > > begin > > Ada.Text_IO.Put_Line("Start Do_Something (2)"); > > Do_Something(2); > > Ada.Text_IO.Put_Line("Stop Do_Something (2)"); > > end Fin_Test_Case; > > > ---end fin_test_case.adb > > > This is what I got: > > > ---begin output > > > Start Do_Something (2) > > I = 2 > > I = 1 > > I = 0 > > Do_Something Finalization 0 > > I = 0 > > Do_Something Finalization 0 > > Do_Something Finalization 0 > > I = 1 > > I = 0 > > Do_Something Finalization 0 > > I = 0 > > Do_Something Finalization 0 > > Do_Something Finalization 0 > > Do_Something Finalization 0 > > Stop Do_Something (2) > > > ---end output > > > Somehow, the local parameter I is always 0 when finalize is called. What I > > expected was the following: > > > ---begin expected output > > > Start Do_Something (2) > > I = 2 > > I = 1 > > I = 0 > > Do_Something Finalization 0 > > I = 0 > > Do_Something Finalization 0 > > Do_Something Finalization 1 > > I = 1 > > I = 0 > > Do_Something Finalization 0 > > I = 0 > > Do_Something Finalization 0 > > Do_Something Finalization 1 > > Do_Something Finalization 2 > > Stop Do_Something (2) > > > ---end expected output > > > Now, is my expectation wrong? Or is this a compiler bug? I am using > > GNAT GPL 2007 (20070405-41). > > This looks like a pretty clear compiler bug, especially since by the > time Finalize is called by the outermost Do_Something, it's using, for > the value of I, the parameter from a Do_Something call that is no > longer active. It shouldn't be hard to modify this slightly, using > (say) a string or record as a parameter to Do_Something, to create a > test where utter garbage is displayed; then it would be clearer that > this is a compiler bug. > > -- Adam
From: george.priv on 4 Apr 2008 13:38 On Apr 4, 12:08 pm, Adam Beneschan <a...(a)irvine.com> wrote: > On Apr 4, 2:33 am, stefan-lu...(a)see.the.signature wrote: > > > > > Hi, > > > I have written a little program to demonstrate finalisation. The idea is > > to locally declare a singelton object of a class derived from > > Ada.Finalization.Limited_Controlled, and to override the Finalize method. > > When the sigelton object leaves scope, Finalize than cleans up whatever > > needs to be cleaned up. At a first look this appeared to work nicely. But > > when done in a recursive subprogram, Finalize rather unexpectedly seems to > > always read the local parameters of the innermost scope. > > > Here is a test case: > > > ---begin fin_test_case.adb > > > with Ada.Text_IO, Ada.Finalization; > > > procedure Fin_Test_Case is > > type Fin is new Ada.Finalization.Limited_Controlled with null record; > > > procedure Do_Something (I: Natural) is > > > type My_Fin is new Fin with null record; > > > overriding procedure Finalize(Self: in out My_Fin) is > > S: String := Natural'Image(I); > > begin > > Ada.Text_IO.Put_Line(" Do_Something Finalization " & S); > > end Finalize; > > > Singleton: My_Fin; > > > begin -- Do_Something > > Ada.Text_IO.Put_Line(" I = " & Natural'Image(I)); > > if I>0 then > > Do_Something(I-1); > > Do_Something(I-1); > > end if; > > end Do_Something; > > > begin > > Ada.Text_IO.Put_Line("Start Do_Something (2)"); > > Do_Something(2); > > Ada.Text_IO.Put_Line("Stop Do_Something (2)"); > > end Fin_Test_Case; > > > ---end fin_test_case.adb > > > This is what I got: > > > ---begin output > > > Start Do_Something (2) > > I = 2 > > I = 1 > > I = 0 > > Do_Something Finalization 0 > > I = 0 > > Do_Something Finalization 0 > > Do_Something Finalization 0 > > I = 1 > > I = 0 > > Do_Something Finalization 0 > > I = 0 > > Do_Something Finalization 0 > > Do_Something Finalization 0 > > Do_Something Finalization 0 > > Stop Do_Something (2) > > > ---end output > > > Somehow, the local parameter I is always 0 when finalize is called. What I > > expected was the following: > > > ---begin expected output > > > Start Do_Something (2) > > I = 2 > > I = 1 > > I = 0 > > Do_Something Finalization 0 > > I = 0 > > Do_Something Finalization 0 > > Do_Something Finalization 1 > > I = 1 > > I = 0 > > Do_Something Finalization 0 > > I = 0 > > Do_Something Finalization 0 > > Do_Something Finalization 1 > > Do_Something Finalization 2 > > Stop Do_Something (2) > > > ---end expected output > > > Now, is my expectation wrong? Or is this a compiler bug? I am using > > GNAT GPL 2007 (20070405-41). > > This looks like a pretty clear compiler bug, especially since by the > time Finalize is called by the outermost Do_Something, it's using, for > the value of I, the parameter from a Do_Something call that is no > longer active. It shouldn't be hard to modify this slightly, using > (say) a string or record as a parameter to Do_Something, to create a > test where utter garbage is displayed; then it would be clearer that > this is a compiler bug. > > -- Adam With little modification: procedure Fin_Test_Case is type Fin is new Ada.Finalization.Limited_Controlled with null record; procedure Do_Something (I: Natural) is type My_Fin(X : natural) is new Fin with null record; overriding procedure Finalize(Self: in out My_Fin) is S: String := Natural'Image(I) & ':' & Natural'Image(Self.X); begin Ada.Text_IO.Put_Line(" Do_Something Finalization " & S); end Finalize; Singleton: My_Fin(i); begin -- Do_Something Ada.Text_IO.Put_Line(" I = " & Natural'Image(I)); if I>0 then Do_Something(I-1); Do_Something(I-1); end if; end Do_Something; begin Ada.Text_IO.Put_Line("Start Do_Something (2)"); Do_Something(2); Ada.Text_IO.Put_Line("Stop Do_Something (2)"); end Fin_Test_Case; The result becomes: Start Do_Something (2) I = 2 I = 1 I = 0 Do_Something Finalization 0: 0 I = 0 Do_Something Finalization 0: 0 Do_Something Finalization 0: 1 I = 1 I = 0 Do_Something Finalization 0: 0 I = 0 Do_Something Finalization 0: 0 Do_Something Finalization 0: 1 Do_Something Finalization 0: 2 Stop Do_Something (2) Seems that compiler doing some shortcut with access to wrong I instance
From: stefan-lucks on 4 Apr 2008 13:51
> This looks like a pretty clear compiler bug, especially since by the > time Finalize is called by the outermost Do_Something, it's using, for > the value of I, the parameter from a Do_Something call that is no > longer active. It shouldn't be hard to modify this slightly, using > (say) a string or record as a parameter to Do_Something, to create a > test where utter garbage is displayed; then it would be clearer that > this is a compiler bug. Good idea! Yes, the following change makes the program output a bit of garbage, as you guessed: procedure Strong_Fin_Test_Case is type Fin is new Ada.Finalization.Limited_Controlled with null record; procedure Do_Something (I: Natural) is A: String(1 .. 5); -- this is new type My_Fin is new Fin with null record; overriding procedure Finalize(Self: in out My_Fin) is begin Ada.Text_IO.Put_Line(" Do_Something Finalization " & A); end Finalize; Singleton: My_Fin; begin -- Do_Something Ada.Text_IO.Put_Line(" I = " & Natural'Image(I)); if I>0 then Do_Something(I-1); Do_Something(I-1); end if; A(1 .. 5) := ("ABCDE"); -- always the same end Do_Something; begin Ada.Text_IO.Put_Line("Start Do_Something (2)"); Do_Something(2); Ada.Text_IO.Put_Line("Stop Do_Something (2)"); end Strong_Fin_Test_Case; The putput: Start Do_Something (2) I = 2 I = 1 I = 0 Do_Something Finalization ABCDE I = 0 Do_Something Finalization ABCDE Do_Something Finalization ABCDE I = 1 I = 0 Do_Something Finalization ABCDE I = 0 Do_Something Finalization ABCDE Do_Something Finalization ABCDE Do_Something Finalization �l Stop Do_Something (2) The last line before "Stop Do_Something (2)" contains some strange characters instead of the constant "ABCDE" it should output. Furthermore, this output is not always the same. So long Stefan -- ------ Stefan Lucks -- Bauhaus-University Weimar -- Germany ------ Stefan dot Lucks at uni minus weimar dot de ------ I love the taste of Cryptanalysis in the morning! ------ |