Skip to content

Commit

Permalink
Fix code that could lead to a possible deadlock. (#1380)
Browse files Browse the repository at this point in the history
* Fix code that could lead to a possible deadlock.

Drop implementations are not called until the end of a statement. The statement changed in this commit therefore took 4 read locks on a RwLock which can lead to problems if a write lock is requested between any of these read locks. The code looks like it would only hold one lock at a time but it does not drop any of the locks until after the arithmatic operations complete, which leads to this situation. See https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=996079046184329f3a9df1cd19c87da8 to see this in action. The fix is to just take one lock and share it between the three calls to num_presses, letting it drop at the end of the scope.

* Fix code that may cause a deadlock in `MenuRoot::stationary_interaction`

The issue here is related to that in 9673b8f in that the lock is not dropped when it is expected.  Since the `RwLockReadGuard` produced by `ctx.input()` has a reference taken from it (one into `pointer`), the lock cannot be dropped until that reference is no longre valid, which is the end of the scope (in this case this function).  The following `ctx.input()` then attempts to aquire a second lock on the `RwLock`, creating the same situation that was found in the referenced commit.

This has been resolved by holding one lock on the input for the whole function.

* Reference this PR from comments in the code for future maintainers

* Add the change to the changelog

* Use full link to PR

* Use full link to PR

Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
  • Loading branch information
DusterTheFirst and emilk committed Mar 20, 2022
1 parent 465c961 commit 8bb381d
Show file tree
Hide file tree
Showing 3 changed files with 15 additions and 11 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Expand Up @@ -17,7 +17,7 @@ NOTE: [`epaint`](epaint/CHANGELOG.md), [`eframe`](eframe/CHANGELOG.md), [`egui_w

### Fixed 🐛
* Fixed ComboBoxes always being rendered left-aligned ([#1304](https://github.com/emilk/egui/pull/1304)).

* Fixed ui code that could lead to a deadlock ([#1380](https://github.com/emilk/egui/pull/1380))

## 0.17.0 - 2022-02-22 - Improved font selection and image handling

Expand Down
12 changes: 6 additions & 6 deletions egui/src/menu.rs
Expand Up @@ -277,10 +277,10 @@ impl MenuRoot {
root: &mut MenuRootManager,
id: Id,
) -> MenuResponse {
let pointer = &response.ctx.input().pointer;
if (response.clicked() && root.is_menu_open(id))
|| response.ctx.input().key_pressed(Key::Escape)
{
// Lock the input once for the whole function call (see https://github.com/emilk/egui/pull/1380).
let input = response.ctx.input();

if (response.clicked() && root.is_menu_open(id)) || input.key_pressed(Key::Escape) {
// menu open and button clicked or esc pressed
return MenuResponse::Close;
} else if (response.clicked() && !root.is_menu_open(id))
Expand All @@ -290,8 +290,8 @@ impl MenuRoot {
// or button hovered while other menu is open
let pos = response.rect.left_bottom();
return MenuResponse::Create(pos, id);
} else if pointer.any_pressed() && pointer.primary_down() {
if let Some(pos) = pointer.interact_pos() {
} else if input.pointer.any_pressed() && input.pointer.primary_down() {
if let Some(pos) = input.pointer.interact_pos() {
if let Some(root) = root.inner.as_mut() {
if root.id == id {
// pressed somewhere while this menu is open
Expand Down
12 changes: 8 additions & 4 deletions egui/src/widgets/slider.rs
Expand Up @@ -455,10 +455,14 @@ impl<'a> Slider<'a> {

fn value_ui(&mut self, ui: &mut Ui, position_range: RangeInclusive<f32>) -> Response {
// If `DragValue` is controlled from the keyboard and `step` is defined, set speed to `step`
let change = ui.input().num_presses(Key::ArrowUp) as i32
+ ui.input().num_presses(Key::ArrowRight) as i32
- ui.input().num_presses(Key::ArrowDown) as i32
- ui.input().num_presses(Key::ArrowLeft) as i32;
let change = {
// Hold one lock rather than 4 (see https://github.com/emilk/egui/pull/1380).
let input = ui.input();

input.num_presses(Key::ArrowUp) as i32 + input.num_presses(Key::ArrowRight) as i32
- input.num_presses(Key::ArrowDown) as i32
- input.num_presses(Key::ArrowLeft) as i32
};
let speed = match self.step {
Some(step) if change != 0 => step,
_ => self.current_gradient(&position_range),
Expand Down

0 comments on commit 8bb381d

Please sign in to comment.