Skip to content

Ide 1.5.x Cleaned up a few warnings and fixed strict-aliasing #1399

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from

Conversation

penguin359
Copy link

Cleaned up warnings about unsigned types, unused variables, and
declarations.

Explicitly declare char as signed for cases when compiling with
-funsigned-char.

Fixed strict-aliasing issues in IPAddress.h.

Fixed array overrun where EXTERNAL_NUM_INTERRUPTS was defined too small.

penguin359 added 2 commits May 3, 2013 18:21
Cleaned up warnings about unsigned types, unused variables, and
declarations.

Explicitly declare char as signed for cases when compiling with
-funsigned-char.

Fixed strict-aliasing issues in IPAddress.h.

Fixed array overrun where EXTERNAL_NUM_INTERRUPTS was defined too small.
Local variables can't be declared with PROGMEM and don't need to be when
pointing to a PROGMEM address.
@matthijskooijman
Copy link
Collaborator

Looking at this patch:

  • I see two changes I'm not sure are needed. See comments above (though I just realized I'm testing with gcc 4.8, perhaps things are different for 4.3).
  • I see the IPAddress casting fix. I'm not sure if that one is the proper fix, since it implicitely depends on the fact that the compiler uses a little-endian layout and I think the code you wrote can't be optimized efficiently (havent' checked assembly here, but I recently submitted a gcc bug for a similar case). I'll see if I can come up with another approach using unions which should solve both problems.
  • All changes in HardwareSerial seem to have been fixed or made unneeded by recent changes (one change left which I missed in In HardwareSerial, don't use int for buffer indices #1863, which I added in In HardwareSerial::_rx_complete_irq, don't use int for buffer index #1870).
  • For the change wrt to EXTERNAL_INTERRUPTS, it really looks like that code is quite messy to begin with. I think the problem there is that it could be that an ISR is defined when EXTERNAL_INTERRUPTS does not include that ISR. I guess the proper fix here is to have a single place which detects what ISRs should be available and then have all other code listen to that. Right now, I think that the EXTERNAL_INTERRUPTS, attachInterrupt, detachInterrupt and the ISR declarations all use different macro checks. I started on an attempt to fix this, but since it's quite a mess and I currently do not really care, I gave up again.

@matthijskooijman
Copy link
Collaborator

Oh, and the PROGMEM thing was also fixed in a different way already.

matthijskooijman added a commit to matthijskooijman/Arduino that referenced this pull request Feb 19, 2014
Previously, pointer casting was used, but this resulted in strict-aliasing warnings:

IPAddress.h: In member function ‘IPAddress::operator uint32_t() const’:
IPAddress.h:46:61: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
     operator uint32_t() const { return *((uint32_t*)_address); };
                                                             ^
IPAddress.h: In member function ‘bool IPAddress::operator==(const IPAddress&) const’:
IPAddress.h:47:81: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
     bool operator==(const IPAddress& addr) const { return (*((uint32_t*)_address)) == (*((uint32_t*)addr._address)); };
                                                                                 ^
IPAddress.h:47:114: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
     bool operator==(const IPAddress& addr) const { return (*((uint32_t*)_address)) == (*((uint32_t*)addr._address)); };

Converting between unrelated types like this is commonly done using a union,
which do not break the strict-aliasing rules. Using that union, inside
IPAddress there is now an attribute _address.bytes for the raw byte
arra, or _address.dword for the uint32_t version.

Since we now have easy access to the uint32_t version, this also removes
two memcpy invocations that can just become assignments.

This patch does not change the generated code in any way, the compiler
already optimized away the memcpy calls and the previous casts mean
exactly the same.

This is a different implementation of a part of arduino#1399 and it helps
toward fixing arduino#1728.
matthijskooijman added a commit to matthijskooijman/Arduino that referenced this pull request Feb 19, 2014
peekNextDigit() returns an int, so it can return -1 in addition to all
256 possible bytes. By putting the result in a signe char, all bytes
over 128 will be interpreted as "no bytes available". Furthermore, it
seems that on SAM "char" is unsigned by default, causing the
"if (c < 0)" line a bit further down to always be false.

Using an int is more appropriate.

A different fix for this issue was suggested in arduino#1399. This fix helps
towards arduino#1728.
@ffissore ffissore added New and removed New labels Feb 27, 2014
@penguin359
Copy link
Author

I'd need to review the change related to IPAddress, but the idea was that IPAddress would contain the address in network-byte order which is always big-endian regardless of architecture. Since I move the bytes via explicit offsets, it's unaffected by the compiler's native endianess (AKA host-byte order). The order that the bytes move over SPI is always going to be the same since that's defined by the WizNet chip and should be network byte order. The original code was sensitive to the compiler endianess.

@matthijskooijman
Copy link
Collaborator

@penguin359 The original code, as well as my changes, store the IP address in the "obvious order", e.g. offsets are like 0.1.2.3. When converting to uint32_t, the compiler endianness indeed comes into play, which is little-endian on AVR, so the MSB would be the last part in the IP address, not the first part.

Looking at your code, indeed it doesn't just fix the warning but also removes the endianness dependency. However, I think your code is the same as the original and my code on a little endian compiler, not a big endian one?

I can actually imagine that the uint32_t conversion should always use big-endian interpretation, since then the first part of an IP ends up in the MSB, which is probably what people expect to happen. However, that's a separate change, that affects API compatibility, so that would need separate discussion on the developer's list.

@cmaglie cmaglie added feature request A request to make an enhancement (not a bug fix) Architecture: AVR Applies only to the AVR microcontrollers (Uno, etc.) and removed Component: Toolchain The tools used for compilation and uploading to Arduino boards labels Apr 15, 2015
@matthijskooijman
Copy link
Collaborator

As stated above, most of the things in this PR are already fixed, others are detable. In its current form, this PR is no longer useful. If some of the warnings it fixes still occur and you want to fix them, creating a new PR would be the best approach. I'm closing this one.

ollie1400 pushed a commit to ollie1400/Arduino that referenced this pull request May 2, 2022
Previously, pointer casting was used, but this resulted in strict-aliasing warnings:

IPAddress.h: In member function ‘IPAddress::operator uint32_t() const’:
IPAddress.h:46:61: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
     operator uint32_t() const { return *((uint32_t*)_address); };
                                                             ^
IPAddress.h: In member function ‘bool IPAddress::operator==(const IPAddress&) const’:
IPAddress.h:47:81: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
     bool operator==(const IPAddress& addr) const { return (*((uint32_t*)_address)) == (*((uint32_t*)addr._address)); };
                                                                                 ^
IPAddress.h:47:114: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
     bool operator==(const IPAddress& addr) const { return (*((uint32_t*)_address)) == (*((uint32_t*)addr._address)); };

Converting between unrelated types like this is commonly done using a union,
which do not break the strict-aliasing rules. Using that union, inside
IPAddress there is now an attribute _address.bytes for the raw byte
arra, or _address.dword for the uint32_t version.

Since we now have easy access to the uint32_t version, this also removes
two memcpy invocations that can just become assignments.

This patch does not change the generated code in any way, the compiler
already optimized away the memcpy calls and the previous casts mean
exactly the same.

This is a different implementation of a part of arduino#1399 and it helps
toward fixing arduino#1728.
ollie1400 pushed a commit to ollie1400/Arduino that referenced this pull request May 2, 2022
peekNextDigit() returns an int, so it can return -1 in addition to all
256 possible bytes. By putting the result in a signe char, all bytes
over 128 will be interpreted as "no bytes available". Furthermore, it
seems that on SAM "char" is unsigned by default, causing the
"if (c < 0)" line a bit further down to always be false.

Using an int is more appropriate.

A different fix for this issue was suggested in arduino#1399. This fix helps
towards arduino#1728.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Architecture: AVR Applies only to the AVR microcontrollers (Uno, etc.) Component: Core Related to the code for the standard Arduino API feature request A request to make an enhancement (not a bug fix)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants