From a717238f767a3401e15aa4a254be6ef13b6f9574 Mon Sep 17 00:00:00 2001 From: Frank Date: Sun, 21 May 2023 13:21:38 +0200 Subject: [PATCH] espalexa robustness improvements * prevent string buffer overflows (stack corruption) * avoid division by zero (program might crash) * avoid log(0) which is undefined, too * use faster math routines for float (logf, powf) --- wled00/src/dependencies/espalexa/Espalexa.h | 26 ++++++++-------- .../dependencies/espalexa/EspalexaDevice.cpp | 30 ++++++++++++++----- 2 files changed, 35 insertions(+), 21 deletions(-) diff --git a/wled00/src/dependencies/espalexa/Espalexa.h b/wled00/src/dependencies/espalexa/Espalexa.h index 0850ddea..5c780e24 100644 --- a/wled00/src/dependencies/espalexa/Espalexa.h +++ b/wled00/src/dependencies/espalexa/Espalexa.h @@ -10,7 +10,7 @@ */ /* * @title Espalexa library - * @version 2.7.0 + * @version 2.7.1 * @author Christian Schwinne * @license MIT * @contributors d-999 @@ -50,7 +50,7 @@ #include "../network/Network.h" #ifdef ESPALEXA_DEBUG - #pragma message "Espalexa 2.7.0 debug mode" + #pragma message "Espalexa 2.7.1 debug mode" #define EA_DEBUG(x) Serial.print (x) #define EA_DEBUGLN(x) Serial.println (x) #else @@ -142,7 +142,7 @@ private: } //device JSON string: color+temperature device emulates LCT015, dimmable device LWB010, (TODO: on/off Plug 01, color temperature device LWT010, color device LST001) - void deviceJsonString(EspalexaDevice* dev, char* buf) + void deviceJsonString(EspalexaDevice* dev, char* buf, size_t maxBuf) // softhack007 "size" parameter added, to avoid buffer overrun { char buf_lightid[27]; encodeLightId(dev->getId() + 1, buf_lightid); @@ -153,19 +153,19 @@ private: //TODO: %f is not working for some reason on ESP8266 in v0.11.0 (was fine in 0.10.2). Need to investigate //sprintf_P(buf_col,PSTR(",\"hue\":%u,\"sat\":%u,\"effect\":\"none\",\"xy\":[%f,%f]") // ,dev->getHue(), dev->getSat(), dev->getX(), dev->getY()); - sprintf_P(buf_col,PSTR(",\"hue\":%u,\"sat\":%u,\"effect\":\"none\",\"xy\":[%s,%s]"),dev->getHue(), dev->getSat(), + snprintf_P(buf_col, sizeof(buf_col), PSTR(",\"hue\":%u,\"sat\":%u,\"effect\":\"none\",\"xy\":[%s,%s]"),dev->getHue(), dev->getSat(), ((String)dev->getX()).c_str(), ((String)dev->getY()).c_str()); char buf_ct[16] = ""; //white spectrum support if (static_cast(dev->getType()) > 1 && dev->getType() != EspalexaDeviceType::color) - sprintf(buf_ct, ",\"ct\":%u", dev->getCt()); + snprintf(buf_ct, sizeof(buf_ct), ",\"ct\":%u", dev->getCt()); char buf_cm[20] = ""; if (static_cast(dev->getType()) > 1) - sprintf(buf_cm,PSTR("\",\"colormode\":\"%s"), modeString(dev->getColorMode())); + snprintf(buf_cm, sizeof(buf_cm), PSTR("\",\"colormode\":\"%s"), modeString(dev->getColorMode())); - sprintf_P(buf, PSTR("{\"state\":{\"on\":%s,\"bri\":%u%s%s,\"alert\":\"none%s\",\"mode\":\"homeautomation\",\"reachable\":true}," + snprintf_P(buf, maxBuf, PSTR("{\"state\":{\"on\":%s,\"bri\":%u%s%s,\"alert\":\"none%s\",\"mode\":\"homeautomation\",\"reachable\":true}," "\"type\":\"%s\",\"name\":\"%s\",\"modelid\":\"%s\",\"manufacturername\":\"Philips\",\"productname\":\"E%u" "\",\"uniqueid\":\"%s\",\"swversion\":\"espalexa-2.7.0\"}") @@ -219,10 +219,10 @@ private: EA_DEBUGLN("# Responding to description.xml ... #\n"); IPAddress localIP = Network.localIP(); char s[16]; - sprintf(s, "%d.%d.%d.%d", localIP[0], localIP[1], localIP[2], localIP[3]); + snprintf(s, sizeof(s), "%d.%d.%d.%d", localIP[0], localIP[1], localIP[2], localIP[3]); char buf[1024]; - sprintf_P(buf,PSTR("" + snprintf_P(buf, sizeof(buf), PSTR("" "" "10" "http://%s:80/" @@ -297,7 +297,7 @@ private: char buf[1024]; - sprintf_P(buf,PSTR("HTTP/1.1 200 OK\r\n" + snprintf_P(buf, sizeof(buf), PSTR("HTTP/1.1 200 OK\r\n" "EXT:\r\n" "CACHE-CONTROL: max-age=100\r\n" // SSDP_INTERVAL "LOCATION: http://%s:80/description.xml\r\n" @@ -493,7 +493,7 @@ public: unsigned idx = decodeLightKey(devId); EA_DEBUGLN(idx); char buf[50]; - sprintf_P(buf,PSTR("[{\"success\":{\"/lights/%u/state/\": true}}]"),devId); + snprintf_P(buf,sizeof(buf),PSTR("[{\"success\":{\"/lights/%u/state/\": true}}]"),devId); server->send(200, "application/json", buf); if (idx >= currentDeviceCount) return true; //return if invalid ID EspalexaDevice* dev = devices[idx]; @@ -571,7 +571,7 @@ public: jsonTemp += ':'; char buf[512]; - deviceJsonString(devices[i], buf); + deviceJsonString(devices[i], buf, sizeof(buf)-1); jsonTemp += buf; if (i < currentDeviceCount-1) jsonTemp += ','; } @@ -588,7 +588,7 @@ public: return true; } char buf[512]; - deviceJsonString(devices[idx], buf); + deviceJsonString(devices[idx], buf, sizeof(buf)-1); server->send(200, "application/json", buf); } diff --git a/wled00/src/dependencies/espalexa/EspalexaDevice.cpp b/wled00/src/dependencies/espalexa/EspalexaDevice.cpp index fa643491..407a9d61 100644 --- a/wled00/src/dependencies/espalexa/EspalexaDevice.cpp +++ b/wled00/src/dependencies/espalexa/EspalexaDevice.cpp @@ -2,6 +2,15 @@ #include "EspalexaDevice.h" +// debug macros +#ifdef ESPALEXA_DEBUG + #define EA_DEBUG(x) Serial.print (x) + #define EA_DEBUGLN(x) Serial.println (x) +#else + #define EA_DEBUG(x) + #define EA_DEBUGLN(x) +#endif + EspalexaDevice::EspalexaDevice(){} EspalexaDevice::EspalexaDevice(String deviceName, BrightnessCallbackFunction gnCallback, uint8_t initialValue) { //constructor for dimmable device @@ -124,18 +133,21 @@ uint32_t EspalexaDevice::getRGB() { //TODO tweak a bit to match hue lamp characteristics //based on https://gist.github.com/paulkaplan/5184275 - float temp = 10000/ _ct; //kelvins = 1,000,000/mired (and that /100) + float temp = (_ct != 0) ? (10000/ _ct) : 2; //kelvins = 1,000,000/mired (and that /100) softhack007: avoid division by zero - using "2" as substitute float r, g, b; +#ifdef ESPALEXA_DEBUG + if (_ct == 0) {EA_DEBUGLN(F("EspalexaDevice::getRGB() Warning: ct = 0!"));} +#endif if (temp <= 66) { r = 255; g = temp; - g = 99.470802 * log(g) - 161.119568; + g = 99.470802 * logf(g) - 161.119568; if (temp <= 19) { b = 0; } else { b = temp-10; - b = 138.517731 * log(b) - 305.044793; + b = 138.517731 * logf(b) - 305.044793; } } else { r = temp - 60; @@ -192,9 +204,9 @@ uint32_t EspalexaDevice::getRGB() b = 1.0f; } // Apply gamma correction - r = r <= 0.0031308f ? 12.92f * r : (1.0f + 0.055f) * pow(r, (1.0f / 2.4f)) - 0.055f; - g = g <= 0.0031308f ? 12.92f * g : (1.0f + 0.055f) * pow(g, (1.0f / 2.4f)) - 0.055f; - b = b <= 0.0031308f ? 12.92f * b : (1.0f + 0.055f) * pow(b, (1.0f / 2.4f)) - 0.055f; + r = r <= 0.0031308f ? 12.92f * r : (1.0f + 0.055f) * powf(r, (1.0f / 2.4f)) - 0.055f; + g = g <= 0.0031308f ? 12.92f * g : (1.0f + 0.055f) * powf(g, (1.0f / 2.4f)) - 0.055f; + b = b <= 0.0031308f ? 12.92f * b : (1.0f + 0.055f) * powf(b, (1.0f / 2.4f)) - 0.055f; if (r > b && r > g) { // red is biggest @@ -328,8 +340,10 @@ void EspalexaDevice::setColor(uint8_t r, uint8_t g, uint8_t b) float X = r * 0.664511f + g * 0.154324f + b * 0.162028f; float Y = r * 0.283881f + g * 0.668433f + b * 0.047685f; float Z = r * 0.000088f + g * 0.072310f + b * 0.986039f; - _x = X / (X + Y + Z); - _y = Y / (X + Y + Z); + if ((r+g+b) > 0) { // softhack007: avoid division by zero + _x = X / (X + Y + Z); + _y = Y / (X + Y + Z); + } else { _x = _y = 0.5f;} // softhack007: use default values in case of "black" _rgb = ((r << 16) | (g << 8) | b); _mode = EspalexaColorMode::xy; }