mirror of https://github.com/arendst/Tasmota.git
Merge pull request #11202 from s-hadinger/crash_protection
Add crash protection to ext_vsnprintf_P
This commit is contained in:
commit
0ea89b2ed6
|
@ -212,6 +212,9 @@ char * copyStr(const char * str) {
|
||||||
return cpy;
|
return cpy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char ext_invalid_mem[] PROGMEM = "<--INVALID-->";
|
||||||
|
const uint32_t min_valid_ptr = 0x3FF00000; // addresses below this line are invalid
|
||||||
|
|
||||||
int32_t ext_vsnprintf_P(char * buf, size_t buf_len, const char * fmt_P, va_list va) {
|
int32_t ext_vsnprintf_P(char * buf, size_t buf_len, const char * fmt_P, va_list va) {
|
||||||
va_list va_cpy;
|
va_list va_cpy;
|
||||||
va_copy(va_cpy, va);
|
va_copy(va_cpy, va);
|
||||||
|
@ -222,7 +225,7 @@ int32_t ext_vsnprintf_P(char * buf, size_t buf_len, const char * fmt_P, va_list
|
||||||
char * fmt = fmt_cpy;
|
char * fmt = fmt_cpy;
|
||||||
|
|
||||||
const uint32_t ALLOC_SIZE = 12;
|
const uint32_t ALLOC_SIZE = 12;
|
||||||
static char * allocs[ALLOC_SIZE] = {}; // initialized to zeroes
|
static const char * allocs[ALLOC_SIZE] = {}; // initialized to zeroes
|
||||||
uint32_t alloc_idx = 0;
|
uint32_t alloc_idx = 0;
|
||||||
static char hex[20]; // buffer used for 64 bits, favor RAM instead of stack to remove pressure
|
static char hex[20]; // buffer used for 64 bits, favor RAM instead of stack to remove pressure
|
||||||
|
|
||||||
|
@ -264,12 +267,13 @@ int32_t ext_vsnprintf_P(char * buf, size_t buf_len, const char * fmt_P, va_list
|
||||||
fmt++;
|
fmt++;
|
||||||
uint32_t cur_val = va_arg(va, uint32_t); // current value
|
uint32_t cur_val = va_arg(va, uint32_t); // current value
|
||||||
const char ** cur_val_ptr = va_cur_ptr4(va, const char*); // pointer to value on stack
|
const char ** cur_val_ptr = va_cur_ptr4(va, const char*); // pointer to value on stack
|
||||||
char * new_val_str = (char*) "";
|
const char * new_val_str = "";
|
||||||
switch (*fmt) {
|
switch (*fmt) {
|
||||||
case 'H': // Hex, decimals indicates the length, default 2
|
case 'H': // Hex, decimals indicates the length, default 2
|
||||||
{
|
{
|
||||||
if (decimals < 0) { decimals = 0; }
|
if (decimals < 0) { decimals = 0; }
|
||||||
if (decimals > 0) {
|
if (cur_val < min_valid_ptr) { new_val_str = ext_invalid_mem; }
|
||||||
|
else if (decimals > 0) {
|
||||||
char * hex_char = (char*) malloc(decimals*2 + 2);
|
char * hex_char = (char*) malloc(decimals*2 + 2);
|
||||||
ToHex_P((const uint8_t *)cur_val, decimals, hex_char, decimals*2 + 2);
|
ToHex_P((const uint8_t *)cur_val, decimals, hex_char, decimals*2 + 2);
|
||||||
new_val_str = hex_char;
|
new_val_str = hex_char;
|
||||||
|
@ -280,13 +284,16 @@ int32_t ext_vsnprintf_P(char * buf, size_t buf_len, const char * fmt_P, va_list
|
||||||
break;
|
break;
|
||||||
case 'B': // Pointer to SBuffer
|
case 'B': // Pointer to SBuffer
|
||||||
{
|
{
|
||||||
const SBuffer & buf = *(const SBuffer*)cur_val;
|
if (cur_val < min_valid_ptr) { new_val_str = ext_invalid_mem; }
|
||||||
size_t buf_len = (&buf != nullptr) ? buf.len() : 0;
|
else {
|
||||||
if (buf_len) {
|
const SBuffer & buf = *(const SBuffer*)cur_val;
|
||||||
char * hex_char = (char*) malloc(buf_len*2 + 2);
|
size_t buf_len = (&buf != nullptr) ? buf.len() : 0;
|
||||||
ToHex_P(buf.getBuffer(), buf_len, hex_char, buf_len*2 + 2);
|
if (buf_len) {
|
||||||
new_val_str = hex_char;
|
char * hex_char = (char*) malloc(buf_len*2 + 2);
|
||||||
allocs[alloc_idx++] = new_val_str;
|
ToHex_P(buf.getBuffer(), buf_len, hex_char, buf_len*2 + 2);
|
||||||
|
new_val_str = hex_char;
|
||||||
|
allocs[alloc_idx++] = new_val_str;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -315,40 +322,46 @@ int32_t ext_vsnprintf_P(char * buf, size_t buf_len, const char * fmt_P, va_list
|
||||||
// Note: float MUST be passed by address, because C alsays promoted float to double when in vararg
|
// Note: float MUST be passed by address, because C alsays promoted float to double when in vararg
|
||||||
case 'f': // input is `float`, printed to float with 2 decimals
|
case 'f': // input is `float`, printed to float with 2 decimals
|
||||||
{
|
{
|
||||||
bool truncate = false;
|
if (cur_val < min_valid_ptr) { new_val_str = ext_invalid_mem; }
|
||||||
if (decimals < 0) {
|
else {
|
||||||
decimals = -decimals;
|
bool truncate = false;
|
||||||
truncate = true;
|
if (decimals < 0) {
|
||||||
}
|
decimals = -decimals;
|
||||||
float number = *(float*)cur_val;
|
truncate = true;
|
||||||
if (isnan(number) || isinf(number)) {
|
}
|
||||||
new_val_str = (char*) "null";
|
float number = *(float*)cur_val;
|
||||||
} else {
|
if (isnan(number) || isinf(number)) {
|
||||||
dtostrf(*(float*)cur_val, (decimals + 2), decimals, hex);
|
new_val_str = "null";
|
||||||
|
} else {
|
||||||
if (truncate) {
|
dtostrf(*(float*)cur_val, (decimals + 2), decimals, hex);
|
||||||
uint32_t last = strlen(hex) - 1;
|
|
||||||
// remove trailing zeros
|
if (truncate) {
|
||||||
while (hex[last] == '0') {
|
uint32_t last = strlen(hex) - 1;
|
||||||
hex[last--] = 0; // remove last char
|
// remove trailing zeros
|
||||||
}
|
while (hex[last] == '0') {
|
||||||
// remove trailing dot
|
hex[last--] = 0; // remove last char
|
||||||
if (hex[last] == '.') {
|
}
|
||||||
hex[last] = 0;
|
// remove trailing dot
|
||||||
}
|
if (hex[last] == '.') {
|
||||||
|
hex[last] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
new_val_str = copyStr(hex);
|
||||||
|
allocs[alloc_idx++] = new_val_str;
|
||||||
}
|
}
|
||||||
new_val_str = copyStr(hex);
|
|
||||||
allocs[alloc_idx++] = new_val_str;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
// '%_X' outputs a 64 bits unsigned int to uppercase HEX with 16 digits
|
// '%_X' outputs a 64 bits unsigned int to uppercase HEX with 16 digits
|
||||||
case 'X': // input is `uint64_t*`, printed as 16 hex digits (no prefix 0x)
|
case 'X': // input is `uint64_t*`, printed as 16 hex digits (no prefix 0x)
|
||||||
{
|
{
|
||||||
if ((decimals < 0) || (decimals > 16)) { decimals = 16; }
|
if (cur_val < min_valid_ptr) { new_val_str = ext_invalid_mem; }
|
||||||
U64toHex(*(uint64_t*)cur_val, hex, decimals);
|
else {
|
||||||
new_val_str = copyStr(hex);
|
if ((decimals < 0) || (decimals > 16)) { decimals = 16; }
|
||||||
allocs[alloc_idx++] = new_val_str;
|
U64toHex(*(uint64_t*)cur_val, hex, decimals);
|
||||||
|
new_val_str = copyStr(hex);
|
||||||
|
allocs[alloc_idx++] = new_val_str;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
// Trying to do String allocation alternatives, but not as interesting as I thought in the beginning
|
// Trying to do String allocation alternatives, but not as interesting as I thought in the beginning
|
||||||
|
@ -382,7 +395,7 @@ int32_t ext_vsnprintf_P(char * buf, size_t buf_len, const char * fmt_P, va_list
|
||||||
|
|
||||||
// disallocated all temporary strings
|
// disallocated all temporary strings
|
||||||
for (uint32_t i = 0; i < alloc_idx; i++) {
|
for (uint32_t i = 0; i < alloc_idx; i++) {
|
||||||
free(allocs[i]); // it is ok to call free() on nullptr so we don't test for nullptr first
|
free((void*)allocs[i]); // it is ok to call free() on nullptr so we don't test for nullptr first
|
||||||
allocs[i] = nullptr;
|
allocs[i] = nullptr;
|
||||||
}
|
}
|
||||||
free(fmt_cpy); // free the local copy of the format string
|
free(fmt_cpy); // free the local copy of the format string
|
||||||
|
|
Loading…
Reference in New Issue