On Wednesday 07 November 2007, Julian Seward wrote:

> > a real workaround would be to copy the content into a new location (e.g.
> > a local variable) and access that one via its type.
> I'd like to fix it properly, but there's lots of code like this:
>
>    while (TC_(nextIterFM)( map_locks, (Word*)(void*)&gla,
>                                       (Word*)(void*)&lk )) {
>       ...
>    }

Ok, I`ve had a short look at the code and it seems that this is because of a 
generic AVL tree implementation based on "Lock" and a few other struct`s. Of 
course any casting you do here might silence the warning, but it does not fix 
the issue. 

The static type of the memory you allocated is "Lock". if you access it 
via "Word" (as the AVL implementation does), then you`re violating strict 
aliasing. For now this seems to work because the AVL implementation is not 
inline, so the compiler doesn`t have much chance at optimi^h^h^h^hscrewing it 
up. 

A proper solution would be something like

typdef union {
  Word* asPtr;
  Word asWord;
} AVLBase;

and changing struct Lock into

struct _Lock {
  AVLBase admin;
  ...

Then the nextIterFM calls would look like:

  &TC_(nextIterFM)(map_locks, &gla.admin, &lk.admin)

one could hide the ugly detail behind a #define, and it would suddenly look 
rather nice. Its a pity that type inheritance is not implemented in C ;)

> > piece of memory via pointers that have a different type (except for the
> > non-symmetrical char* exception). in this case I guess it is because
> > Word*
> char* exception?  Does the standard say a char* can point at anything?

not exactly. it is not about pointers, but about the actual access (load or 
store). The standard says that as an exception, you can read or modify any 
memory via "char" accesses (note, not unsigned/signed char! though that 
happens to work as well on almost any platform). The sole motivation behind 
that is that memcpy() has to work (which does not know type and is supposed 
to copy by char). so something like:

  int i = 0;
  char* p = (char*)&i;
  p[0] = 1;
  if (!i) abort();

is going to work. However, 

  int i = 0;
  short* s = (short*)(void*)(char*)&i;
  s[0] = 1;
  if (!i) abort();
  
will not. 

So, by casting to "char*" inbetween, you`re silencing the warning (because 
that is implemented somewhere else in the compiler) but you`re not fixing the 
actual aliasing information (which is generated later). In this care, you`re 
still accessing memory that has the static aliasing information "struct 
_Lock" via "int". those two types may not alias. Even if you casted the 
pointer a hundred times inbetween to all kinds of different types, it does 
not matter: the actual access matters. In practice, it is possible that you 
confuse the compiler good enough so that it will stop "miscompiling" the code 
by no longer knowing that it doesn`t have to re-load a value that was already 
cached in a register, but any future version of the compiler might become 
better at interpreting your cast-chain. 

> If yes, can I use the same hack as I just committed, but with char* as
> the intermediate type instead of void* ?

No. Sorry for not following up earlier, I only got reminded of this email 
after I read the commit log. 

Greetings,
Dirk

-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >> http://get.splunk.com/
_______________________________________________
Valgrind-developers mailing list
Valgrind-developers@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/valgrind-developers

Reply via email to