-
Notifications
You must be signed in to change notification settings - Fork 13.3k
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
Check Print::write(byte) return and stop on fail #4527
Check Print::write(byte) return and stop on fail #4527
Conversation
The default Print::write(byte, count) method was continuing to send bytes one-by-one even when a prior write returned 0. Because the buffer pointer was incremented no matter success or fail, this leads to data corruption as you'll not send some bytes in the middle and will then send extra bytes past the end of the passed in buffer. Because there's no concept of timeout, just stop on the first time write(byte) fails and return the total bytes successfully written and let the user worry about retrying or handling an error. Found by @d-a-v and discussed on gitter.
This is a small patch but has potentially large code exposure since it's in the Print:: base class. Appreciate lots of eyeballs on it and its interactions with the 10s of subclasses that implement it. |
My single commentt: are there any examples that should be modified to implement correct error handling for this? |
Good question. Related to this specific code, I would say no because most examples only do Serial.write(a,b) which cannot, by construction, do anything but write every character out. AFAICT, only the WiFi* and SPIFFS methods seem to have the chance to do partial ::writes. Serial.write (most common) will either always print out all chars, or always fail. For SPIFFS, a failed write probably means out of space, so there's generally not a way to recover (but an error would be nice). For WiFi, a retry could actually get the data to the other side (i.e. the write failure could be transient). EEPROM writes are going to be hard failures always since it's not actually writing to EEPROM but a RAM buffer this does not indicate a potential temporary flash issue). Per my grep-fu, the following examples are not checking WiFi*.write() return values and should be fixed in another PR:
|
My attention was caught by SD library. Code is quite tricky. What I could see is SdFile:: is inheriting Stream:: but defines write(void*,len) and not write(uint8_t*,len). This is worth further checking. |
The SD libs are...interesting. Love this comment on SDFile::write():
The signatures are all messed up, too:
|
The default Print::write(byte, count) method was continuing to send bytes one-by-one even when a prior write returned 0. Because the buffer pointer was incremented no matter success or fail, this leads to data corruption as you'll not send some bytes in the middle and will then send extra bytes past the end of the passed in buffer. Because there's no concept of timeout, just stop on the first time write(byte) fails and return the total bytes successfully written and let the user worry about retrying or handling an error. Found by @d-a-v and discussed on gitter. (cherry picked from commit 06352ab)
The default Print::write(byte, count) method was continuing to send
bytes one-by-one even when a prior write returned 0. Because the buffer
pointer was incremented no matter success or fail, this leads to data
corruption as you'll not send some bytes in the middle and will then
send extra bytes past the end of the passed in buffer.
Because there's no concept of timeout, just stop on the first time
write(byte) fails and return the total bytes successfully written
and let the user worry about retrying or handling an error.
Found by @d-a-v as discussed on gitter.