• strange cursor in nested containers

    From Mario Blunk@21:1/5 to All on Wed Apr 19 00:09:46 2023
    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Simon Wright@21:1/5 to Mario Blunk on Wed Apr 19 16:07:00 2023
    Mario Blunk <mario.blunk.gplus@gmail.com> writes:

    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

    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Egil H H@21:1/5 to Egil H H on Wed Apr 19 22:33:44 2023
    On Thursday, April 20, 2023 at 7:15:36 AM UTC+2, Egil H H wrote:
    On Wednesday, April 19, 2023 at 9:09:48 AM UTC+2, Mario Blunk wrote:

    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);


    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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Egil H H@21:1/5 to Mario Blunk on Wed Apr 19 22:15:34 2023
    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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Simon Wright@21:1/5 to Egil H H on Thu Apr 20 15:59:35 2023
    Egil H H <ehh.public@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."

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Mario Blunk@21:1/5 to All on Thu Apr 20 08:28:08 2023
    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 ?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Randy Brukardt@21:1/5 to All on Sat Apr 22 04:33:37 2023
    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.blunk.gplus@gmail.com> wrote in message news:ed311a62-41ba-493e-a4cc-481402a1cc6bn@googlegroups.com...
    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 ?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Mario Blunk@21:1/5 to All on Sat Apr 22 10:04:06 2023
    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 ?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Jeffrey R.Carter@21:1/5 to Mario Blunk on Sat Apr 22 20:33:14 2023
    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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Mario Blunk@21:1/5 to All on Tue Apr 25 00:30:37 2023
    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)