From 6b09c6d8f71cbd55aaa1786137fcbad9cc324691 Mon Sep 17 00:00:00 2001 From: inogenous <123803852+inogenous@users.noreply.github.com> Date: Tue, 13 Aug 2024 11:55:43 +0200 Subject: [PATCH] Prevent div by zero crash in mana widget Prevents division by zero crash when displaying widgets with defined break levels. Example of where previous crash from div-by-zero happened: * Provided save used the `zenfs_thick_sidebar`, which includes widget `zenfs_mana_bar_14_no_label` that defines break levels. * When running the provided save, mana value is usually at `v=201` with `min=0` `max=201`. * Those values are computed by `known_magic::max_mana` where internal values are `bionic_penalty=999` `mana_base=1000` `int_bonus=200`. * But when int falls (because of tiredness), then `known_magic::max_mana` will return `0` because `int_bonus=-100`. * This leads to `_var_max=0` in `widget::value_color` and thus `var_range=0` which causes the div by zero. Backtrace of previous crash beng fixed: ``` Thread 1 "cataclysm-tiles" received signal SIGFPE, Arithmetic exception. 0x0000555556a9c54e in widget::value_color (this=this@entry=0x7fffffffb8d8, value=value@entry=201) at src/widget.cpp:1310 1310 const int value_offset = ( 100 * ( value - _var_min ) ) / var_range; (gdb) bt #0 0x0000555556a9c54e in widget::value_color (this=this@entry=0x7fffffffb8d8, value=value@entry=201) at src/widget.cpp:1310 #1 0x0000555556aa37dc in widget::color_value_string[abi:cxx11](int, int) (this=this@entry=0x7fffffffb8d8, value=201, width_max=width_max@entry=14) at src/widget.cpp:1262 #2 0x0000555556aa38ca in widget::show[abi:cxx11](avatar const&, unsigned int) (this=this@entry=0x7fffffffb8d8, ava=..., max_width=max_width@entry=14) at src/widget.cpp:890 #3 0x0000555556aa497f in widget::layout[abi:cxx11](avatar const&, unsigned int, int, bool) (this=this@entry=0x7fffffffb8d8, ava=..., max_width=, label_width=label_width@entry=0, skip_pad=false) at src/widget.cpp:1834 #4 0x0000555556aa42c2 in widget::layout[abi:cxx11](avatar const&, unsigned int, int, bool) (this=this@entry=0x7fffffffbe88, ava=..., max_width=, label_width=label_width@entry=9, skip_pad=false) at src/widget.cpp:1794 #5 0x0000555556aa3cfa in widget::layout[abi:cxx11](avatar const&, unsigned int, int, bool) (this=this@entry=0x7fffffffc438, ava=..., max_width=, label_width=label_width@entry=0, skip_pad=false) at src/widget.cpp:1724 #6 0x0000555556aa42c2 in widget::layout[abi:cxx11](avatar const&, unsigned int, int, bool) (this=this@entry=0x7fffffffc9e8, ava=..., max_width=, label_width=label_width@entry=0, skip_pad=false) at src/widget.cpp:1794 #7 0x0000555556aa42c2 in widget::layout[abi:cxx11](avatar const&, unsigned int, int, bool) (this=this@entry=0x555562c47160, ava=..., max_width=, max_width@entry=64, label_width=, skip_pad=skip_pad@entry=false) at src/widget.cpp:1794 #8 0x0000555556aa5222 in custom_draw_func (args=...) at src/widget.cpp:970 #9 0x0000555555ec4360 in std::function::operator() (this=0x555597eb1780, __args#0=...) at /usr/include/c++/14/bits/std_function.h:591 #10 game::draw_panels (this=this@entry=0x55555827ef50, force_draw=force_draw@entry=true) at src/game.cpp:4007 #11 0x0000555555eed1ac in game::draw (this=0x55555827ef50, ui=...) at src/game.cpp:3961 #12 0x00005555569a962c in ui_adaptor::redraw_invalidated () at src/ui_manager.cpp:440 #13 0x00005555569a96e9 in ui_adaptor::redraw () at src/ui_manager.cpp:345 #14 0x00005555569a9710 in ui_manager::redraw () at src/ui_manager.cpp:506 #15 0x0000555555dd0850 in do_turn () at src/do_turn.cpp:712 #16 0x00005555557a138d in main (argc=, argv=) at src/main.cpp:873 (gdb) print var_range $1 = 0 (gdb) print value $2 = 201 (gdb) print _var_min $3 = 0 (gdb) print _var_max $4 = 0 ``` --- src/widget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widget.cpp b/src/widget.cpp index 2f0acf870bf41..faa69108b1929 100644 --- a/src/widget.cpp +++ b/src/widget.cpp @@ -1306,7 +1306,7 @@ nc_color widget::value_color( int value ) // Get range of values from min to max const int var_range = _var_max - _var_min; - if( ! _breaks.empty() ) { + if( var_range > 0 && ! _breaks.empty() ) { const int value_offset = ( 100 * ( value - _var_min ) ) / var_range; for( int i = 0; i < color_max; i++ ) { if( value_offset < _breaks[i] ) {