Skip to content

Commit

Permalink
Fix integer overflow when computing the progress percentage
Browse files Browse the repository at this point in the history
  • Loading branch information
amadvance committed Jan 3, 2024
1 parent a327006 commit 85ca997
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 24 deletions.
20 changes: 10 additions & 10 deletions cmdline/state.c
Original file line number Diff line number Diff line change
Expand Up @@ -4245,7 +4245,7 @@ void state_progress_end(struct snapraid_state* state, block_off_t countpos, bloc

elapsed = now - state->progress_whole_start - state->progress_wasted;

msg_bar("%u%% completed, %u MB accessed", countpos * 100 / countmax, countsize_MB);
msg_bar("%u%% completed, %u MB accessed", muldiv(countpos, 100, countmax), countsize_MB);

msg_bar(" in %u:%02u", (unsigned)(elapsed / 3600), (unsigned)((elapsed % 3600) / 60));

Expand Down Expand Up @@ -4405,7 +4405,7 @@ static void state_progress_graph(struct snapraid_state* state, struct snapraid_i
struct snapraid_disk* disk = i->data;
v = disk->progress_tick[current] - ref(disk->progress_tick, oldest);
printr(disk->name, pad);
printf("%3" PRIu64 "%% | ", v * 100 / tick_total);
printf("%3u%% | ", muldiv(v, 100, tick_total));
printc('*', v * bar / tick_total);
printf("\n");

Expand All @@ -4416,32 +4416,32 @@ static void state_progress_graph(struct snapraid_state* state, struct snapraid_i
for (l = 0; l < state->level; ++l) {
v = state->parity[l].progress_tick[current] - ref(state->parity[l].progress_tick, oldest);
printr(lev_config_name(l), pad);
printf("%3" PRIu64 "%% | ", v * 100 / tick_total);
printf("%3u%% | ", muldiv(v, 100, tick_total));
printc('*', v * bar / tick_total);
printf("\n");
}

v = state->progress_tick_raid[current] - ref(state->progress_tick_raid, oldest);
printr("raid", pad);
printf("%3" PRIu64 "%% | ", v * 100 / tick_total);
printf("%3u%% | ", muldiv(v, 100, tick_total));
printc('*', v * bar / tick_total);
printf("\n");

v = state->progress_tick_hash[current] - ref(state->progress_tick_hash, oldest);
printr("hash", pad);
printf("%3" PRIu64 "%% | ", v * 100 / tick_total);
printf("%3u%% | ", muldiv(v, 100, tick_total));
printc('*', v * bar / tick_total);
printf("\n");

v = state->progress_tick_sched[current] - ref(state->progress_tick_sched, oldest);
printr("sched", pad);
printf("%3" PRIu64 "%% | ", v * 100 / tick_total);
printf("%3u%% | ", muldiv(v, 100, tick_total));
printc('*', v * bar / tick_total);
printf("\n");

v = state->progress_tick_misc[current] - ref(state->progress_tick_misc, oldest);
printr("misc", pad);
printf("%3" PRIu64 "%% | ", v * 100 / tick_total);
printf("%3u%% | ", muldiv(v, 100, tick_total));
printc('*', v * bar / tick_total);
printf("\n");

Expand Down Expand Up @@ -4499,7 +4499,7 @@ int state_progress(struct snapraid_state* state, struct snapraid_io* io, block_o

/* completion percentage */
if (countmax)
out_perc = countpos * 100 / countmax;
out_perc = muldiv(countpos, 100, countmax);

/* if we have at least 5 measures */
if (state->progress_tick >= 5
Expand Down Expand Up @@ -4565,11 +4565,11 @@ int state_progress(struct snapraid_state* state, struct snapraid_io* io, block_o

/* estimate the cpu usage percentage */
if (delta_tick_total != 0)
out_cpu = (unsigned)(delta_tick_cpu * 100U / delta_tick_total);
out_cpu = muldiv(delta_tick_cpu, 100, delta_tick_total);

/* estimate the remaining time in minutes */
if (delta_pos != 0)
out_eta = (countmax - countpos) * delta_time / (60 * delta_pos);
out_eta = muldiv(countmax - countpos, delta_time, 60 * delta_pos);

if (state->opt.force_stats) {
os_clear();
Expand Down
18 changes: 5 additions & 13 deletions cmdline/status.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,6 @@ unsigned day_ago(time_t ref, time_t now)
#define GRAPH_COLUMN 70
#define GRAPH_ROW 15

static unsigned perc(uint64_t part, uint64_t total)
{
if (!total)
return 0;

return (unsigned)(part * 100 / total);
}

/**
* Bit used to mark unscrubbed time info.
*/
Expand Down Expand Up @@ -239,7 +231,7 @@ int state_status(struct snapraid_state* state)
printf(" - ");
} else {
printf("%8" PRIu64, (disk_block_max - disk_block_count) * (uint64_t)state->block_size / GIGA);
printf(" %3u%%", perc(disk_block_count, disk_block_max));
printf(" %3u%%", muldiv(disk_block_count, 100, disk_block_max));
}
printf(" %s\n", disk->name);

Expand All @@ -266,7 +258,7 @@ int state_status(struct snapraid_state* state)
printf("%8.1f", (double)all_wasted / GIGA);
printf("%8" PRIu64, file_size / GIGA);
printf("%8" PRIu64, file_block_free * state->block_size / GIGA);
printf(" %3u%%", perc(file_block_count, file_block_count + file_block_free));
printf(" %3u%%", muldiv(file_block_count, 100, file_block_count + file_block_free));
printf("\n");

/* warn about invalid data free info */
Expand Down Expand Up @@ -468,13 +460,13 @@ int state_status(struct snapraid_state* state)

if (unsynced_blocks) {
printf("WARNING! The array is NOT fully synced.\n");
printf("You have a sync in progress at %u%%.\n", (blockmax - unsynced_blocks) * 100 / blockmax);
printf("You have a sync in progress at %u%%.\n", muldiv(blockmax - unsynced_blocks, 100, blockmax));
} else {
printf("No sync is in progress.\n");
}

if (unscrubbed_blocks) {
printf("The %u%% of the array is not scrubbed.\n", (unscrubbed_blocks * 100 + blockmax - 1) / blockmax);
printf("The %u%% of the array is not scrubbed.\n", muldiv_upper(unscrubbed_blocks, 100, blockmax));
} else {
printf("The full array was scrubbed at least one time.\n");
}
Expand All @@ -487,7 +479,7 @@ int state_status(struct snapraid_state* state)
}

if (rehash) {
printf("You have a rehash in progress at %u%%.\n", (count - rehash) * 100 / count);
printf("You have a rehash in progress at %u%%.\n", muldiv(count - rehash, 100, count));
} else {
if (state->besthash != state->hash) {
printf("No rehash is in progress, but for optimal performance one is recommended.\n");
Expand Down
19 changes: 19 additions & 0 deletions cmdline/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -672,3 +672,22 @@ int lock_unlock(int f)
}
#endif

/****************************************************************************/
/* muldiv */

unsigned muldiv(uint64_t v, uint64_t mul, uint64_t div)
{
if (!div)
return 0;

return (uint32_t)(v * mul / div);
}

unsigned muldiv_upper(uint64_t v, uint64_t mul, uint64_t div)
{
if (!div)
return 0;

return (uint32_t)((v * mul + div - 1) / div);
}

7 changes: 6 additions & 1 deletion cmdline/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -251,5 +251,10 @@ static inline int bit_vect_test(bit_vect_t* bit_vect, size_t off)
return (bit_vect[off / BIT_VECT_SIZE] & mask) != 0;
}

#endif
/****************************************************************************/
/* muldiv */

unsigned muldiv(uint64_t v, uint64_t mul, uint64_t div);
unsigned muldiv_upper(uint64_t v, uint64_t mul, uint64_t div);

#endif

0 comments on commit 85ca997

Please sign in to comment.