From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00 autolearn=unavailable autolearn_force=no version=3.4.4 Path: eternal-september.org!reader01.eternal-september.org!reader02.eternal-september.org!news.eternal-september.org!mx02.eternal-september.org!.POSTED!not-for-mail From: "Alejandro R. Mosteo" Newsgroups: comp.lang.ada Subject: Finalization and class-wide views Date: Thu, 16 Jun 2016 01:50:04 +0200 Organization: A noiseless patient Spider Message-ID: Mime-Version: 1.0 Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 7bit Injection-Date: Wed, 15 Jun 2016 23:50:04 -0000 (UTC) Injection-Info: mx02.eternal-september.org; posting-host="6d84a6c85b8a1a019c7ed28ae8b7efda"; logging-data="26689"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX19csMxHg6mvzRhKIeDg7eXr" User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Thunderbird/38.8.0 X-Mozilla-News-Host: news://news.eternal-september.org:119 Cancel-Lock: sha1:1+x+UCxECNtDdqtr2LyjSmhF1hY= Xref: news.eternal-september.org comp.lang.ada:30753 Date: 2016-06-16T01:50:04+02:00 List-Id: Dear all, while pursuing a memory leak I've found a subtle difference in Controlled behavior in the latest Gnat GPL when using operators vs regular functions. Now, this could well be a misunderstanding on my part on how these things work, but the implications for a real program I'm working on are so that I can't really move forward without properly understanding it. I've tried the ARM but couldn't arrive at a firm conclusion. In my program, the outcome is that, for some class-wide types, finalization of its controlled members is delayed past their proper lifetime until program termination, generating a memory leak. I have attempted to reproduce it in a self-contained case, but the result is not identical. Here, it seems a finalization is missing altogether (I know by now you're skeptical of me ;-) See below for the output and explanation, if you prefer, before taking a look at the code (compiled with -Og): with Ada.Finalization; use Ada.Finalization; with Ada.Text_Io; use Ada.Text_Io; procedure Finalize_Leak is generic package P is type One is interface; type Managed is new Controlled with record X : Integer := 1; end record; overriding procedure Finalize (M : in out Managed); type Two is new One with record M : Managed; end record; end P; package body P is overriding procedure Finalize (M : in out Managed) is pragma Unreferenced (M); begin Put_Line ("finalize M"); M.X := 0; end Finalize; end P; package PP is new P; use PP; function Pass (X : Two'Class) return One'Class is (X); function "not" (X : Two'Class) return One'Class is (X); A : Two; begin declare B : constant One'Class := A; begin Put_Line ("---8<---"); Put_Line (Two'Class (B).M.X'Img); end; Put_Line ("--->8---"); New_Line; declare B : constant One'Class := Pass (A); begin Put_Line ("---8<---"); Put_Line (Two'Class (B).M.X'Img); end; Put_Line ("--->8---"); New_Line; A.M.X := 2; declare B : One'Class := not A; begin Put_Line ("---8<---"); Put_Line (Two'Class (B).M.X'Img); end; Put_Line ("--->8---"); New_Line; Put_Line ("Now A is going to finalize"); end Finalize_Leak; *So.* I would expect the three declare blocks to produce more or less (besides temporaries) the same output: One "finalize" printed between each matching scissor pair, corresponding to B going out of scope. In other words, the conversion to an ancestor does not cause the finalization of the full view type (this was my belief until now, otherwise how could containers of classwide types work?). Instead, the output I get is: ---8<--- 1 finalize M --->8--- finalize M ---8<--- 1 finalize M --->8--- finalize M ---8<--- 2 --->8--- Now A is going to finalize finalize M So the first declare is straightforward, the second one seems to involve a temporary somewhere, and (here is my hope that this is not normal) the last one, where seemingly B.M finalization seems missing. The integer tells me that the previous finalization is of a temporary. I hope some of you experts can shed some light. To summarize: do class-wide conversions affect finalization? Do you smell something fishy in this case? Thanks in advance, Alex.