comp.lang.ada
 help / color / mirror / Atom feed
* Passing the same actual as both in and out formal parameters?
@ 2009-11-17  9:50 Ludovic Brenta
  2009-11-17 10:31 ` Jean-Pierre Rosen
                   ` (2 more replies)
  0 siblings, 3 replies; 12+ messages in thread
From: Ludovic Brenta @ 2009-11-17  9:50 UTC (permalink / raw)


Consider:

   type T is tagged private;
   procedure P (A : in T; B : out T) is separate;
   Object : T;
begin
   P (A => Object, B => Object);

This seems legal but I suspect the execution might lead to bugs if P
reads and writes components of A and B in arbitrary order, e.g.

type T is tagged record
   L, M : Integer;
end record;

procedure P (A : in T; B : out T) is
begin
   B.L := A.M; -- does this change A.L too?
   B.M := A.L; -- bug: A.L has been clobbered, now B.M = B.L?
end P;

My concern stems from the fact that T is tagged (I cannot change
that), so Object is passed by reference as both A and B.

Am I right to be concerned?

--
Ludovic Brenta.



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Passing the same actual as both in and out formal parameters?
  2009-11-17  9:50 Passing the same actual as both in and out formal parameters? Ludovic Brenta
@ 2009-11-17 10:31 ` Jean-Pierre Rosen
  2009-11-17 11:26   ` Ludovic Brenta
  2009-11-17 10:40 ` Niklas Holsti
  2009-11-17 16:26 ` Adam Beneschan
  2 siblings, 1 reply; 12+ messages in thread
From: Jean-Pierre Rosen @ 2009-11-17 10:31 UTC (permalink / raw)


Ludovic Brenta a �crit :

> procedure P (A : in T; B : out T) is
> begin
>    B.L := A.M; -- does this change A.L too?
Yes
>    B.M := A.L; -- bug: A.L has been clobbered, now B.M = B.L?
> end P;
> 
> My concern stems from the fact that T is tagged (I cannot change
> that), so Object is passed by reference as both A and B.
> 
> Am I right to be concerned?
> 
Depend on what your concern is ;-)
The semantic is well defined: tagged types are by-reference type. If you
want to swap two fields of different parameters of the same type, use a
local variable.

-- 
---------------------------------------------------------
           J-P. Rosen (rosen@adalog.fr)
Visit Adalog's web site at http://www.adalog.fr



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Passing the same actual as both in and out formal parameters?
  2009-11-17  9:50 Passing the same actual as both in and out formal parameters? Ludovic Brenta
  2009-11-17 10:31 ` Jean-Pierre Rosen
@ 2009-11-17 10:40 ` Niklas Holsti
  2009-11-17 16:26 ` Adam Beneschan
  2 siblings, 0 replies; 12+ messages in thread
From: Niklas Holsti @ 2009-11-17 10:40 UTC (permalink / raw)


Ludovic Brenta wrote:
> Consider:
> 
>    type T is tagged private;
>    procedure P (A : in T; B : out T) is separate;
>    Object : T;
> begin
>    P (A => Object, B => Object);
> 
> This seems legal but I suspect the execution might lead to bugs if P
> reads and writes components of A and B in arbitrary order, e.g.

I think this situation is defined in RM 6.2(12) where A and B are 
defined as "distinct access paths" to the same object. It is a bounded 
error if the parameter passing mechanism is not specified, but (by 
default) should work as expected when the parameters are passed by 
reference.

> type T is tagged record
>    L, M : Integer;
> end record;
> 
> procedure P (A : in T; B : out T) is
> begin
>    B.L := A.M; -- does this change A.L too?

Yes, as far as I understand RM 6.2(12).

>    B.M := A.L; -- bug: A.L has been clobbered, now B.M = B.L?

I believe so.

> end P;
> 
> My concern stems from the fact that T is tagged (I cannot change
> that), so Object is passed by reference as both A and B.
> 
> Am I right to be concerned?

Yes, if you expect A to be immutable during the execution of P.

There is a Note to RM 6.2(12), which is 6.2(13): "A formal parameter of 
mode in is a constant view (see 3.3); it cannot be updated within the 
subprogram body". But I think this means only that the "in" mode access 
path to this object cannot be used to update it. It does not mean that 
the value of the object cannot change at all, due to assignments from 
other access paths.

If P is mean to return B as A with L and M swapped, you should use an 
aggregate assignment, B := (L => A.M, M => A.L).

-- 
Niklas Holsti
Tidorum Ltd
niklas holsti tidorum fi
       .      @       .



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Passing the same actual as both in and out formal parameters?
  2009-11-17 10:31 ` Jean-Pierre Rosen
