-
Notifications
You must be signed in to change notification settings - Fork 13.3k
Crash when sending content from flash to client using the webserver #596
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
Comments
|
The weird thing is that this function works, even though the data is in flash.
Because flash data apparently isn't supported that well, how can I copy the flash data to a buffer in ram before sending it? |
Yes you can copy PROGMEM data into RAM via String: String content(DATA_css);
server.send(200, "text/css", content); |
I uploaded my sketch to my webserver, you can download it here: http://rnpl.us/code.zip Maybe that helps while debugging the problem. |
/cc @Makuna |
Regards... And thanks for all the job you are doing ! |
@patjazz: Sometimes it works with two progmem instances, but I've not yet been able to find a pattern in when it works and when it doesn't. My guess is that it fails above a certain size. (Wild guess, big chance it's bullshit: could it be that the flash is divided in pages and that the first PROGMEM instance fits into the first page but the second does not? (Then while reading the ESP fails because it only reads the first page and then tries to read more data than what it read from the flash?) |
My thought about new WebServer needs : |
With Progmem, you really need to look closely at the Arduino docs, the way it was original designed is not how I would have done it, but it is the way it is in this project for compatibility. The core of the problem is, the compiler can't tell the difference between these two variables to decide which function to call; as the PROGMEM doesn't not effect the type, it only effects where in memory the data is stored.
But the memory location they are stored at have different requirements. Specifically, in flash, the data pointer must always be 32bit aligned and reads are always 32bits. But the same code reads both flash and ram. So if the code tries to read one byte at a time, it will cause an exception. If you use the above "stringInFlash" variable in program method (end in _P), then there is an implied knowledge that the passed variable is in flash and it does the right thing in the method. So, in your example, you have
since it can't tell DATA_css is in flash, you need to let it know, by casting it like this
This assumes you have enough RAM to temporally store the complete string. FYI: I glanced at the Server code to see how hard it would be to convert to have a send_P(), unfortunately it is not simple; but in the long run I agree it would be interesting. As @martinayotte mentions, a good start is to separate out the header and content for sending, then the rest gets simpler. |
Why the compiler and/or linker can't do an ALIGN 32 ? even if we loose 3 bytes ? as they know that the data will stay in flash ? (if it is an alignment problem....) |
@patjazz The compiler does create the data aligned, but you can't read a single byte, which most string methods assume they can do. You can only read 32bits (as you can't reference the other bytes due to the pointer must remain 32bit aligned). And the compiler doesn't know anything about where it stored, this seems to be dark spot in C/C++ where it doesn't track this information with the type. I wish that Arduino guys had created a more solid solution for this, like providing a real pointer wrapper and not the kludge _FlashStringHelper. |
Hi Makuna, EDIT : coding should be simply copy/paste and adding the memccpy_P(), it should take 5 mins. But testing and commit can take hours ... :-) |
@martinayotte If it still has to allocate the full buffer inside to copy memory, sure, but I think the right solution is to try to "chunk" it so the memory allocation is smaller allowing a large content size to be used without taking a larger memory footprint. Oh yeah, testing ;-) |
Note: more then 1460 Byte can note be send by TCP at one. so bigger buffer make no sense. |
p.s. I am working on exposing a send_P();
|
Great! On Fri, Jul 24, 2015, 20:20 Michael Miller [email protected] wrote:
|
If the compiler doesn't do string duplication removal, and you call send_P is many locations, those can add up quickly. |
Can't you give it a pointer to a const char[] PROGMEM? |
@mplus a PGM_P is a const char[] PROGMEM. |
ah, okay But, how would it then be possible to cause duplication when you are using a pointer? |
@Makuna, Great ! |
@mplus pointer uses are not commonly used by Arduino AVR developers, so you may see code where the same literal string is used like... ... Serial.print (F ("dup")); |
@rnplus the content type is also progmem string, but you are not passing one. please provide the smallest sample sketch that demonstrates your problem and I will look into it. |
As discussed here http://www.esp8266.com/viewtopic.php?f=28&t=4688#p26962, I think the current ESP8266WebServer::sendContent_P() should be used for now only with text or html, since it doesn't have "size_t size" argument to tell the end of the content, it rely on NULL character at the end of the string. Maybe we will end up to add this "size_t size", this will allow binary too, like I did in my commit for WiFiClient::write_P() but still pending for merge. |
This commit waiting for PR merge should fix all the issues : |
Released in staging |
I get this error using the stable, staging and latest (compiled from source) version of the arduino package.
Data:
The text was updated successfully, but these errors were encountered: