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

Strange behaviour

28 views
Skip to first unread message

card

unread,
Jan 4, 2010, 9:44:59 PM1/4/10
to
Hi All,

Here is a strange behaviour I can't figure out. Here is the code:

module bug
implicit none

type buggy
type (buggy), pointer :: left => null()
type (buggy), pointer :: right => null()
type (buggy), pointer :: parent => null()
integer :: num = 0
end type buggy

type (buggy), target, save :: nil = buggy(null(), null(), null(), 0)

private :: nil

contains

subroutine showBug()
type (buggy), pointer :: x, y, z
type (buggy), pointer :: p

allocate(x,y,z)

x%parent => nil
x%num = 1
x%left => y

y%parent => x
y%num = 1
y%left => z

z%parent => y
z%num = 3

p => z%parent%parent

! This does not work
call rearrange(z%parent%parent)

! This works
! call rearrange(p)

end subroutine showBug

subroutine rearrange(x)
type (buggy), pointer :: x
type (buggy), pointer :: y

y => x%left
y%parent => x%parent

print *, x%parent%num

end subroutine rearrange
end module bug


program main
use bug
call showBug()
end program main

Compile as is and you should get a seg fault. Then compile it with
the line under "! This works" uncommented and the line under "! This
doesn't work" commented out. That version works, but I don't
understand why the first didn't since the second version is
effectively the same thing. Many thanks to anyone who can explain
this to me.

-David

Richard Maine

unread,
Jan 5, 2010, 12:02:10 AM1/5/10
to
card <david...@gmail.com> wrote:

You have a tricky issue with "aliasing" of a dummy argument. Aliasing
arises when you access the same variable by two different "paths".
Fortran has restrictions on some kinds of aliasing. But pointer dummy
arguments are different. Aliasing with pointers is a "normal" thing, so
it is allowed. That doesn't mean it is always easy to see what is going
on.

You have added an extra level of confusion by using the names x and y in
both the subroutine and ths host. Anyway, it managed to confuse me for a
while (which admitedly might not take much at times :-)). Also, let us
all remember that your "nil" is a perfectly valid variable, not to be
confused with null; in particular, nil%num is a valid component, while
trying to take a component of a null pointer is an error.

No, z%parent%parent and p are not the same thing. Yes, the difference
matters. Both are pointers that point to the same thing, but that
doesn't mean that they are the same thing themselves. This is just like
the fact that you can have two variables with the same value, but that
doesn't make the two variables the same thing.

In particular, z%parent%parent is the parent component of y. It happens
to point to x, but that's beside the point. What it *IS* (rather than
what it points to) is the parent component of y. This is important. On
the other hand, p is a separate pointer in its own right.

Now analyze the two cases. This gets confusing if we don't carefully
distinguish between the pointers and the targets. The allocate statement
alocates 3 targets. They don't have names known to Fortran, but let's
call them tx, ty, and tz for expository purposes. After the allocate
statement, x points to tx, y points to ty, and z points to tz. Yes,
that's what an allocate for a pointer does. It allocates a target and
then makes the pointer point to that target, but you need to remember
that the target and the pointer are different things.

Tracing things through, we can see that p ends up being a pointer to tx.

First consider passing p as the actual argument.

y => x%left

sets the subroutine's y to point to the same thing as x%left points to
(where x is the dummy x). The dummy x is argument associated with p (for
most practical purposes, we can just say that it is the same thing as
p). P (and thus the dummy x) points to tx. The left component of tx is a
pointer to ty. So the subroutine's y is set to be a pointer to ty.

Then

y%parent => x%parent

makes ty%parent point to the same thing as dummy x (aka p) %parent,
which is nil.

In the print statement, the dummy x (aka p) is still a pointer to tx,
the parent component of tx is still a pointer to nil, so the num
component of nil gets printed. All is valid (if confusing.)

Now consider passing z%parent%parent as the actual argument. z%parent is
a pointer to ty, so this passes the parent component of ty as the actual
argument. It is *VERY* important to understand that this actually is the
parent component of ty. It isn't just some other random pointer that
happens to point to the same thing.

Now the y=>x%left bit goes just as in the other case. The subroutine's y
is set to be a pointer to ty.

And likewise, y%parent=>x%parent still makes ty%parent point to nil.

But remember that ty%parent is the actual argument. You do recall that I
said it was important to understand that, I hope. Well, you just changed
what ty%parent points to. It used to point to tx, but it now points to
nil. That means that the dummy x also just became a pointer to nil. This
is the kind of confusing thing that aliasing can do. It looks like you
are just changing y%parent, but because y%parent is aliased to the dummy
argument x, this also has the effect of changing the dummy argument. As
mentioned above, for non-pointer dummy arguments, this kind of thing is
disallowed (though compilers don't necessarily catch it). But for
pointers, well, pointers are made to alias (in fact, I've occasionally
suggested that "alias" might have been a more accurate term for Fortran
pointers). If one deals with pointers, one is presumed to be able to
keep the resulting confusion straight. (This presumption, is, of course,
often wrong.)

Anyway, since x now points to nil, x%parent is a null pointer, and
trying to print x%parent%num results in dereferencing a null pointer,
which probably gives you a segfault (and in any case is illegal).

It is possible that I got confused in some of the above stuff. I sure
got it wrong the first time I tried partly because I failed to notice
the two different y pointers. I redid it and it seems better this time,
but it is easy to get this stuff wrong, and i might still have screwed
something up. But I think the critical points of note will stand in any
case.

Those critical points are:

1. Just because two pointers point to the same thing, that doesn't mean
that the pointers are the same thing. In your case, p and
z%parent%parent both point to the same thing, but they are two different
pointers. If it helps, note that they are physically two different
memory locations.

2. Aliasing. I can't summarize this one easily. Just watch out for it.
It can be confusing. With non-pointers, the confusing cases are all
illegal. With pointers, well, they are just confusing. Things change
behind your back. In particular, the aliasing here made the dummy
argument x change when that wasn't obvious. When you passed p as the
actual argument, there was no aliasing.

--
Richard Maine | Good judgment comes from experience;
email: last name at domain . net | experience comes from bad judgment.
domain: summertriangle | -- Mark Twain

card

unread,
Jan 5, 2010, 12:19:29 AM1/5/10
to
On Jan 5, 12:02 am, nos...@see.signature (Richard Maine) wrote:

Thanks Richard. That was an wonderful step-by-step explanation. I
had stepped through it with gdb and discovered exactly what you were
saying, but I couldn't put my finger on it as to why the dummy pointer
argument x was changing during the association of y%parent => x
%parent. Makes complete sense and so obvious now. Thanks for making
that so clear.

-David

0 new messages