@ 2009-11-17 11:26   ` Ludovic Brenta
  2009-11-17 13:13     ` Jean-Pierre Rosen
  0 siblings, 1 reply; 12+ messages in thread
From: Ludovic Brenta @ 2009-11-17 11:26 UTC (permalink / raw)


Jean-Pierre Rosen wrote on comp.lang.ada:
> Ludovic Brenta a écrit :
>
>  procedure P (A : in T; B : out T) is
>> begin
>>    B.L := A.M; -- does this change A.L too?
> Yes
>>    B.M := A.L; -- bug: A.L has been clobbered, now B.M = B.L?
>> end P;
>
>> My concern stems from the fact that T is tagged (I cannot change
>> that), so Object is passed by reference as both A and B.
>
>> Am I right to be concerned?
>
> Depend on what your concern is ;-)
> The semantic is well defined: tagged types are by-reference type. If you
> want to swap two fields of different parameters of the same type, use a
> local variable.

My exampled was heavily simplified; the actual type has about a
hundred components and the procedure P is a little more complex than
swapping components :)

But thanks for the responses, Niklas and Jean-Pierre. They confirm my
suspicion.

--
Ludovic Brenta.



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Passing the same actual as both in and out formal parameters?
  2009-11-17 11:26   ` Ludovic Brenta
@ 2009-11-17 13:13     ` Jean-Pierre Rosen
  2009-11-17 16:07       ` Ludovic Brenta
  0 siblings, 1 reply; 12+ messages in thread
From: Jean-Pierre Rosen @ 2009-11-17 13:13 UTC (permalink / raw)


Ludovic Brenta a �crit :
> My exampled was heavily simplified; the actual type has about a
> hundred components and the procedure P is a little more complex than
> swapping components :)
> 
> But thanks for the responses, Niklas and Jean-Pierre. They confirm my
> suspicion.
> 
But the important thing is that there is no risk: behaviour is well
defined, and will not change with the next release of the compiler.

If it is not the behaviour you want, you can make a local copy (but you
know that).

-- 
---------------------------------------------------------
           J-P. Rosen (rosen@adalog.fr)
Visit Adalog's web site at http://www.adalog.fr



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Passing the same actual as both in and out formal parameters?
  2009-11-17 13:13     ` Jean-Pierre Rosen
@ 2009-11-17 16:07       ` Ludovic Brenta
  2009-11-18 10:00         ` Jean-Pierre Rosen
  0 siblings, 1 reply; 12+ messages in thread
From: Ludovic Brenta @ 2009-11-17 16:07 UTC (permalink / raw)


Jean-Pierre Rosen wrote:
> Ludovic Brenta a écrit :
>> My exampled was heavily simplified; the actual type has about a
>> hundred components and the procedure P is a little more complex than
>> swapping components :)
>
> > But thanks for the responses, Niklas and Jean-Pierre. They confirm my
> > suspicion.
>
> But the important thing is that there is no risk: behaviour is well
> defined, and will not change with the next release of the compiler.
>
> If it is not the behaviour you want, you can make a local copy (but you
> know that).

Indeed; I was careful not to use the phrases "bounded error" or
"erroneous execution", just "bug" :) The construct is well-defined but
error-prone and needs documentation in my sources, so I've added that.
Triggering the bug requires:

(1) pass-by-reference type (i.e. tagged, limited, etc.) or explicit
access type
(2) same object passed twice as both in and out parameters
(3) non-atomic reads and writes to the object inside the subprogram

When writing such a procedure, it is necessary to pay attention:
either prevent the bug by checking for condition (2) and raising an
exception if it is met; use only atomic operations so as to prevent
(3); or accept that the bug may happen and warn about it.

In my particular case, the operations are "atomic" in that the
procedure first reads the Object, then passes it as an "out" parameter
to another procedure, and never reads it again. However, this being
long-term-support software, one never knows that (3) can never happen
in some future revision.

--
Ludovic Brenta.



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Passing the same actual as both in and out formal parameters?
  2009-11-17  9:50 Passing the same actual as both in and out formal parameters? Ludovic Brenta
  2009-11-17 10:31 ` Jean-Pierre Rosen
  2009-11-17 10:40 ` Niklas Holsti
@ 2009-11-17 16:26 ` Adam Beneschan
  2009-11-17 21:25   ` Randy Brukardt
  2 siblings, 1 reply; 12+ messages in thread
From: Adam Beneschan @ 2009-11-17 16:26 UTC (permalink / raw)


