Merge pull request #17137 from s-hadinger/malloc_fix_2

Avoid crash if malloc fails take 2
This commit is contained in:
s-hadinger 2022-11-18 21:58:59 +01:00 committed by GitHub
commit eac0bbc1d9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 19 additions and 16 deletions

View File

@ -208,9 +208,12 @@ char* ToHex_P(const unsigned char * in, size_t insz, char * out, size_t outsz, c
// get a fresh malloc allocated string based on the current pointer (can be in PROGMEM)
// It is the caller's responsibility to free the memory
//
// Returns nullptr if something went wrong
char * copyStr(const char * str) {
if (str == nullptr) { return nullptr; }
char * cpy = (char*) malloc(strlen_P(str) + 1);
if (cpy == nullptr) { return nullptr; } // something went wrong
strcpy_P(cpy, str);
return cpy;
}
@ -224,8 +227,10 @@ int32_t ext_vsnprintf_P(char * out_buf, size_t buf_len, const char * fmt_P, va_l
// iterate on fmt to extract arguments and patch them in place
char * fmt_cpy = copyStr(fmt_P);
if (fmt_cpy == nullptr) { return 0; }
if (fmt_cpy == nullptr) { return 0; } // we couldn't copy the format, abort
char * fmt = fmt_cpy;
int32_t ret = 0; // return 0 if unsuccessful
bool aborted = true; // did something went wrong?
const uint32_t ALLOC_SIZE = 12;
static const char * allocs[ALLOC_SIZE] = {}; // initialized to zeroes
@ -277,6 +282,7 @@ int32_t ext_vsnprintf_P(char * out_buf, size_t buf_len, const char * fmt_P, va_l
if (cur_val < min_valid_ptr) { new_val_str = ext_invalid_mem; }
else if (decimals > 0) {
char * hex_char = (char*) malloc(decimals*2 + 2);
if (hex_char == nullptr) { goto free_allocs; }
ToHex_P((const uint8_t *)cur_val, decimals, hex_char, decimals*2 + 2);
new_val_str = hex_char;
allocs[alloc_idx++] = new_val_str;
@ -292,6 +298,7 @@ int32_t ext_vsnprintf_P(char * out_buf, size_t buf_len, const char * fmt_P, va_l
size_t buf_len = (&buf != nullptr) ? buf.len() : 0;
if (buf_len) {
char * hex_char = (char*) malloc(buf_len*2 + 2);
if (hex_char == nullptr) { goto free_allocs; }
ToHex_P(buf.getBuffer(), buf_len, hex_char, buf_len*2 + 2);
new_val_str = hex_char;
allocs[alloc_idx++] = new_val_str;
@ -307,6 +314,7 @@ int32_t ext_vsnprintf_P(char * out_buf, size_t buf_len, const char * fmt_P, va_l
else if (decimals > 0) {
uint32_t val_size = decimals*6 + 2;
char * val_char = (char*) malloc(val_size);
if (val_char == nullptr) { goto free_allocs; }
val_char[0] = '\0';
for (uint32_t count = 0; count < decimals; count++) {
uint32_t value = pgm_read_byte((const uint8_t *)cur_val +1) << 8 | pgm_read_byte((const uint8_t *)cur_val);
@ -328,6 +336,7 @@ int32_t ext_vsnprintf_P(char * out_buf, size_t buf_len, const char * fmt_P, va_l
case 'I': // Input is `uint32_t` 32 bits IP address, output is decimal dotted address
{
char * ip_str = (char*) malloc(16);
if (ip_str == nullptr) { goto free_allocs; }
snprintf_P(ip_str, 16, PSTR("%u.%u.%u.%u"), cur_val & 0xFF, (cur_val >> 8) & 0xFF, (cur_val >> 16) & 0xFF, (cur_val >> 24) & 0xFF);
new_val_str = ip_str;
allocs[alloc_idx++] = new_val_str;
@ -371,6 +380,7 @@ int32_t ext_vsnprintf_P(char * out_buf, size_t buf_len, const char * fmt_P, va_l
}
}
new_val_str = copyStr(hex);
if (new_val_str == nullptr) { goto free_allocs; }
allocs[alloc_idx++] = new_val_str;
}
}
@ -384,24 +394,11 @@ int32_t ext_vsnprintf_P(char * out_buf, size_t buf_len, const char * fmt_P, va_l
if ((decimals < 0) || (decimals > 16)) { decimals = 16; }
U64toHex(*(uint64_t*)cur_val, hex, decimals);
new_val_str = copyStr(hex);
if (new_val_str == nullptr) { goto free_allocs; }
allocs[alloc_idx++] = new_val_str;
}
}
break;
// Trying to do String allocation alternatives, but not as interesting as I thought in the beginning
// case 's':
// {
// new_val_str = copyStr(((String*)cur_val)->c_str());
// allocs[alloc_idx++] = new_val_str;
// }
// break;
// case 'S':
// {
// funcString_t * func_str = (funcString_t*) cur_val;
// new_val_str = copyStr((*func_str)().c_str());
// allocs[alloc_idx++] = new_val_str;
// }
// break;
}
*cur_val_ptr = new_val_str;
*fmt = 's'; // replace `%_X` with `%0s` to display a string instead
@ -413,9 +410,9 @@ int32_t ext_vsnprintf_P(char * out_buf, size_t buf_len, const char * fmt_P, va_l
}
}
// Serial.printf("> format_final=%s\n", fmt_cpy); Serial.flush();
int32_t ret = 0; // return 0 if unsuccessful
if (out_buf != nullptr) {
ret = vsnprintf_P(out_buf, buf_len, fmt_cpy, va_cpy);
aborted = false; // we completed without malloc error
} else {
// if there is no output buffer, we allocate one on the heap
// first we do a dry-run to know the target size
@ -428,12 +425,18 @@ int32_t ext_vsnprintf_P(char * out_buf, size_t buf_len, const char * fmt_P, va_l
allocated_buf[0] = 0; // default to empty string
vsnprintf_P(allocated_buf, target_len + 1, fmt_cpy, va_cpy);
ret = (int32_t) allocated_buf;
aborted = false; // we completed without malloc error
}
}
}
va_end(va_cpy);
free_allocs:
if (aborted && out_buf != nullptr) { // if something went wrong, set output string to empty string to avoid corrupt data
*out_buf = '\0';
}
// disallocated all temporary strings
for (uint32_t i = 0; i < alloc_idx; i++) {
free((void*)allocs[i]); // it is ok to call free() on nullptr so we don't test for nullptr first