Re: large files: when ubiquitous?

From: Kasper Dupont (kasperd_at_daimi.au.dk)
Date: 05/08/04


Date: Sat, 08 May 2004 18:23:18 +0200


"P.T. Breuer" wrote:
>
> The compiler can safely make no optimization assumptions at all on an
> indirection in C. Just to be silly, the pointer might be into shared
> memory - you're not then even the only thread with access.

In which case you must use either memory barriers
and/or volatile variables. If you don't do so, the
compiler will make optimizations giving unexpected
behaviour. That have been seen so often.

>
> It's only safe when you can prove that no other functional unit has
> write access there, which is nearly freaking impossible in C.

If you required the program to behave exactly the
same with and without optimization, you wouldn't be
able to do any optimization at all. That is part of
the reason why there are so many cases of undefined
behaviour, the optimizer can make a lot of changes
that cause broken program to behave differently.

>
> > Eg. this program print 1078523331 when compiled without
> > optimization, and print 42 when compiled with -O3
> >
> > #include <stdio.h>
> > #include <stdlib.h>
> > long f(long *a, float *b)
> > {
> > *a=42;
> > *b=3.14;
> > return *a;
> > }
>
> Oh great. When both addresses are the same one or the other write wins.

Yes. And the assignments will probably be done in
the order they appear in the code. Which means the
contents of the memory as the function returns
will be as expected.

>
> Well, as you can see, it's not safe to elide the *b = 3.14 here.

The compiler doesn't elide it.

> Compiler mistake if it does.

It doesn't.

> Send in bug report.

It is not a compiler bug. There is a bug in the
program I wrote, which I deliberately put there to
demonstrate my point.

If you think it is a bug *you* report it here:
http://gcc.gnu.org/bugzilla/
And watch it getting closed as notabug as soon as
the bug report have been read. Feel free to use my
example program if you like.

> Rewrite code for f as
> inline local function using parents variables, or macro.

Why should I?

>
> > int main()
> > {
> > void *p=malloc(42);
> > printf("%ld\n",f(p,p));
>
> Hmm. You don't seem to object to void* there!

I never objected to void*. I just said you couldn't
dereference a void. And dereferencing is all what is
relevant to this optimization.

> As I said below, at least
> void* is a contractural promise that it's 4-aligned.

No.

malloc guarantee the returned memory will satisfy
the alignment requirement of any type.

> Making promises is
> a good thing, in general, imo.
>
> If we pass char* instead to f,

What exactly did you have in mind? Casting the pointer
to a char pointer type or changing p to be a char
pointer would result in a warning about incompatible
pointer types. That is completely unrelated to
alignment, and would happen even if both types had
the same size and the same alignment requirement. And
the code would behave exactly the same.

> then we would be implictly saying that we
> don't guarantee to f that its parameters in this instance are even
> aligned the way f's prototype says they should be, which in my opinion
> ought to generate a compiler warning.
>
> Yet the info page seems to say that passing char* turns off "type
> punning" checks.

It doesn't say anything about passing pointers, that
is not where the optimization happens. Passing a char
pointer doesn't change anything. You could have tried
changing the void *p to char *p and tried running the
program with and without optimization.

>
> The practice of reading from a different union member than the one
> most recently written to (called "type-punning") is common. Even
> with `-fstrict-aliasing', type-punning is allowed, provided the
> memory is accessed through the union type.
>
> ...
>
> For example, an `unsigned int' can alias an `int', but not a `void*'
> or a `double'. A character type may alias any other type.
>
> (I'm not absolutely sure what they meant in the last, but I think they
> mean to refer to char*, where "character type" refers to the content of
> the indirection).

It means that if I change one of the types to char*
the compiler will no more assume they couldn't point
to the same address. If for example long *a was
changed to char *a, the program would print -61 both
with and without optimization.

>
> So do you think the compiler will warn you about type punning in your
> example?

The compiler doesn't warn about anything in my example.

>
> > return 0;
> > }
> >
> > > Wouldn't reading "anything" from a void* be safer?
> >
> > Dereferencing a void shouldn't be allowed at all.
>
> Nobody does - they cast the address to (other*) first. I meant
>
> int *x = (void*)silly_address;
>
> There is no read of a void.

But then the discussion of type punning wouldn't apply.
Or more precisely, if you derefernce x anywhere, it will
be of type int, and will be assumed not to be at the
same address as any variable of a significant different
type (except from char). Replacing char with void in the
description would make no sense at all, because you cannot
use expressions of type void for anything.

>
> Then what ARE we talking about? I'll try and look up some debian type
> punning warning reports of mine ..
>
> In function `masterpropagate':
> 2732: warning: dereferencing type-punned pointer will break strict-aliasing rules
> 2734: warning: dereferencing type-punned pointer will break strict-aliasing rules
>
> int i;
> int pid;
> struct d_db * spids_db = &self->spids;
>
> for (
> ***** i = spids_db->first(spids_db, (void**)&pid,NULL);
> i >= 0;
> ***** i = spids_db->next (spids_db,i,(void**)&pid,NULL)
> ) {
>
> and the methods are of type
>
> int (*first)(struct d_db * self, void **nam, void **val);
> int (*next) (struct d_db * self, int i, void **nam, void **val);
>
> The calls match the prototypes. What is it complaining about?

I don't know this particular piece of code, and without
the context, I really don't know what it is all about.

-- 
Kasper Dupont -- der bruger for meget tid paa usenet.
For sending spam use abuse@mk.lir.dk and kasperd@mk.lir.dk
I'd rather be a hammer than a nail.


Relevant Pages

  • Re: TEA Implementation
    ... The second argument should be a pointer to pointer to ... It should be the address of a pointer to char. ... compiler won't even accept it at all. ... Seems like a rather confusing way of writing ...
    (comp.lang.c)
  • Re: large files: when ubiquitous?
    ... the pointer might be into shared ... I was merely pointing out that the compiler cannot ... > same with and without optimization, ... align), but instead you mean int, long, void * and so on ... ...
    (comp.os.linux.development.system)
  • Re: i386 nmi_watchdog: Merge check_nmi_watchdog fixes from x86_64
    ... > after the store without volatile it seems a reasonable ... > as we have taken the address earlier so at some point the compiler ... pointer away and will be referring to it later. ... or if the compiler does whole-program optimization and can see ...
    (Linux-Kernel)
  • Re: lvalue assignment error
    ... > char *sstrdup ... convert the char pointer to a void pointer automatically, no cast ... compiler is forced to assume that it returns an int. ...
    (comp.lang.c.moderated)
  • Re: Keil c51 interprets &Array as Array. Is that normal?
    ... Yes it is a pointer to an array of 10 chars. ... but the compiler is well aware of it ... char a; ... Need to learn how to apply control theory in your embedded system? ...
    (comp.arch.embedded)