This is the mail archive of the gcc-bugs@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: neat bug in alias analysis


>>>>> "Mike" == Mike Stump <mrs@wrs.com> writes:

    Mike> You can bury your head, generate broken code, and one day
    Mike> someone will find the bug, explain it to you again, and you
    Mike> will then understand, or you can take the time now.  Your
    Mike> choice.

Please be polite, even if you happen to think I'm being dumb.  Just
disagree; please don't insult my industriousness, or the degree to
which I'm trying to the right thing.

I *am* taking the time, and I responded to your initial bug report
immediately; dropping other rather pressing issues to attend to my
responsibilities as the author of the buggy code.

As an aside, there are *way* too many insults on this list.  Everyone
is working hard, and everyone is doing their best.  The frequency with
which I see a message and think "wow, that wasn't nice" is just way
too high.  The reason is that we don't sufficiently much think of
ourselves as a common team.  Instead we tend to focus more on our own
projects, customers, needs, etc.  Were we all working in the same
building, playing volleyball at lunch-time, and so forth, we'd
probably be a lot more polite.  We should all get together and play
volleyball, but in the mean time we should try to pretend we already
did.  :-)

I know this message is long.  I'd appreciate it if you would read
through it carefully, and take the questions I raise in turn, so that
we can arrive at a well-reasoned conclusion, either agreeing, or at
least agreeing to disagree.

    Mike> Well, *p2 can change *p1:

    Mike> extern "C" int printf(const char *, ... );

    Mike> main() { int i = 1; int *ip = &i;

    Mike>   const int *const *p1; int **p2;

    Mike>   p1 = &ip; p2 = &ip;

    Mike>   *p2 = (int *)42; printf("%d\n", *p1); }

Thank you for the your example.  Now I understand what you are driving
at.

I do not believe that the standard supports your position, although I
can see why perhaps it ought to do so.

The reference in the the call to `printf' is through an lvalue of type
`const int *'.  (Top-level qualifiers don't matter.)  The dynamic type
of the object is `int *', since that is the declared type of `ip'.

Since we're now in C++-land, here's the relevant paragraph from the
C++ standard.  I've omitted lines that refer to signed and unsigned
variants, aggregates, and base-classes, since they don't apply here.

  If a program attempts to access the stored value of an object through
  an lvalue of other than one of the following  types  the  behavior  is
  undefined):

  --the dynamic type of the object,

Not this one.

  --a char or unsigned char type.

Not this one.

  --a cv-qualified version of the dynamic type of the object,

This is the only option.  So, the question boils down to:

  Is `const int *' a cv-qualified version of `int *'.

>From [basic.type.qualifier]:

  Each type which is a cv-unqualified complete or incomplete object
  type or is void (_basic.types_) has three corresponding cv-qualified
  versions of its type: a const-qualified version, a volatile-qualified
  version, and a const-volatile-qualified version.

And, the const-qualified version of `int *' is `int * const', not
`const int *'.

So, I conclude that the standard specifically gives undefined behavior
to your program.

Now, there remain two questions, which I think we should take
separately:

  o Do you agree with my analysis of the standard as it is written?
    In other words, have I misinterpreted language in the standard?

  o Does the standard make sense is this regard?

The first question is obviously not one that I can answer.  The
second, however, I'll sort-of answer.  In doing so, I'm assuming that
my reading of the standard is correct; obviously, if the standard does
not support my point of view, then its meaningless to even ask the
question.

In C, your program isn't legal.  You can assign an `int **' to an
`const int *const *' (without an explicit cast).  In C++, you can;
that's the qualification conversion in [conv.qual].  My guess is that
nobody on the committee noticed that this change should probably
result in a change in the undefined behavior rule quoted above.  In
fact, one might argue that the corresponding program, with the cast,
should have defined behavior in C.

It seems to make little sense to allow an implicit conversion between
pointers, and then not allow the resulting pointer to be dereferenced.
Normally, such "dicey" conversions require an explicit cast.  So I
think this to be a defect in the C++ standard.  I would like to know
if you concur.  Furthermore, I would appreciate it if you, or someone
else, would submit a defect report to the committee.  I do not
currently have the time, but I would be willing for someone to take my
words above, and package them appropriately, if that would be of help.

I agree with you, then, that the comment I inserted in your code
should be removed, and replaced instead with a brief summary of the
above discussion.  Do you concur?

--
Mark Mitchell                   mark@codesourcery.com
CodeSourcery, LLC               http://www.codesourcery.com


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]