A Quick Question Regarding Parameters

I could swear if I have a procedure with an out parameter, of a by-copy or by-reference type, that assignments to that parameter will take effect even if the procedure raises an exception immediately thereafter. However, I scanned through the ARM and was unable to find the section guaranteeing me this. I was recently reviewing controlled types again, and relearned that Finalize is called even when Initialize raises an exception. A library that I’ve written has a subtle flaw unless this out parameter assignment quality holds. Any guidance on the relevant part of the ARM would be appreciated.

The copy back of an [in] out mode parameter of a by-copy type only occurs on normal return from the subprogram [ARM 6.4.1(17)]. If the subprogram propagates an exception, the copy back does not occur, and the variable retains its original value. Both GNAT 12.3.0 and ObjectAda 10.5U5 behave this way.

1 Like

Darn. I guess I’ll give the one component the controlled type has a default value, which should fix the problem, if I’m reading the ARM correctly. I very much appreciate the help.

I’m getting some odd results. The code in question can be found here:
http://verisimilitudes.net/2022-08-22

The Initialize procedure calls socket and bind, raising an exception if either fails; the Finalize procedure simply calls close. However, I decided to use strace to see what happens when this fails; since I didn’t originally give a default value to the Socket_Nonsense component of the controlled type, I thought close would be called on a random file descriptor, and wanted to doublecheck this, but I’m not seeing close called at all.

Have I misunderstood something regarding controlled types? I’m a little confused right now.

I suppose I misread 7.6.1 14.a of the ARM:

Ramification: It is not a bounded error for Initialize to propagate an exception. If Initialize propagates an exception, then no further calls on Initialize are performed, and those components that have already been initialized (either explicitly or by default) are finalized in the usual way.

So, here I was thinking that I had a subtle and very rare uninitialized variable use, because it’s possible for Initialize to leave the file descriptor untouched, and I thought that Finalize would still be called, but this is wrong. Instead, Finalize will only be called for recursive such initialized components. So, I didn’t write an uninitialized variable use flaw, but the Initialize procedure I wrote does need to clean up after itself. I accidentally wrote a little resource leak.

Well, don’t I feel silly. Once again, I appreciate the help.