Skip to content

Fix for 32 bit processors. #1977

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 1 commit into from
Closed

Fix for 32 bit processors. #1977

wants to merge 1 commit into from

Conversation

Timmmm
Copy link

@Timmmm Timmmm commented Mar 31, 2014

The time-outs do not ever time-out on 32 bit processors if t0 happens to be close to 65535. This means that if you try to open an SD card that isn't present your app will sometimes freeze entirely in card.init() rather than returning an error like it is supposed to.

The time-outs do not ever time-out on 32 bit processors if t0 happens to be close to 65535. This means that if you try to open an SD card that isn't present your app will sometimes freeze entirely in card.init() rather than returning an error like it is supposed to.
@cmaglie cmaglie added this to the Release 1.5.7 milestone Apr 8, 2014
@cmaglie cmaglie modified the milestones: Release 1.5.8, Release 1.5.7 Jul 15, 2014
@ArduinoBot
Copy link
Contributor

Can I build this pull request?

@Timmmm
Copy link
Author

Timmmm commented Aug 22, 2014

Yes? Explain yourself, robot.

On 22 August 2014 12:51, ArduinoBot [email protected] wrote:

Can I build this pull request?


Reply to this email directly or view it on GitHub
#1977 (comment).

@ffissore
Copy link
Contributor

@Timmmm sorry for the comment from arduinobot. we are setting up automated build of all PRs, so that we can provide a downloadable version of the patched IDE

@cmaglie cmaglie modified the milestones: Release 1.5.8, Release 1.5.9 Oct 13, 2014
@agdl
Copy link
Member

agdl commented Nov 3, 2014

@Timmmm can u provide me an example sketch that shows the freezing please?

@matthijskooijman
Copy link
Collaborator

Just looked at the commit, it looks good to me. AFAIU, what happens is that the compiler applies integer promotion, which on a 32-bit system promotes to uint32_t, breaking the overflow.

In the original code:

(((uint16_t)millis() - t0) > SD_INIT_TIMEOUT)

Both sides of the subtraction are uint16_t, but are promoted to uint32_t before subtracting. Overflow in the subtraction now also happens in 32-bit, breaking the calculation.

As an example, consider that t0 is 65535. If (the lower 16 bits of) millis is 1, the expected result is 2 (2 ms passed since t0). However, when this calculation is done in 32-bits, the result is 1 - 65535 = 2^32 + 1 - 65535 = 4294901762 = 0xffff0002 which is clearly incorrect. However, the lower 16 bits of the result do contain the right answer, so casting to uint16_t after subtracting yields correct results.

Note that my analysis would only explain that the timeout would happen too soon around the overflow time, I can't explain the code locking up (but that might be a side effect of some other code?)

I actually think the cast to uint16_t for the result of millis could be dropped as well (unless the compiler doesn't know to optimize away the upper bits of the subtraction without it - would have to be tested).

@ArduinoBot
Copy link
Contributor

Can one of the admins verify this patch?

@cmaglie cmaglie modified the milestones: Release 1.6.0, Release 1.6.1 Feb 18, 2015
@facchinm
Copy link
Member

Very interesting bug!
AFAICS, the unexpected behaviour is in AVR side, not ARM.
If t0 approaches 2^16, the while loop will last forever because we are checking if a number that can be at most 2^16 will ever become bigger than the max value it can assume + a big constant (SD_INIT_TIMEOUT ).
So the strange thing is that this code works with 8bit AVR; I checked the generated ASM and no promotion is applied so when (uint16_t)millis() wraps the result of the check is TRUE (I believe this is a side effect and not the expected behaviour).
However, on ARM with the patch applied only the intermediate value checked against SD_INIT_TIMEOUT is promoted, while the mainline version promotes both the operands before subtracting (leading to the wrong result).
We should take a look in all shared libraries to check if this happens somewhere else.
Merging soon

facchinm added a commit to facchinm/Arduino that referenced this pull request Mar 23, 2015
@facchinm
Copy link
Member

Merged as #2808

@facchinm facchinm closed this Mar 23, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Board: Arduino Due Applies only to the Due Component: Core Related to the code for the standard Arduino API Type: Bug
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants