Skip to content

Commit f05ff5d

Browse files
committed
Add bounds checking or length parameter to decode_utf8
#1 (comment)
1 parent eba4660 commit f05ff5d

File tree

3 files changed

+37
-30
lines changed

3 files changed

+37
-30
lines changed

components/nspanel_easy/text.cpp

Lines changed: 35 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -131,41 +131,48 @@ namespace nspanel_easy {
131131
[&strToSearch](const std::string& str) { return strToSearch == str; });
132132
}
133133

134-
uint32_t decode_utf8(const char* bytes) {
135-
if (!bytes || bytes[0] == '\0') {
136-
return 0;
134+
uint32_t decode_nextion_icon_utf8(const char* bytes, size_t length) {
135+
// Nextion icons are encoded as 1-3 byte UTF-8 sequences only
136+
if (!bytes || length == 0 || length > 3) {
137+
return 0; // Invalid: null, empty, or too long for Nextion icon
137138
}
138-
uint32_t code_point = 0;
139+
139140
unsigned char byte = static_cast<unsigned char>(bytes[0]);
140-
auto is_continuation = [](unsigned char b) { return (b & 0xC0) == 0x80; }; // Helper to check valid continuation byte
141+
uint32_t code_point = 0;
142+
143+
// 1-byte sequence (0x00-0x7F)
141144
if ((byte & 0x80) == 0x00) {
142145
code_point = byte;
143-
} else if ((byte & 0xE0) == 0xC0 && is_continuation(bytes[1])) {
144-
unsigned char b1 = static_cast<unsigned char>(bytes[1]);
145-
code_point = ((byte & 0x1F) << 6) | (b1 & 0x3F);
146-
// Reject overlong encodings (code points < 0x80 encoded as 2 bytes)
147-
if (code_point < 0x80) return 0;
148-
} else if ((byte & 0xF0) == 0xE0 && is_continuation(bytes[1]) && is_continuation(bytes[2])) {
149-
unsigned char b1 = static_cast<unsigned char>(bytes[1]);
150-
unsigned char b2 = static_cast<unsigned char>(bytes[2]);
146+
}
147+
// 2-byte sequence (0xC0-0xDF)
148+
else if ((byte & 0xE0) == 0xC0) {
149+
if (length < 2 || (bytes[1] & 0xC0) != 0x80) {
150+
return 0; // Invalid: insufficient length or bad continuation byte
151+
}
152+
code_point = ((byte & 0x1F) << 6) | (bytes[1] & 0x3F);
153+
// Reject overlong encodings
154+
if (code_point < 0x80) {
155+
return 0;
156+
}
157+
}
158+
// 3-byte sequence (0xE0-0xEF)
159+
else if ((byte & 0xF0) == 0xE0) {
160+
if (length < 3 || (bytes[1] & 0xC0) != 0x80 || (bytes[2] & 0xC0) != 0x80) {
161+
return 0; // Invalid: insufficient length or bad continuation bytes
162+
}
151163
code_point = ((byte & 0x0F) << 12) |
152-
((b1 & 0x3F) << 6) |
153-
(b2 & 0x3F);
164+
((bytes[1] & 0x3F) << 6) |
165+
(bytes[2] & 0x3F);
154166
// Reject overlong encodings and surrogate code points
155-
if (code_point < 0x800 || (code_point >= 0xD800 && code_point <= 0xDFFF)) return 0;
156-
} else if ((byte & 0xF8) == 0xF0 && is_continuation(bytes[1]) && is_continuation(bytes[2]) && is_continuation(bytes[3])) {
157-
unsigned char b1 = static_cast<unsigned char>(bytes[1]);
158-
unsigned char b2 = static_cast<unsigned char>(bytes[2]);
159-
unsigned char b3 = static_cast<unsigned char>(bytes[3]);
160-
code_point = ((byte & 0x07) << 18) |
161-
((b1 & 0x3F) << 12) |
162-
((b2 & 0x3F) << 6) |
163-
(b3 & 0x3F);
164-
// Reject overlong encodings and values beyond Unicode max
165-
if (code_point < 0x10000 || code_point > 0x10FFFF) return 0;
166-
} else {
167-
code_point = 0;
167+
if (code_point < 0x800 || (code_point >= 0xD800 && code_point <= 0xDFFF)) {
168+
return 0;
169+
}
168170
}
171+
// Invalid: 4-byte sequences or invalid leading byte
172+
else {
173+
return 0;
174+
}
175+
169176
return code_point;
170177
}
171178

components/nspanel_easy/text.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ namespace nspanel_easy {
4949
*/
5050
bool isStringInList(const std::string& strToSearch, std::initializer_list<std::string> list);
5151

52-
uint32_t decode_utf8(const char* bytes);
52+
uint32_t decode_nextion_icon_utf8(const char* bytes);
5353

5454
/**
5555
* @brief Compile-time string comparison for C++17/20.

esphome/nspanel_esphome_api.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ api:
212212
#if ESP_LOG_LEVEL >= ESP_LOG_VERBOSE
213213
const uint16_t icon_len = icon.length();
214214
if (icon_len == 3) {
215-
const uint32_t codepoint = decode_utf8(icon.c_str());
215+
const uint32_t code_point = nspanel_easy::decode_nextion_icon_utf8(icon.c_str(), icon_len);
216216
ESP_LOGV("${TAG_API}", " icon: %s (\\u%04" PRIx32 ")", icon.c_str(), codepoint);
217217
} else if (icon_len > 0) {
218218
ESP_LOGV("${TAG_API}", " icon: '%s' (len=%" PRIu16 ")", icon.c_str(), icon_len);

0 commit comments

Comments
 (0)