Segmentation fault when switching to the color wheel in "Fill and Stroke"
Steps to reproduce:
- open Inkscape, have "Fill and Stroke" dialog open
- draw rectangle
- click on a "Wheel" tab in "Fill and Stroke"
What happened?
Segmentation fault.
What should have happened?
No crash.
Inkscape Version and Operating System:
- Inkscape Version: Inkscape 1.0beta2 (d0959305, 2019-12-07, custom), debug build
- Operating System: Kubuntu 19.10
- KDE Plasma Version: 5.16.5
- KDE Frameworks Version: 5.62.0
- Qt Version: 5.12.4
- Kernel Version: 5.3.0-24-generic
- OS Type: 64-bit
Thread 1 "inkscape" received signal SIGSEGV, Segmentation fault.
0x00007ffff759fec3 in Inkscape::UI::Widget::draw_vertical_padding (p0=..., p1=..., padding=padding@entry=3, pad_upwards=true, buffer=buffer@entry=0x555559946dd0,
height=144, stride=stride@entry=455) at ../src/ui/widget/ink-color-wheel.cpp:22
22 guint32 get_color() { return (int(r*255) << 16 | int(g*255) << 8 | int(b*255)); };
(gdb) bt
#0 0x00007ffff759fec3 in Inkscape::UI::Widget::draw_vertical_padding(color_point, color_point, int, bool, unsigned int*, int, int)
(p0=..., p1=..., padding=padding@entry=3, pad_upwards=true, buffer=buffer@entry=0x555559946dd0, height=144, stride=stride@entry=455)
at ../src/ui/widget/ink-color-wheel.cpp:22
#1 0x00007ffff75a1795 in Inkscape::UI::Widget::ColorWheel::on_draw(Cairo::RefPtr<Cairo::Context> const&) (this=0x55555760e330, cr=...)
at ../src/ui/widget/ink-color-wheel.cpp:327
#2 0x00007ffff5ff9516 in Gtk::Widget_Class::draw_callback(_GtkWidget*, _cairo*) () at /lib/x86_64-linux-gnu/libgtkmm-3.0.so.1
#3 0x00007ffff5654f44 in () at /lib/x86_64-linux-gnu/libgtk-3.so.0
I think this is a corner case where interpolation by lerp turns into extrapolation due to bad input.
This line:
for (int y = min_y; y <= max_y; ++y)
(397 in ink-color-wheel.cpp)
casts min_y
to int, and with min_y..max_y
equal (44.799984377990178..44.800015622012779) it makes y
= 40 and causes start_x
to blow up:
int start_x = lerp(p0, p1, p0.y, p1.y, y).x;
start_x
is optimized out, but we can trace it down, because it is added to p
, which makes p
point way past the allocated buffer.
(gdb) info frame
Stack level 0, frame at 0x7fffffff8e70:
rip = 0x7ffff759fec3 in Inkscape::UI::Widget::draw_vertical_padding (../src/ui/widget/ink-color-wheel.cpp:22); saved rip = 0x7ffff75a1795
called by frame at 0x7fffffff9130
source language c++.
Arglist at 0x7fffffff8e40, args: p0=..., p1=..., padding=padding@entry=3, pad_upwards=true, buffer=buffer@entry=0x5555598c9c90, height=144, stride=stride@entry=455
Locals at 0x7fffffff8e40, Previous frame's sp is 0x7fffffff8e70
Saved registers:
rbx at 0x7fffffff8e48, rbp at 0x7fffffff8e50, r12 at 0x7fffffff8e58, r13 at 0x7fffffff8e60, rip at 0x7fffffff8e68
(gdb) info locals
offset = 0
point = {x = 2.0231988197199046e-320, y = 44.799984377990178, r = 0, g = 0, b = 0}
x = 2187944
start_x = <optimized out>
end_x = 2412811
p = 0x55555a136000
y = 44
gradient = <optimized out>
min_y = 44.799984377990178
max_y = 44.800015622012779
min_x = 179.88820901475671
max_x = 274.11177294649843
(gdb) x 0x55555a136000
0x55555a136000: Cannot access memory at address 0x55555a136000
(gdb) info args
p0 = {x = 274.11177294649843, y = 44.799984377990178, r = 0, g = 0, b = 0}
p1 = {x = 179.88820901475671, y = 44.800015622012779, r = 1, g = 1, b = 1}
padding = 3
pad_upwards = true
buffer = 0x5555598c9c90
height = 144
stride = 455
(gdb) x 0x5555598c9c90
0x5555598c9c90: 0xf50c33b0
(gdb) print p - buffer
$1 = 2207964