ARM/Linux: Is this a cross-compiler bug? $B!J(Bmemcpy doesn't work as expected)

Breakage of existing code is common.

There was quite some discussion about the fact that a new version of GCC optimized checks away that depended on unspecified behaviour of integer overflows.

That was around april. The CERT advice is still there but has been revised multiple times (easy to find). The fun thing was that GCC got blamed for beeing an unsecure compiler while tons of other compilers applied the same optimization as well.

If you want a fun read/flamewar google for "Cert GCC". You'll find lots of discussion if this was a bug in the "optimized away"-code or a bug in the GCC-optimizer. Even the C-experts weren't sure who to blame for a day or two..

Reply to
Nils
Loading thread data ...

What's redundant about it?

The rule is different than C, but it isn't complicated. The semicolon is used to separate two consecutive statements.

In fact, the rule in C is actually more complicated, even though most of us are probably so accustomed to it that we don't normally think it in detail.

And that's different from C in what way?

Eric

Reply to
Eric Smith

another (that one would be to easy). Instead

No, his example uses the built-in memcpy, and he says that it goes away when he uses his own memcpy.

memcpy is rewritten to use char* instead of

There is nothing special about uint8_t, it's just a typedef in .

I don't believe it is an aliasing issue. I can't reproduce it with the EABI GCC4.2, so it's more likely a bug in memcpy or an alignment issue (older non-EABI versions used some weird structure alignment rules, making Bar a 4-byte structure...).

Wilco

Reply to
Wilco Dijkstra

True..

Now a look at the assembly output of his test-case would be interesting ...

Nils

Reply to
Nils

I would call adding optimizations that break perfectly valid code horrible and dangerous...

There is little value in catching overflows (apart from blowing up expensive rockets in spectacular ways) while the complexity and cost of implementing asynchronous exceptions is enormous.

Bitfields are easier to use than complex bit manipulation code, so they are useful. If I use your argument then why do we have if statements and loops as you can achieve the same with goto?

No non-trivial piece of code meets all requirements of the standard. Have you ever used lint or compiled some application with the strict conformance checking option? You will be surprised. Even if it does compile, it will still contain implementation defined behaviour which makes it theorhetically unportable. In practise most non-conforming code is portable, so there is no advantage at all in being conformant.

Wilco

Reply to
Wilco Dijkstra

A well defined syntax would allow either. Or make the whole problem go away by not requiring separators/terminators - in almost all cases they are redundant. Parsing is a well understood problem.

I think he's just confirming that other languages have similar undefined and/or implementation defined issues as C has. Ie. so called safe languages are not actually much more portable or safer than C, even if they appear to be. Java is not immune to it either (the correctness of some programs depends on when exactly garbage collection occurs).

Wilco

Reply to
Wilco Dijkstra

That was my point. GCC does have a lot of advanced high-level optimizations (including ones that unnecessarily break code), but it's very bad at doing target aware optimizations.

That's partly due the less professional compilers using LR parser generators rather than handcrafting a recursive descent parser, and partly due to it being a lot of work. It's funny how easy it is to crash the frontend of any compiler just by giving it random input.

Wilco

Reply to
Wilco Dijkstra

You're right, but being *that* conservative would mean you couldn't do any optimization! Volatile is one of those things which most people understand intuitively and which is implemented almost identically in all compilers (despite being almost completely unspecified in C). So it's perfectly reasonable to expect programmers to use it properly.

So with being conservative I mean optimizing as much as possible without breaking existing software. Even if the language standard allows us to break most software, it's commercial suicide. Basically you weigh the benefit vs the cost of lots of angry customers. Would you like to pay lots of money for a compiler, and be told to rewrite all your existing software just because it isn't 100% conformant?

Conforming = adhering to the language standard. Correct = working as intended/specified.

Wilco

Reply to
Wilco Dijkstra

... snip ...

Yes there is something special. It doesn't exist in C89/C90/C95 compilers, requiring C99 systems. And it doesn't exist if CHAR_BIT is larger than 8, i.e. a byte/char fills more than 8 bits. Using it reduces portability.

--
 [mail]: Chuck F (cbfalconer at maineline dot net) 
 [page]: 
            Try the download section.
Reply to
CBFalconer

... snip ...

I routinely compile everything with virtually all error catching enabled. If something appears that is not portable, I either rewrite it to be portable (prefereable, unless there is a significant performance penalty) or remove it to an isolated module. You will be surprised how portable your code becomes, and how easy such writing becomes.

I eschew long functions, and I use the following alias (single line) to execute gcc as cc:

gcc -W -Wall -ansi -pedantic -Wwrite-strings -Wfloat-equal -gstabs+

-ftrapv

--
 [mail]: Chuck F (cbfalconer at maineline dot net) 
 [page]: 
            Try the download section.
Reply to
CBFalconer

... snip ...

I can find -Wstrict-aliasing for my gcc, but no luck for strict-overflow. At what version did it appear?

--
 [mail]: Chuck F (cbfalconer at maineline dot net) 
 [page]: 
            Try the download section.
Reply to
CBFalconer

Neither is an issue as many compilers added without fully supporting C99, and CHAR_BIT not being equal to 8 is quickly becoming as rare as ones-complement (the one unfortunate thing compilers can't seem to agree on is the signedness of char...).

A lot of existing code defines sized typedefs already for portability (like uint32). It's unfortunate it took so long for the C standard to support sized types, but better late than never...

Wilco

Reply to
Wilco Dijkstra

It's still very common in both floating point and integer DSPs.

--
Grant Edwards                   grante             Yow! Half a mind is a
                                  at               terrible thing to waste!
                               visi.com
Reply to
Grant Edwards

That came with 4.1.something as far as I remember. It was one reaction to the Cert vs. Gcc discussion.

Cheers, Nils

Reply to
Nils

Here is your bug:

The m member of struct Foo is not the same as a struct Bar. It's up to the compiler how to pack the members in a struct. It could, for example, add a header before the first member, which would be sufficient to make your code break.

You can rewrite your code like this:

struct Bar { uint8_t m[3]; };

struct Foo { uint8_t x; uint8_t y; uint8_t z; struct Bar bar; };

struct Bar *p1 = &bar; struct Bar *p2 = &(foo->bar);

Then your problem should disappear.

Reply to
jetmarc

This is not the bug, because the own written memcpy function works. I think the bug is, that the wrong memcpy function is selected, but the assembler output has to be analyzed and compared with e.g. your code, or the void* solution I proposed, for verifying this assumption. Maybe someone who has more time than I have could do this.

--
Frank Buss, fb@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
Reply to
Frank Buss

Then we agree - that was the point I was making.

No... but then I use gcc :) :)

