From d9c0c09aa8308c52e96388dc55ad6fca533348a1 Mon Sep 17 00:00:00 2001
From: TD-er <gijs.noorlander@gmail.com>
Date: Thu, 25 Aug 2022 22:30:22 +0200
Subject: [PATCH] [String] Fix float assignment using wrong type

Using 3.0.2 assigning a float to a string resulted in undefined behaviour.

```c++
String str;
float myfloat[12][4];
myfloat[0][0] = 1.0f;
str = myfloat[0][0];
```

`str` does contain a single char.

Worked fine in 2.7.4
---
 cores/esp8266/WString.cpp | 120 ++++++++++++++++++++++++++++------
 cores/esp8266/WString.h   | 133 ++++++++++++--------------------------
 2 files changed, 144 insertions(+), 109 deletions(-)

diff --git a/cores/esp8266/WString.cpp b/cores/esp8266/WString.cpp
index 331b2a5409..77b021d4dc 100644
--- a/cores/esp8266/WString.cpp
+++ b/cores/esp8266/WString.cpp
@@ -37,7 +37,7 @@
 /*  Conversion helpers                       */
 /*********************************************/
 
-static String toString(unsigned char value, unsigned char base) {
+static String toString(const unsigned char& value, unsigned char base) {
     String out;
 
     char buf[1 + std::numeric_limits<unsigned char>::digits];
@@ -46,7 +46,7 @@ static String toString(unsigned char value, unsigned char base) {
     return out;
 }
 
-static String toString(int value, unsigned char base) {
+static String toString(const int& value, unsigned char base) {
     String out;
 
     char buf[2 + std::numeric_limits<int>::digits];
@@ -55,7 +55,7 @@ static String toString(int value, unsigned char base) {
     return out;
 }
 
-static String toString(unsigned int value, unsigned char base) {
+static String toString(const unsigned int& value, unsigned char base) {
     String out;
 
     char buf[1 + std::numeric_limits<unsigned int>::digits];
@@ -64,7 +64,7 @@ static String toString(unsigned int value, unsigned char base) {
     return out;
 }
 
-static String toString(long value, unsigned char base) {
+static String toString(const long& value, unsigned char base) {
     String out;
 
     char buf[2 + std::numeric_limits<long>::digits];
@@ -73,7 +73,7 @@ static String toString(long value, unsigned char base) {
     return out;
 }
 
-static String toString(unsigned long value, unsigned char base) {
+static String toString(const unsigned long& value, unsigned char base) {
     String out;
 
     char buf[1 + std::numeric_limits<unsigned long>::digits];
@@ -84,7 +84,7 @@ static String toString(unsigned long value, unsigned char base) {
 
 // TODO: {u,}lltoa don't guarantee that the buffer is usable directly, one should always use the returned pointer
 
-static String toString(long long value, unsigned char base) {
+static String toString(const long long& value, unsigned char base) {
     String out;
 
     char buf[2 + std::numeric_limits<long long>::digits];
@@ -93,7 +93,7 @@ static String toString(long long value, unsigned char base) {
     return out;
 }
 
-static String toString(unsigned long long value, unsigned char base) {
+static String toString(const unsigned long long& value, unsigned char base) {
     String out;
 
     char buf[1 + std::numeric_limits<unsigned long long>::digits];
@@ -102,7 +102,7 @@ static String toString(unsigned long long value, unsigned char base) {
     return out;
 }
 
-static String toString(double value, unsigned char decimalPlaces) {
+static String toString(const double& value, unsigned char decimalPlaces) {
     String out;
 
     char buf[33];
@@ -111,7 +111,7 @@ static String toString(double value, unsigned char decimalPlaces) {
     return out;
 }
 
-static String toString(float value, unsigned char decimalPlaces) {
+static String toString(const float& value, unsigned char decimalPlaces) {
     return toString(static_cast<double>(value), decimalPlaces);
 }
 
@@ -140,42 +140,79 @@ String::String(String &&rval) noexcept {
     move(rval);
 }
 
-String::String(unsigned char value, unsigned char base) :
+String::String(const unsigned char& value, unsigned char base) :
     String(toString(value, base))
 {}
 
-String::String(int value, unsigned char base) :
+String::String(unsigned char value) :
+    String(value, 10)
+{}
+
+String::String(const int& value, unsigned char base) :
     String(toString(value, base))
 {}
 
-String::String(unsigned int value, unsigned char base) :
+String::String(int value) :
+    String(value, 10)
+{}
+
+String::String(const unsigned int& value, unsigned char base) :
     String(toString(value, base))
 {}
 
-String::String(long value, unsigned char base) :
+String::String(unsigned int value) :
+    String(value, 10)
+{}
+
+String::String(const long& value, unsigned char base) :
     String(toString(value, base))
 {}
 
-String::String(unsigned long value, unsigned char base) :
+String::String(long value) :
+    String(value, 10)
+{}
+
+String::String(const unsigned long& value, unsigned char base) :
     String(toString(value, base))
 {}
 
-String::String(long long value, unsigned char base) :
+String::String(unsigned long value) :
+    String(value, 10)
+{}
+
+String::String(const long long& value, unsigned char base) :
     String(toString(value, base))
 {}
 
-String::String(unsigned long long value, unsigned char base) :
+String::String(long long value) :
+    String(value, 10)
+{}
+
+String::String(const unsigned long long& value, unsigned char base) :
     String(toString(value, base))
 {}
 
-String::String(float value, unsigned char decimalPlaces) :
+String::String(unsigned long long value) :
+    String(value, 10)
+{}
+
+String::String(const float& value, unsigned char decimalPlaces) :
     String(toString(value, decimalPlaces))
 {}
 
-String::String(double value, unsigned char decimalPlaces) :
+String::String(float value) :
+    String(value, 2)
+{}
+
+String::String(const double& value, unsigned char decimalPlaces) :
     String(toString(value, decimalPlaces))
 {}
 
+String::String(double value) :
+    String(value, 2)
+{}
+
+
 /*********************************************/
 /*  Memory Management                        */
 /*********************************************/
@@ -314,12 +351,57 @@ String &String::operator =(const __FlashStringHelper *pstr) {
     return *this;
 }
 
-String &String::operator =(char c) {
+String &String::operator =(const char& c) {
     char buffer[2] { c, '\0' };
     *this = buffer;
     return *this;
 }
 
+String &String::operator =(const unsigned char& value) {
+    *this = String(value);
+    return *this;
+}
+
+String &String::operator =(const int& value) {
+    *this = String(value);
+    return *this;
+}
+
+String &String::operator =(const unsigned int& value) {
+    *this = String(value);
+    return *this;
+}
+
+String &String::operator =(const long& value) {
+    *this = String(value);
+    return *this;
+}
+
+String &String::operator =(const unsigned long& value) {
+    *this = String(value);
+    return *this;
+}
+
+String &String::operator =(const long long& value) {
+    *this = String(value);
+    return *this;
+}
+
+String &String::operator =(const unsigned long long& value) {
+    *this = String(value);
+    return *this;
+}
+
+String &String::operator =(const float& value) {
+    *this = String(value);
+    return *this;
+}
+
+String &String::operator =(const double& value) {
+    *this = String(value);
+    return *this;
+}
+
 /*********************************************/
 /*  concat                                   */
 /*********************************************/
diff --git a/cores/esp8266/WString.h b/cores/esp8266/WString.h
index 47a9177534..79a0b1011d 100644
--- a/cores/esp8266/WString.h
+++ b/cores/esp8266/WString.h
@@ -66,50 +66,32 @@ class String {
             sso.isHeap  = 0;
         }
 
-        String(unsigned char, unsigned char base);
-        explicit String(unsigned char value) :
-            String(value, 10)
-        {}
-
-        String(int, unsigned char base);
-        explicit String(int value) :
-            String(value, 10)
-        {}
-
-        String(unsigned int, unsigned char base);
-        explicit String(unsigned int value) :
-            String(value, 10)
-        {}
-
-        String(long, unsigned char base);
-        explicit String(long value) :
-            String(value, 10)
-        {}
-
-        String(unsigned long, unsigned char base);
-        explicit String(unsigned long value) :
-            String(value, 10)
-        {}
-
-        String(long long, unsigned char base);
-        explicit String(long long value) :
-            String(value, 10)
-        {}
-
-        String(unsigned long long, unsigned char base);
-        explicit String(unsigned long long value) :
-            String(value, 10)
-        {}
-
-        String(float, unsigned char decimalPlaces);
-        explicit String(float value) :
-            String(value, 2)
-        {}
-
-        String(double, unsigned char decimalPlaces);
-        explicit String(double value) :
-            String(value, 2)
-        {}
+        String(const unsigned char&, unsigned char base);
+        explicit String(unsigned char value);
+
+        String(const int&, unsigned char base);
+        explicit String(int value);
+
+        String(const unsigned int&, unsigned char base);
+        explicit String(unsigned int value);
+
+        String(const long&, unsigned char base);
+        explicit String(long value);
+
+        String(const unsigned long&, unsigned char base);
+        explicit String(unsigned long value);
+
+        String(const long long&, unsigned char base);
+        explicit String(long long value);
+
+        String(const unsigned long long&, unsigned char base);
+        explicit String(unsigned long long value);
+
+        String(const float&, unsigned char decimalPlaces);
+        explicit String(float value);
+
+        String(const double&, unsigned char decimalPlaces);
+        explicit String(double value);
 
         ~String() {
             invalidate();
@@ -135,52 +117,17 @@ class String {
         String &operator =(String &&rval) noexcept;
         String &operator =(const char *cstr);
         String &operator =(const __FlashStringHelper *str);
-        String &operator =(char c);
-
-        String &operator =(unsigned char value) {
-            *this = String(value);
-            return *this;
-        }
-
-        String &operator =(int value) {
-            *this = String(value);
-            return *this;
-        }
-
-        String &operator =(unsigned int value) {
-            *this = String(value);
-            return *this;
-        }
-
-        String &operator =(long value) {
-            *this = String(value);
-            return *this;
-        }
-
-        String &operator =(unsigned long value) {
-            *this = String(value);
-            return *this;
-        }
-
-        String &operator =(long long value) {
-            *this = String(value);
-            return *this;
-        }
-
-        String &operator =(unsigned long long value) {
-            *this = String(value);
-            return *this;
-        }
-
-        String &operator =(float value) {
-            *this = String(value);
-            return *this;
-        }
-
-        String &operator =(double value) {
-            *this = String(value);
-            return *this;
-        }
+        String &operator =(const char& c);
+
+        String &operator =(const unsigned char& value);
+        String &operator =(const int& value);
+        String &operator =(const unsigned int& value);
+        String &operator =(const long& value);
+        String &operator =(const unsigned long& value);
+        String &operator =(const long long& value);
+        String &operator =(const unsigned long long& value);
+        String &operator =(const float& value);
+        String &operator =(const double& value);
 
         // concatenate (works w/ built-in types, same as assignment)
 
@@ -227,12 +174,18 @@ class String {
         bool operator ==(const char *cstr) const {
             return equals(cstr);
         }
+        bool operator ==(const __FlashStringHelper *s) const {
+            return equals(s);
+        }
         bool operator !=(const String &rhs) const {
             return !equals(rhs);
         }
         bool operator !=(const char *cstr) const {
             return !equals(cstr);
         }
+        bool operator !=(const __FlashStringHelper *s) const {
+            return !equals(s);
+        }
         bool operator <(const String &rhs) const;
         bool operator >(const String &rhs) const;
         bool operator <=(const String &rhs) const;