Skip to content
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

wstring: fix concatenation from flash #6368

Merged
merged 2 commits into from
Aug 5, 2019

Conversation

d-a-v
Copy link
Collaborator

@d-a-v d-a-v commented Aug 1, 2019

fixes #6367

@d-a-v
Copy link
Collaborator Author

d-a-v commented Aug 1, 2019

@earlephilhower
while String s = FPSTR("s"); works, String s = PSTR("s"); has the same issue.

I'm not sure if operator= has to be overloaded or if ::copy(const char *cstr, should receive the same fix as for ::concat, or any other clever idea.

@earlephilhower
Copy link
Collaborator

The class structure in String gives me a headache, and I think the operator + helper classes could have the same kinds of issues.

@d-a-v, how about working around the issue by adding a "memmove_P" to the standard newlib functions instead? It's trivial:

void *memmove_P(void *dest, const void *src, size_t n) {
    if (src > (void*)0x40000000) return memcpy_P(dest, src, n);
    else return memmove(dest, src, n);
}

Yes, it crashes if you try to memmove with flash destination, but that's the correct behavior. :)

Something similar is being done for strlen() due to GCC having some silent optimizations that call it.

Then this fix becomes a sed s/memmove/memmove_P/g WString.cpp.

@d-a-v d-a-v added this to the 2.6.0 milestone Aug 5, 2019
@everslick
Copy link
Contributor

I don/t want to sound pushy or something, but can we have a intermittent fix for master in the meantime? ;-)

My firmware depends on += PSTR() in literally hundreds of places and I cannot push my current changes due to API changes in the FS layer.

I'm surprised nobody else complained about += being broken, yet.

@everslick
Copy link
Contributor

Thanks!

@cr1st1p
Copy link

cr1st1p commented Aug 26, 2019

@earlephilhower
while String s = FPSTR("s"); works, String s = PSTR("s"); has the same issue.

I'm not sure if operator= has to be overloaded or if ::copy(const char *cstr, should receive the same fix as for ::concat, or any other clever idea.

Adding just PSTR() to a string and hoping things work is very bad. Never do this unless you really know what you do.
Read first https://arduino-esp8266.readthedocs.io/en/latest/PROGMEM.html

I commented on #6367 and I think you should actually revert this code change.

@d-a-v
Copy link
Collaborator Author

d-a-v commented Aug 26, 2019

Adding just PSTR() to a string and hoping things work is very bad

It's not about hope&magic :)
There's only determinism and potential fixes for issues in open source world.

The fix can be done, but what @earlephilhower proposed in #6368 (comment) is better than what I proposed.
We just need to let him time to implement memmove_P and update strlen in libc (that he provides) then we can use it in WString.

@cr1st1p
Copy link

cr1st1p commented Aug 26, 2019

Adding just PSTR() to a string and hoping things work is very bad

It's not about hope&magic :)
There's only determinism and potential fixes for issues in open source world.

And ... the fix for the user's problem is for him to correctly use flash strings: to use F("sss") and NOT PSTR("xyz") .
Not changing some library code to make it work with a wrong use case, and automatically encouraging people believe that's a normal use of PSTR()
Especially since it looks like the flash strings usage is pretty good explained in https://arduino-esp8266.readthedocs.io/en/latest/PROGMEM.html

The fix can be done, but what @earlephilhower proposed in #6368 (comment) is better than what I proposed.
We just need to let him time to implement memmove_P and update strlen in libc (that he provides) then we can use it in WString.

@d-a-v : That fix is also using some strange hardcoded number (0x40000000).
But you're missing my point about wrong use and assumptions on PSTR() general use, versus use of PSTR() in WString concat. You are continuing to talk about WString use, while I'm describing a larger perspective of the issue.

Imagine people doing these:

  • strtok(PSTR("some string"), ...)
  • strpos(PSTR("some string")
  • strcmp,strcasecmp(PSTR("somestring"), someVariable)
  • gethostbyname(PSTR("google.com"))
  • Library::function1(const char* c) : while(c && *c != '\0' && *c != ';') { do something }
    another library user: Library::function1(PSTR("some string"))

I hope you see now how bad it is to use PSTR() randomly and why promoting that kind of use is bad.

A better change - although it can also probably break things and might not be complete either, is to do changes in pgmspace.h:

  • PGM_P -> cast to const __FlashStringHelper*
  • PGM_VOID_P -> cast to either const __FlashStringHelper* or some other similar class (and make FlashStringHelper* derive from it)
  • PSTR() -> add cast to PGM_P

Or just redirect people having problems to the docs I linked.

@d-a-v
Copy link
Collaborator Author

d-a-v commented Aug 26, 2019

That fix is also using some strange hardcoded number (0x40000000).

This is specific to esp8266. All data above this address are "PROGMEM" and must be accessed by blocks of 32 bits. This code is supposed to be hidden in the newlib port of esp8266 (or cores/ subdirectory where you can see such constants too).

About the documentation on the arduino side, you are right and libraries need to use the correct macros when it comes to use PROGMEM data. We usually redirect users to the docs you mentionned when such issue occurs. Again, #6367 is about restoring something which was working in the past (I think, but anyway internally useful) and is not a good use case to show to users.

@cr1st1p
Copy link

cr1st1p commented Aug 27, 2019

@d-a-v Of course I figured out what's with the 0x40... value. But I would recommend creating a real constant in some header with it. Somehow I think it might be useful in more places.
Examples:

  • gdbstub.c
  • eboot.c

@d-a-v
Copy link
Collaborator Author

d-a-v commented Aug 27, 2019

What about you create a pull request with your proposed recommended changes ?

earlephilhower added a commit to earlephilhower/Arduino that referenced this pull request Sep 13, 2019
memmove_P is now in libc, so use it to allow WString to handle F()
pointers without errors.

Supercedes esp8266#6368

Fixes esp8266#6384
earlephilhower added a commit that referenced this pull request Sep 13, 2019
memmove_P is now in libc, so use it to allow WString to handle F()
pointers without errors.

Supercedes #6368

Fixes #6384
This pull request was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

String += PSTR() crashes (and it should on Arduino, but can esp8266 be more flexible?)
4 participants