BLI: Prevent Overflow in Grouped Number Output #105263

Merged
Harley Acheson merged 2 commits from Harley/blender:GroupedOverflow into main 2023-03-02 17:38:47 +01:00
12 changed files with 92 additions and 44 deletions

View File

@ -3706,8 +3706,8 @@ void BKE_ptcache_update_info(PTCacheID *pid)
}
else {
PTCacheMem *pm = cache->mem_cache.first;
char formatted_tot[16];
char formatted_mem[15];
char formatted_tot[BLI_STR_FORMAT_INT32_GROUPED_SIZE];
char formatted_mem[BLI_STR_FORMAT_INT64_BYTE_UNIT_SIZE];
long long int bytes = 0.0f;
int i;

View File

@ -310,7 +310,7 @@ class HashTableStats {
std::cout << " Removed Slots: " << removed_amount_ << " (" << removed_load_factor_ * 100.0f
<< " %)\n";
char memory_size_str[15];
char memory_size_str[BLI_STR_FORMAT_INT64_BYTE_UNIT_SIZE];
BLI_str_format_byte_unit(memory_size_str, size_in_bytes_, true);
std::cout << " Size: ~" << memory_size_str << "\n";
std::cout << " Size per Slot: " << size_per_element_ << " bytes\n";

View File

@ -17,6 +17,22 @@
extern "C" {
#endif
/* Buffer size of maximum `uint64` plus commas and terminator. */
#define BLI_STR_FORMAT_UINT64_GROUPED_SIZE 27
/* Buffer size of maximum `int32` with commas and terminator. */
#define BLI_STR_FORMAT_INT32_GROUPED_SIZE 16
/* Buffer size of maximum `int64` formatted as byte size (with GiB for example). */
#define BLI_STR_FORMAT_INT64_BYTE_UNIT_SIZE 15
/* Buffer size of maximum `int32` formatted as compact decimal size ("15.6M" for example). */
#define BLI_STR_FORMAT_INT32_DECIMAL_UNIT_SIZE 7
/* Buffer size of maximum `int32` formatted as very short decimal size ("15B" for example). */
#define BLI_STR_FORMAT_INT32_INTEGER_UNIT_SIZE 5
Harley marked this conversation as resolved
Review

Should be BLI_STR_FORMAT_INT32_INTEGER_UNIT_SIZE

Should be BLI_STR_FORMAT_INT32_INTEGER_UNIT_SIZE
/**
* Duplicates the first \a len bytes of cstring \a str
* into a newly mallocN'd string and returns it. \a str
@ -276,7 +292,8 @@ const char *BLI_str_escape_find_quote(const char *str) ATTR_NONNULL();
* \param num: Number to format
* \return The length of \a dst
*/
size_t BLI_str_format_int_grouped(char dst[16], int num) ATTR_NONNULL();
size_t BLI_str_format_int_grouped(char dst[BLI_STR_FORMAT_INT32_GROUPED_SIZE], int num)
ATTR_NONNULL();
/**
* Format uint64_t with decimal grouping.
* 1000 -> 1,000
@ -285,7 +302,8 @@ size_t BLI_str_format_int_grouped(char dst[16], int num) ATTR_NONNULL();
* \param num: Number to format
* \return The length of \a dst
*/
size_t BLI_str_format_uint64_grouped(char dst[16], uint64_t num) ATTR_NONNULL();
size_t BLI_str_format_uint64_grouped(char dst[BLI_STR_FORMAT_UINT64_GROUPED_SIZE], uint64_t num)
ATTR_NONNULL();
/**
* Format a size in bytes using binary units.
* 1000 -> 1 KB
@ -296,7 +314,9 @@ size_t BLI_str_format_uint64_grouped(char dst[16], uint64_t num) ATTR_NONNULL();
* \param bytes: Number to format.
* \param base_10: Calculate using base 10 (GB, MB, ...) or 2 (GiB, MiB, ...).
*/
void BLI_str_format_byte_unit(char dst[15], long long int bytes, bool base_10) ATTR_NONNULL();
void BLI_str_format_byte_unit(char dst[BLI_STR_FORMAT_INT64_BYTE_UNIT_SIZE],
long long int bytes,
bool base_10) ATTR_NONNULL();
/**
* Format a count to up to 6 places (plus '\0' terminator) string using long number
* names abbreviations. Used to produce a compact representation of large numbers.
@ -315,7 +335,8 @@ void BLI_str_format_byte_unit(char dst[15], long long int bytes, bool base_10) A
*
* Length of 7 is the maximum of the resulting string, for example, `-15.5K\0`.
*/
void BLI_str_format_decimal_unit(char dst[7], int number_to_format) ATTR_NONNULL();
void BLI_str_format_decimal_unit(char dst[BLI_STR_FORMAT_INT32_DECIMAL_UNIT_SIZE],
int number_to_format) ATTR_NONNULL();
/**
* Format a count to up to 3 places (plus minus sign, plus '\0' terminator) string using long
* number names abbreviations. Used to produce a compact representation of large numbers as
@ -337,7 +358,8 @@ void BLI_str_format_decimal_unit(char dst[7], int number_to_format) ATTR_NONNULL
*
* Length of 5 is the maximum of the resulting string, for example, `-15K\0`.
*/
void BLI_str_format_integer_unit(char dst[5], int number_to_format) ATTR_NONNULL();
void BLI_str_format_integer_unit(char dst[BLI_STR_FORMAT_INT32_INTEGER_UNIT_SIZE],
int number_to_format) ATTR_NONNULL();
/**
* Compare two strings without regard to case.
*

View File

@ -974,7 +974,7 @@ class Vector {
std::cout << " Capacity: " << (capacity_end_ - begin_) << "\n";
std::cout << " Inline Capacity: " << InlineBufferCapacity << "\n";
char memory_size_str[15];
char memory_size_str[BLI_STR_FORMAT_INT64_BYTE_UNIT_SIZE];
BLI_str_format_byte_unit(memory_size_str, sizeof(*this), true);
std::cout << " Size on Stack: " << memory_size_str << "\n";
}

View File

@ -1098,7 +1098,7 @@ int BLI_string_find_split_words(
/** \name String Formatting (Numeric)
* \{ */
static size_t BLI_str_format_int_grouped_ex(char src[16], char dst[16], int num_len)
static size_t BLI_str_format_int_grouped_ex(char *src, char *dst, int num_len)
{
char *p_src = src;
char *p_dst = dst;
@ -1122,25 +1122,25 @@ static size_t BLI_str_format_int_grouped_ex(char src[16], char dst[16], int num_
return (size_t)(p_dst - dst);
}
size_t BLI_str_format_int_grouped(char dst[16], int num)
size_t BLI_str_format_int_grouped(char dst[BLI_STR_FORMAT_INT32_GROUPED_SIZE], int num)
{
char src[16];
char src[BLI_STR_FORMAT_INT32_GROUPED_SIZE];
const int num_len = BLI_snprintf(src, sizeof(src), "%d", num);
return BLI_str_format_int_grouped_ex(src, dst, num_len);
}
size_t BLI_str_format_uint64_grouped(char dst[16], uint64_t num)
size_t BLI_str_format_uint64_grouped(char dst[BLI_STR_FORMAT_UINT64_GROUPED_SIZE], uint64_t num)
{
/* NOTE: Buffer to hold maximum `uint64`, which is 1.8e+19. but
* we also need space for commas and null-terminator. */
char src[27];
char src[BLI_STR_FORMAT_UINT64_GROUPED_SIZE];
const int num_len = BLI_snprintf(src, sizeof(src), "%" PRIu64 "", num);
return BLI_str_format_int_grouped_ex(src, dst, num_len);
}
void BLI_str_format_byte_unit(char dst[15], long long int bytes, const bool base_10)
void BLI_str_format_byte_unit(char dst[BLI_STR_FORMAT_INT64_BYTE_UNIT_SIZE],
long long int bytes,
const bool base_10)
{
double bytes_converted = bytes;
int order = 0;
@ -1159,14 +1159,15 @@ void BLI_str_format_byte_unit(char dst[15], long long int bytes, const bool base
decimals = MAX2(order - 1, 0);
/* Format value first, stripping away floating zeroes. */
const size_t dst_len = 15;
const size_t dst_len = BLI_STR_FORMAT_INT64_BYTE_UNIT_SIZE;
size_t len = BLI_snprintf_rlen(dst, dst_len, "%.*f", decimals, bytes_converted);
len -= (size_t)BLI_str_rstrip_float_zero(dst, '\0');
dst[len++] = ' ';
BLI_strncpy(dst + len, base_10 ? units_base_10[order] : units_base_2[order], dst_len - len);
}
void BLI_str_format_decimal_unit(char dst[7], int number_to_format)
void BLI_str_format_decimal_unit(char dst[BLI_STR_FORMAT_INT32_DECIMAL_UNIT_SIZE],
int number_to_format)
{
float number_to_format_converted = number_to_format;
int order = 0;
@ -1179,7 +1180,7 @@ void BLI_str_format_decimal_unit(char dst[7], int number_to_format)
order++;
}
const size_t dst_len = 7;
const size_t dst_len = BLI_STR_FORMAT_INT32_DECIMAL_UNIT_SIZE;
int decimals = 0;
if ((order > 0) && fabsf(number_to_format_converted) < 100.0f) {
decimals = 1;
@ -1187,7 +1188,8 @@ void BLI_str_format_decimal_unit(char dst[7], int number_to_format)
BLI_snprintf(dst, dst_len, "%.*f%s", decimals, number_to_format_converted, units[order]);
}
void BLI_str_format_integer_unit(char dst[5], const int number_to_format)
void BLI_str_format_integer_unit(char dst[BLI_STR_FORMAT_INT32_INTEGER_UNIT_SIZE],
const int number_to_format)
{
float number_to_format_converted = number_to_format;
int order = 0;
@ -1207,7 +1209,7 @@ void BLI_str_format_integer_unit(char dst[5], const int number_to_format)
order++;
}
const size_t dst_len = 5;
const size_t dst_len = BLI_STR_FORMAT_INT32_INTEGER_UNIT_SIZE;
BLI_snprintf(dst,
dst_len,
"%s%s%d%s",

View File

@ -324,7 +324,7 @@ TEST(string, StrPartitionExUtf8)
/* BLI_str_format_int_grouped */
TEST(string, StrFormatIntGrouped)
{
char number_str[16];
char number_str[BLI_STR_FORMAT_INT32_GROUPED_SIZE];
int number;
BLI_str_format_int_grouped(number_str, number = 0);
@ -355,10 +355,32 @@ TEST(string, StrFormatIntGrouped)
EXPECT_STREQ("-999", number_str);
}
/* BLI_str_format_uint64_grouped */
TEST(string, StrFormatUint64Grouped)
{
char number_str[BLI_STR_FORMAT_UINT64_GROUPED_SIZE];
uint64_t number;
BLI_str_format_uint64_grouped(number_str, number = 0);
EXPECT_STREQ("0", number_str);
BLI_str_format_uint64_grouped(number_str, number = 1);
EXPECT_STREQ("1", number_str);
BLI_str_format_uint64_grouped(number_str, number = 999);
EXPECT_STREQ("999", number_str);
BLI_str_format_uint64_grouped(number_str, number = 1000);
EXPECT_STREQ("1,000", number_str);
BLI_str_format_uint64_grouped(number_str, number = 18446744073709551615);
EXPECT_STREQ("18,446,744,073,709,551,615", number_str);
}
/* BLI_str_format_byte_unit */
TEST(string, StrFormatByteUnits)
{
char size_str[15];
char size_str[BLI_STR_FORMAT_INT64_BYTE_UNIT_SIZE];
long long int size;
/* Base 10 */
@ -423,7 +445,7 @@ TEST(string, StrFormatByteUnits)
/* BLI_str_format_decimal_unit */
TEST(string, StrFormatDecimalUnits)
{
char size_str[7];
char size_str[BLI_STR_FORMAT_INT32_DECIMAL_UNIT_SIZE];
int size;
BLI_str_format_decimal_unit(size_str, size = 0);
@ -518,7 +540,7 @@ TEST(string, StrFormatDecimalUnits)
/* BLI_str_format_integer_unit */
TEST(string, StrFormatIntegerUnits)
{
char size_str[7];
char size_str[BLI_STR_FORMAT_INT32_INTEGER_UNIT_SIZE];
int size;
BLI_str_format_integer_unit(size_str, size = 0);

View File

@ -256,7 +256,7 @@ void EEVEE_lightcache_info_update(SceneEEVEE *eevee)
return;
}
char formatted_mem[15];
char formatted_mem[BLI_STR_FORMAT_INT64_BYTE_UNIT_SIZE];
BLI_str_format_byte_unit(formatted_mem, eevee_lightcache_memsize_get(lcache), false);
int irr_samples = eevee_lightcache_irradiance_sample_count(lcache);

View File

@ -61,8 +61,6 @@
ENUM_OPERATORS(eUserpref_StatusBar_Flag, STATUSBAR_SHOW_VERSION)
#define MAX_INFO_NUM_LEN 16
struct SceneStats {
uint64_t totvert, totvertsel, totvertsculpt;
uint64_t totedge, totedgesel;
@ -76,15 +74,19 @@ struct SceneStats {
struct SceneStatsFmt {
/* Totals */
char totvert[MAX_INFO_NUM_LEN], totvertsel[MAX_INFO_NUM_LEN], totvertsculpt[MAX_INFO_NUM_LEN];
char totface[MAX_INFO_NUM_LEN], totfacesel[MAX_INFO_NUM_LEN];
char totedge[MAX_INFO_NUM_LEN], totedgesel[MAX_INFO_NUM_LEN], totfacesculpt[MAX_INFO_NUM_LEN];
char totbone[MAX_INFO_NUM_LEN], totbonesel[MAX_INFO_NUM_LEN];
char totobj[MAX_INFO_NUM_LEN], totobjsel[MAX_INFO_NUM_LEN];
char totlamp[MAX_INFO_NUM_LEN], totlampsel[MAX_INFO_NUM_LEN];
char tottri[MAX_INFO_NUM_LEN];
char totgplayer[MAX_INFO_NUM_LEN], totgpframe[MAX_INFO_NUM_LEN];
char totgpstroke[MAX_INFO_NUM_LEN], totgppoint[MAX_INFO_NUM_LEN];
char totvert[BLI_STR_FORMAT_UINT64_GROUPED_SIZE], totvertsel[BLI_STR_FORMAT_UINT64_GROUPED_SIZE],
totvertsculpt[BLI_STR_FORMAT_UINT64_GROUPED_SIZE];
char totface[BLI_STR_FORMAT_UINT64_GROUPED_SIZE], totfacesel[BLI_STR_FORMAT_UINT64_GROUPED_SIZE];
char totedge[BLI_STR_FORMAT_UINT64_GROUPED_SIZE], totedgesel[BLI_STR_FORMAT_UINT64_GROUPED_SIZE],
totfacesculpt[BLI_STR_FORMAT_UINT64_GROUPED_SIZE];
char totbone[BLI_STR_FORMAT_UINT64_GROUPED_SIZE], totbonesel[BLI_STR_FORMAT_UINT64_GROUPED_SIZE];
char totobj[BLI_STR_FORMAT_UINT64_GROUPED_SIZE], totobjsel[BLI_STR_FORMAT_UINT64_GROUPED_SIZE];
char totlamp[BLI_STR_FORMAT_UINT64_GROUPED_SIZE], totlampsel[BLI_STR_FORMAT_UINT64_GROUPED_SIZE];
char tottri[BLI_STR_FORMAT_UINT64_GROUPED_SIZE];
char totgplayer[BLI_STR_FORMAT_UINT64_GROUPED_SIZE],
totgpframe[BLI_STR_FORMAT_UINT64_GROUPED_SIZE];
char totgpstroke[BLI_STR_FORMAT_UINT64_GROUPED_SIZE],
totgppoint[BLI_STR_FORMAT_UINT64_GROUPED_SIZE];
};
static bool stats_mesheval(const Mesh *me_eval, bool is_selected, SceneStats *stats)
@ -599,7 +601,7 @@ static const char *info_statusbar_string(Main *bmain,
ViewLayer *view_layer,
char statusbar_flag)
{
char formatted_mem[15];
char formatted_mem[BLI_STR_FORMAT_INT64_BYTE_UNIT_SIZE];
size_t ofs = 0;
static char info[256];
int len = sizeof(info);

View File

@ -913,7 +913,7 @@ static void create_inspection_string_for_geometry_info(const geo_log::GeometryIn
}
auto to_string = [](int value) {
char str[16];
char str[BLI_STR_FORMAT_INT32_GROUPED_SIZE];
BLI_str_format_int_grouped(str, value);
return std::string(str);
};

View File

@ -1747,7 +1747,7 @@ static void outliner_draw_userbuts(uiBlock *block,
uiBut *bt;
ID *id = tselem->id;
const char *tip = nullptr;
char buf[16] = "";
char buf[BLI_STR_FORMAT_INT32_GROUPED_SIZE] = "";
int but_flag = UI_BUT_DRAG_LOCK;
if (ID_IS_LINKED(id)) {

View File

@ -571,11 +571,11 @@ static void spreadsheet_footer_region_draw(const bContext *C, ARegion *region)
std::stringstream ss;
ss << "Rows: ";
if (runtime->visible_rows != runtime->tot_rows) {
char visible_rows_str[16];
char visible_rows_str[BLI_STR_FORMAT_INT32_GROUPED_SIZE];
BLI_str_format_int_grouped(visible_rows_str, runtime->visible_rows);
ss << visible_rows_str << " / ";
}
char tot_rows_str[16];
char tot_rows_str[BLI_STR_FORMAT_INT32_GROUPED_SIZE];
BLI_str_format_int_grouped(tot_rows_str, runtime->tot_rows);
ss << tot_rows_str << " | Columns: " << runtime->tot_columns;
std::string stats_str = ss.str();

View File

@ -143,7 +143,7 @@ void GeometryDataSetTreeViewItem::build_row(uiLayout &row)
if (const std::optional<int> count = this->count()) {
/* Using the tree row button instead of a separate right aligned button gives padding
* to the right side of the number, which it didn't have with the button. */
char element_count[7];
char element_count[BLI_STR_FORMAT_INT32_DECIMAL_UNIT_SIZE];
BLI_str_format_decimal_unit(element_count, *count);
UI_but_hint_drawstr_set((uiBut *)this->view_item_button(), element_count);
}