Skip to content

Commit b3618d6

Browse files
committed
menu/ozone: silence UBSan float-to-unsigned conversion in entries draw
UBSan-instrumented run reported: menu/drivers/ozone.c:6401:13: runtime error: -10.0781 is outside the range of representable values of type 'unsigned int' Origin: the value-text y argument to ozone_draw_entry_value() is declared as unsigned, but the y expression at the call site is y /* size_t */ + ozone->dimensions.entry_height / 2 /* int */ + ozone->fonts.entries_label.line_centre_offset /* int */ + scroll_y /* float */ The trailing float promotes the whole sum to float. scroll_y is clamped to (-inf, 0] (lines 10435-10436), so when the topmost partially-visible row's vertical centre lands above the header boundary -- reachable during pointer/wheel scrolling -- the sum goes slightly negative (UBSan saw -10.0781). The implicit float-to-unsigned conversion of a negative is undefined per C11 6.3.1.4 p1. Runtime impact: low. Every modern compiler wraps the conversion to ~UINT_MAX in practice; ozone_draw_entry_value then promotes that back to float as it forwards into gfx_display_draw_text(), producing a coordinate around 4.29e9 that the rasteriser clips off-screen. The value text just doesn't render that frame, visibly matching the off-screen-row case it would have hit on the next frame anyway. Fix: cast the sum through int (defined conversion for the range these screen coordinates occupy: small positive y plus a bounded negative scroll_y) so the negative case wraps in a defined manner rather than triggering UB. Matches the (int)((float)y + scroll_y) idiom already used at lines 3581, 3595, 5970 and 5985 in the same file for sibling y arguments that are signed-typed at the callee. Also folds entry_height / 2 -> entry_height / 2.0f for consistency with the surrounding label and sublabel y expressions at lines 6319 and 6346, which already use float division -- relevant only on the rare odd entry_height where integer division would round half a pixel below the float result.
1 parent 50f3dd8 commit b3618d6

1 file changed

Lines changed: 21 additions & 3 deletions

File tree

menu/drivers/ozone.c

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6398,10 +6398,28 @@ static void ozone_draw_entries(
63986398
+ x_offset
63996399
+ entry_width
64006400
- ozone->dimensions.entry_icon_padding,
6401-
y
6402-
+ ozone->dimensions.entry_height / 2
6401+
/* The y arg is unsigned but the sum below evaluates to
6402+
* a float because of scroll_y, which is clamped to <= 0
6403+
* (see lines 10435-10436). When the row's vertical
6404+
* centre lands above the visible top -- reachable
6405+
* during pointer/wheel scrolling whenever the topmost
6406+
* partially-visible row's value text would draw above
6407+
* the header -- the float value can be slightly
6408+
* negative (UBSan reported -10.0781). Implicit
6409+
* float-to-unsigned conversion of a negative is UB
6410+
* (C11 6.3.1.4 p1); silently wraps to ~UINT_MAX in
6411+
* practice, which the renderer then implicit-converts
6412+
* back to float as a huge off-screen coordinate, so
6413+
* the text just fails to draw rather than corrupting
6414+
* anything. Cast through int -- well-defined for the
6415+
* range these screen coords occupy -- so the negative
6416+
* case wraps in a defined manner instead. Matches the
6417+
* (int)((float)y + scroll_y) idiom used at lines 5970,
6418+
* 5985, 3581, 3595. */
6419+
(int)((float)y
6420+
+ ozone->dimensions.entry_height / 2.0f
64036421
+ ozone->fonts.entries_label.line_centre_offset
6404-
+ scroll_y,
6422+
+ scroll_y),
64056423
alpha_uint32,
64066424
&entry,
64076425
mymat);

0 commit comments

Comments
 (0)