Seriously, one thing gcc & friends does let you do easily is run different versions for each project, if you want to. So you can develop a project with gcc-x.y and, perhaps years later, make modifications under that *same* version. You don't have to worry about your dongle not being compatible with your new machine or new windows or new network card, with the supplier only selling a version that won't compile your code any more.

You can version control the compiler binaries along with the project, or just the script needed to build them (since the sources look likely to remain available forever).

Of course, it is still better if optimisations can be made *without* breaking existing code.

OK, thanks.

--

John Devereux
Reply to
John Devereux

It wouldn't be allowed to do that of course, or lots of code would break. However if the GCC version is old it may use the old calling standard with its weird structure alignment. This would make Bar a 4-byte struct with 4-byte alignment, which causes alignment issues. Since the OP didn't report a crash due to a misaligned load, it's not clear that is the problem though.

I thought you reproduced the problem, could you post the assembly output for cp()? I can't reproduce it with GCC4.2, but with the assembler it will be easy to diagnose.

Wilco

Reply to
Wilco Dijkstra

Yup... Saves *much* trouble down-the-road *and* encourages developers learn the nuances of the language.

[snip]

What? No -Werror ?

--
Michael N. Moran           (h) 770 516 7918
5009 Old Field Ct.         (c) 678 521 5460
Kennesaw, GA, USA 30144    http://mnmoran.org

"So often times it happens, that we live our lives in chains
  and we never even know we have the key."
"Already Gone" by Jack Tempchin (recorded by The Eagles)

The Beatles were wrong: 1 & 1 & 1 is 1
Reply to
Michael N. Moran

Well you're unlike many of us who inherit many thousands of lines of existing code and have to live with it. Some of this code doesn't even compile when you change or upgrade compilers, so one often has to explicitly disable certain errors and substitute one language extension with another. However when it does compile it usually works without any problems.

Wilco

Reply to
Wilco Dijkstra

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.