Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

strange cursor in nested containers

147 views
Skip to first unread message

Mario Blunk

unread,
Apr 19, 2023, 3:09:48 AM4/19/23
to
Hello out there,
I've put together a demo to reproduce a strange behavior of a cursor.

https://github.com/Blunk-electronic/ada_training/blob/master/src/containers/demo/nested/nest_1.adb

Description:
Inside the procedure "get_line" the cursor "result" is assigned only once (on match). Since there is no further match, in the course of the procedure, I assume that "result" is never changed. So the expected output should be:

net: A
L1 S: 2.00000E+00 E: 3.00000E+00
L2 S: 2.00000E+00 E: 3.00000E+00
net: B
L2 S: 2.00000E+00 E: 3.00000E+00
L3 S: 2.00000E+00 E: 3.00000E+00

but the actual output is:

net: A
L1 S: 2.00000E+00 E: 3.00000E+00
L2 S: 2.00000E+00 E: 3.00000E+00
net: B
L2 S: 1.20000E+01 E: 1.30000E+01
L3 S: 7.47956E-39 E: 0.00000E+00 -- changes randomly

Thanks for your help.


Simon Wright

unread,
Apr 19, 2023, 11:07:04 AM4/19/23
to
This is a puzzler.

To simplify matters (for me, anyway) I changed your doubly linked list
to a vector. Now, instead of junk, I get an access violation.

'result' isn't changed, but a Cursor contains a pointer to the container
and an index; using gdb to look at the container via the unchanged
pointer, it's been overwritten with garbage. However, looping with this
(after the Nets.Iterate call, i.e. after Result has been damaged)

for N of Nets loop
for TL of N.Lines loop
Put_Line (To_String (TL));
end loop;
end loop;

works just fine.

My head hurts.

Egil H H

unread,
Apr 20, 2023, 1:15:36 AM4/20/23
to
On Wednesday, April 19, 2023 at 9:09:48 AM UTC+2, Mario Blunk wrote:
> Hello out there,
> I've put together a demo to reproduce a strange behavior of a cursor.
>
> https://github.com/Blunk-electronic/ada_training/blob/master/src/containers/demo/nested/nest_1.adb
>

Each call to `element(n)` returns a _copy_ of the element, which in this case includes the enitre doubly linked list
(and since `net` is a renames of `element(n), you would have gotten multiple copies if you had called `net` multiple times inside query net)

Using a reference instead should fix this problem:
net : type_net renames nets.reference (key(n));

or (Ada 2012):
net : type_net renames nets(n);

--
~egilhh

Egil H H

unread,
Apr 20, 2023, 1:33:46 AM4/20/23
to
oops, both my solutions are Ada 2012 :)

If Ada 2005 is a requirement (based on your explicit usage of `iterate`), I guess you would need an extra set of callbacks and call `update_element` in order to get a reference to the element containing the correct instance of the doubly linked list

--
~egilhh

Simon Wright

unread,
Apr 20, 2023, 10:59:39 AM4/20/23
to
Egil H H <ehh.p...@gmail.com> writes:

> Each call to `element(n)` returns a _copy_ of the element, which in
> this case includes the enitre doubly linked list

This is indeed the problem, thanks!

I hadn't considered the effect of renaming a function call; the cursor
constructed inside query_net refers to the locally renamed copy of
type_net, which will be destroyed on exit from query_net.

> (and since `net` is a
> renames of `element(n), you would have gotten multiple copies if you
> had called `net` multiple times inside query net)

This appears to say that this renaming of a function call results in
something like a macro, but I think that

R : T renames Func;

is more like

R : constant T := Func;

ARM 8.5(3) says

"The elaboration of a renaming_declaration evaluates the name that
follows the reserved word renames and thereby determines the view and
entity denoted by this name (the renamed view and renamed entity). A
name that denotes the renaming_declaration denotes (a new view of)
the renamed entity."

Mario Blunk

unread,
Apr 20, 2023, 11:28:10 AM4/20/23
to
Thanks for your replies. Now it is becoming clear to me:

1. The statement net : type_net renames element (n) gives a copy of element (n).
2. After the assignment to "result" (line 55), "result" points to an element inside the local copy "net".
3. Once "net" is overwritten in the next call of query_net, "result" still refers to a "net" that does not exist anymore. Likewise, once procedure query_net is left, "result" still points to a list that does not exist anymore. Thatswhy I get garbage in line 68 and 77.
Correct ?