On Nov 17, 1:50 am, Ludovic Brenta <ludo...@ludovic-brenta.org> wrote:
> Consider:
>
>    type T is tagged private;
>    procedure P (A : in T; B : out T) is separate;
>    Object : T;
> begin
>    P (A => Object, B => Object);
>
> This seems legal but I suspect the execution might lead to bugs if P
> reads and writes components of A and B in arbitrary order, e.g.
>
> type T is tagged record
>    L, M : Integer;
> end record;
>
> procedure P (A : in T; B : out T) is
> begin
>    B.L := A.M; -- does this change A.L too?
>    B.M := A.L; -- bug: A.L has been clobbered, now B.M = B.L?
> end P;
>
> My concern stems from the fact that T is tagged (I cannot change
> that), so Object is passed by reference as both A and B.
>
> Am I right to be concerned?

As the others have pointed out, the answers to your questions are
"yes", changing B.L does change A.L if the same object is passed as a
parameter to both A and B.  The semantics are well-defined.  My
concern would be whether optimization could change the order of the
operations inside P in a way that affects the results if A and B are
aliases for the same object; I don't know offhand whether this is
allowable for parameters of by-reference types.  I'd have to hunt
through the RM to figure this out, unless someone already knows the
answer.

Whether this (the simpler problem, without optimization) is a concern
or not depends on the situation.  I've written procedures that are
specifically designed to allow the same object to be passed as an IN
and an OUT parameter.  Of course, the body of the procedure has to be
written carefully to allow for this.  There's no way in Ada to enforce
any of this; right now it's just mentioned in the comments in the
package spec ("A and B may be the same object", or "A and B may not be
the same object"), and the caller is expected to obey this, and the
body is expected to perform correctly when they are the same object,
if they are indeed allowed to be the same.

I think AI05-191 is related to this.  Offhand, it appears that if this
AI is addressed, you could put an assertion somewhere (as a
precondition of P, if AI05-145 is addressed) to ensure that P is never
called with aliased (or overlapping) components, if that would be bad.

                                 -- Adam



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Passing the same actual as both in and out formal parameters?
  2009-11-17 16:26 ` Adam Beneschan
@ 2009-11-17 21:25   ` Randy Brukardt
  2009-11-18  0:11     ` Jeffrey R. Carter
  0 siblings, 1 reply; 12+ messages in thread
From: Randy Brukardt @ 2009-11-17 21:25 UTC (permalink / raw)


"Adam Beneschan" <adam@irvine.com> wrote in message 
news:7dde1f20-1b53-4ccf-8344-a60c9f500130@s21g2000prm.googlegroups.com...
...
> As the others have pointed out, the answers to your questions are
> "yes", changing B.L does change A.L if the same object is passed as a
> parameter to both A and B.  The semantics are well-defined.  My
> concern would be whether optimization could change the order of the
> operations inside P in a way that affects the results if A and B are
> aliases for the same object; I don't know offhand whether this is
> allowable for parameters of by-reference types.  I'd have to hunt
> through the RM to figure this out, unless someone already knows the
> answer.

I don't believe such an optimization would be legitimate, but given how hard 
it is to understand 11.6, I could be wrong. Most of the permissions to 
optimize are related to whether (and where) exceptions are raised, but there 
is no exception here. Similarly, there are a lot of things that are 
evaluated in an unspecified order (which could change because of 
optimization), but that also does not apply here.

> I think AI05-191 is related to this.  Offhand, it appears that if this
> AI is addressed, you could put an assertion somewhere (as a
> precondition of P, if AI05-145 is addressed) to ensure that P is never
> called with aliased (or overlapping) components, if that would be bad.

Right, that's my understanding of the point. The only problem is, there 
isn't any sane way to describe such an assertion.


                                Randy.

P.S. The checks proposed in AI05-0144-1 also are related to this situation, 
although they would not detect this particular case (as the semantics is 
well-defined, there is no non-portability here).





^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Passing the same actual as both in and out formal parameters?
  2009-11-17 21:25   ` Randy Brukardt
@ 2009-11-18  0:11     ` Jeffrey R. Carter
  2009-11-18  0:23       ` Adam Beneschan
  0 siblings, 1 reply; 12+ messages in thread
From: Jeffrey R. Carter @ 2009-11-18  0:11 UTC (permalink / raw)


Randy Brukardt wrote:
> 
> Right, that's my understanding of the point. The only problem is, there 
> isn't any sane way to describe such an assertion.

Given that the types are by-reference, would comparing 'access of the parameters 
  serve?

pragma Assert (A'access /= B'access);

-- 
Jeff Carter
"You cheesy lot of second-hand electric donkey-bottom biters."
Monty Python & the Holy Grail
14



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Passing the same actual as both in and out formal parameters?
  2009-11-18  0:11     ` Jeffrey R. Carter
@ 2009-11-18  0:23       ` Adam Beneschan
  2009-11-18  3:47         ` Jeffrey R. Carter
  0 siblings, 1 reply; 12+ messages in thread
From: Adam Beneschan @ 2009-11-18  0:23 UTC (permalink / raw)


On Nov 17, 4:11 pm, "Jeffrey R. Carter"
<spam.jrcarter....@spam.acm.org> wrote:
> Randy Brukardt wrote:
>
> > Right, that's my understanding of the point. The only problem is, there
> > isn't any sane way to describe such an assertion.
>
> Given that the types are by-reference, would comparing 'access of the parameters
>   serve?
>
> pragma Assert (A'access /= B'access);

First of all, for this to work in the general case, that would need a
major change in language semantics, since you need an access type in
order for 'Access to be allowed.  The only way this would be legal is
if there happened to be exactly one "=" operator directly visible with
operands of some named access-to-T type.  (Also, if "=" were
overridden with a user-defined operator that did something unexpected,
it would fail, but nobody would do that.)

Second, it only catches the case where the operands are of the same
type; it won't catch other overlaps such as

   P2 (A => Object, B => Object.Component);

                                     -- Adam




^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Passing the same actual as both in and out formal parameters?
  2009-11-18  0:23       ` Adam Beneschan
@ 2009-11-18  3:47         ` Jeffrey R. Carter
  0 siblings, 0 replies; 12+ messages in thread
From: Jeffrey R. Carter @ 2009-11-18  3:47 UTC (permalink / raw)


Adam Beneschan wrote:
> On Nov 17, 4:11 pm, "Jeffrey R. Carter"
> <spam.jrcarter....@spam.acm.org> wrote:
>>
>> pragma Assert (A'access /= B'access);
> 
> First of all, for this to work in the general case, that would need a
> major change in language semantics, since you need an access type in
> order for 'Access to be allowed.  The only way this would be legal is
> if there happened to be exactly one "=" operator directly visible with
> operands of some named access-to-T type.  (Also, if "=" were
> overridden with a user-defined operator that did something unexpected,
> it would fail, but nobody would do that.)

OK. Since this in the body of the operation, it seems doable:

procedure P (A : in T; B : out T) is
    type T_Ptr is access T;

    A_Ptr : constant T_Ptr := A'access;
    B_Ptr : constant T_Ptr := B'access;

    pragma Assert (A_Ptr /= B_Ptr);

So you're guaranteed that "=" for T_Ptr is used, and you know it hasn't been 
overridden.

What about 'Address?

> Second, it only catches the case where the operands are of the same
> type; it won't catch other overlaps such as
> 
>    P2 (A => Object, B => Object.Component);

Sure, it's not a general solution; I doubt if there could be one. But it does 
seem to serve for the OP's case.

-- 
Jeff Carter
"You cheesy lot of second-hand electric donkey-bottom biters."
Monty Python & the Holy Grail
14



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Passing the same actual as both in and out formal parameters?
  2009-11-17 16:07       ` Ludovic Brenta
@ 2009-11-18 10:00         ` Jean-Pierre Rosen
  0 siblings, 0 replies; 12+ messages in thread
From: Jean-Pierre Rosen @ 2009-11-18 10:00 UTC (permalink / raw)


Ludovic Brenta a �crit :
[...]
> Triggering the bug requires:
> 
> (1) pass-by-reference type (i.e. tagged, limited, etc.) or explicit
> access type
> (2) same object passed twice as both in and out parameters
> (3) non-atomic reads and writes to the object inside the subprogram
> 
> When writing such a procedure, it is necessary to pay attention:
> either prevent the bug by checking for condition (2) and raising an
> exception if it is met; use only atomic operations so as to prevent
> (3); or accept that the bug may happen and warn about it.
> 
<shameless_plug>
Or be automatically warned by AdaControl, see rule Parameter_Aliasing
</shameless_plug>

-- 
---------------------------------------------------------
           J-P. Rosen (rosen@adalog.fr)
Visit Adalog's web site at http://www.adalog.fr



^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2009-11-18 10:00 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-11-17  9:50 Passing the same actual as both in and out formal parameters? Ludovic Brenta
2009-11-17 10:31 ` Jean-Pierre Rosen
2009-11-17 11:26   ` Ludovic Brenta
2009-11-17 13:13     ` Jean-Pierre Rosen
2009-11-17 16:07       ` Ludovic Brenta
2009-11-18 10:00         ` Jean-Pierre Rosen
2009-11-17 10:40 ` Niklas Holsti
2009-11-17 16:26 ` Adam Beneschan
2009-11-17 21:25   ` Randy Brukardt
2009-11-18  0:11     ` Jeffrey R. Carter
2009-11-18  0:23       ` Adam Beneschan
2009-11-18  3:47         ` Jeffrey R. Carter

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