- 
                Notifications
    You must be signed in to change notification settings 
- Fork 4
(WIP) Feature: Implement fstring topics #72
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
base: master
Are you sure you want to change the base?
Conversation
…beginPublish(__FlashStringHelper*) and beginPublish_P(PGM_P)
| Ok, checks look good. Next I will implement a template for  | 
| on what device are you testing? | 
| 
 Same thing will crash on ESP8266 ... | 
…er variants of publish() and publish_P()
        
          
                src/PubSubClient.h
              
                Outdated
          
        
      | uint8_t buildHeader(uint8_t header, size_t length); | ||
| bool writeControlPacket(uint8_t header, size_t length); | ||
| size_t writeBuffer(size_t pos, size_t size); | ||
| template <bool PROGMEM_STRING, typename StringT> | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is one really big disadvantage of templates...
For each type that can call this function, the compiler will generate a new blob of code.
Now it is contained as a private function, which will keep it somewhat manageble.
For publicly called functions you really should take care or else you might end up with a compiled blob for types like const char[10], const char[11], const char[...], ... well you get the point :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, thanks for the hint. I wasn't aware that the compiler creates new code for every type. The goal was to have just one implementation. But wasting flash does not sound good. Maybe I should not use templates and instead just use a parameter:
size_t PubSubClient::writeStringImpl(bool progmem_string, const char* string, size_t pos) {
Do you think this is better?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well the whole idea of templates is indeed to have the same code from a programmer's perspective. But it should be considered as 'inline' code and thus appears potentially multiple times in the binary when a different (template) type is calling it.
N.B. the same does apply to code written in .h files.
If you want to switch to using const char* then you must make sure whatever is calling this function is handling potential PGM reads.
So either wrap it into a String or feed this writeStringImpl per char.
I don't think adding a bool to indicate type is a good thing as you then do the extra implementation in that function and you potentially introduce bugs as you expect the programmer to always have this pair of bool and string to match.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Haven't seen your answer yet ...
The point is, that I need different implementations in case of PROGMEM and normal RAM. In case of ESP8266 / ESP32 I could always use the PROGMEM functions (strlen_P() and so on). But not for AVR. There RAM and ROM needs to be handled differently. So to make this lib compatible to all kinds of MCUs I need a double implementation or a switch (which is also there in case of the template). And as this is an internal function I think I can deal with the risk. As the template implementation does have no benefit, I will change to the conventional parameter.
| I just tested and it works as expected on the ESP8266. | 
| I just ask Copilot for more details about always using strlen_P(). On ESP32/8266 this might be ok, but not on AVR. 
 It just came into my mind as @mcspr changed WString.{h,cpp} in PR esp8266/Arduino#9272 | 
| 
 Note that PR always assumes  Just using  | 
| 
 Yep and you might even get away with relying on the  | 
| } | ||
|  | ||
| bool PubSubClient::publish(const __FlashStringHelper* topic, const __FlashStringHelper* payload, uint8_t qos, bool retained) { | ||
| return publish_P(topic, (const uint8_t*)payload, payload ? strnlen_P(reinterpret_cast<const char*>(payload), MQTT_MAX_POSSIBLE_PACKET_SIZE) : 0, qos, | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a number of strnlen (and _P) checks, which are all against either max. Packet size or buffer size.
However in a packet/buffer, there is also the topic and some header, so those checks are still allowing for some overflow.
The max. possible packet size is probably not really a problem as we won't get that large payloads, or at least not from a char pointer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As far as I understand the max. length is only there to limit strlen somewhere if the payload is corrupted. Or who wants to send ~268MB payload on a micro controller?
Resolves #35
We can not use
publish_P(), as here the payload it already from PROGMEM.But we can implement a
beginPublish_P()with a topic from PROGMEM.