Randy Brukardt

unread,
Apr 22, 2023, 5:33:44 AM4/22/23
to
I agree. If you used a debugging container that checked for dangling
cursors, you probably would have gotten an exception from any use of the
cursor to the dead copy. Not sure that would have been any clearer as to the
cause, but it would be a suggestion. (Not sure if GNAT still has debugging
containers, they did at one point, but a lot of work has been done on them
since.)

Randy.

"Mario Blunk" <mario.bl...@gmail.com> wrote in message
news:ed311a62-41ba-493e...@googlegroups.com...

Mario Blunk

unread,
Apr 22, 2023, 1:04:08 PM4/22/23
to
I wonder why at runtime no exception is raised.
How could I solve the problem ? Not using "rename" ? Using an aliased access type as John Barnes suggests in Ada2005 on page 275 ?

Jeffrey R.Carter

unread,
Apr 22, 2023, 2:33:17 PM4/22/23
to
On 2023-04-22 19:04, Mario Blunk wrote:
> I wonder why at runtime no exception is raised.
> How could I solve the problem ? Not using "rename" ? Using an aliased access type as John Barnes suggests in Ada2005 on page 275 ?

You have to avoid calling Element. Since you have a cursor, you can call
Query_Element, which should pass the actual element to the procedure you supply.

--
Jeff Carter
"He didn't get that nose from playing ping-pong."
Never Give a Sucker an Even Break
110

Mario Blunk

unread,
Apr 25, 2023, 3:30:39 AM4/25/23
to
> > How could I solve the problem ? Not using "rename" ? Using an aliased access type as John Barnes suggests in Ada2005 on page 275 ?
> You have to avoid calling Element. Since you have a cursor, you can call
> Query_Element, which should pass the actual element to the procedure you supply.

Right, that solves the problem. For those interested please find a comparison here:

1. The demo with a dangling (dangerous) cursor:
https://github.com/Blunk-electronic/ada_training/blob/master/src/containers/demo/nested/nest_1.adb

And the demo with the issue solved properly:
https://github.com/Blunk-electronic/ada_training/blob/master/src/containers/demo/nested/nest_2.adb

Still the question remains, why such a dangling cursor is not detected at runtime.

Randy Brukardt

unread,
May 8, 2023, 11:56:32 PM5/8/23
to
It's not required to detect such cursors because it is expensive to do so
perfectly (essentially, each cursor has to be controlled and one has to keep
a list of them associated with the container). There are imperfect solutions
which are likely to be "good enough" in practice, but they still have a
(small) cost which may be an issue for some uses. Thus, most implementers
don't use them. I know the original GNAT containers had a debugging version
that included such checks, but I don't know if they still exist or how one
would enable them if they do.

Randy.

"Mario Blunk" <mario.bl...@gmail.com> wrote in message
news:9a1c3ba5-d5ae-41d3...@googlegroups.com...

Jeffrey R.Carter

unread,
May 9, 2023, 4:36:36 AM5/9/23
to
On 2023-05-09 05:56, Randy Brukardt wrote:
> It's not required to detect such cursors because it is expensive to do so
> perfectly (essentially, each cursor has to be controlled and one has to keep
> a list of them associated with the container). There are imperfect solutions
> which are likely to be "good enough" in practice, but they still have a
> (small) cost which may be an issue for some uses. Thus, most implementers
> don't use them. I know the original GNAT containers had a debugging version
> that included such checks, but I don't know if they still exist or how one
> would enable them if they do.

This cost is due to the decision to allow access to elements using only a
cursor. If both the container and the cursor are needed, then the cost is
significantly reduced. This is the approach that was used in the Ada-95 version
of the PragmAda Reusable Components.

--
Jeff Carter
“Bug rates in C++ are running higher even than C ...”
Stephen F. Zeigler
216

Dmitry A. Kazakov

unread,
May 9, 2023, 4:51:05 AM5/9/23
to
On 2023-05-09 10:36, Jeffrey R.Carter wrote:

> This cost is due to the decision to allow access to elements using only
> a cursor. If both the container and the cursor are needed, then the cost
> is significantly reduced.

That would be in the index/position team rather than in the
cursor/pointer/address one.

--
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de

0 new messages