From 172dcfa77531bcaea385e7f6e9dcb5b7d86b64db Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Thu, 19 Oct 2023 16:44:42 +0200 Subject: [PATCH] C++: fix crash when accessing empty model from Slint Fixes #3704 --- CHANGELOG.md | 1 + api/cpp/include/slint.h | 14 +++++++++++++- internal/compiler/generator/cpp.rs | 3 +-- tests/cases/models/array.slint | 2 ++ 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b3cb8e3db..9358f721a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,7 @@ All notable changes to this project are documented in this file. - Removed the need for C++ exceptions in generated code. - Added ability to only build the Slint compiler or use an external compiler. - ESP-IDF: wait for vsync before swapping frame buffers. + - Fixed crash when accessing empty model from Slint ### LSP diff --git a/api/cpp/include/slint.h b/api/cpp/include/slint.h index 8c0b8299e..911189c42 100644 --- a/api/cpp/include/slint.h +++ b/api/cpp/include/slint.h @@ -341,13 +341,25 @@ using ModelPeer = std::weak_ptr; template auto access_array_index(const M &model, size_t index) { - if (const auto v = model->row_data_tracked(index)) { + if (!model) { + return decltype(*model->row_data_tracked(index)) {}; + } else if (const auto v = model->row_data_tracked(index)) { return *v; } else { return decltype(*v) {}; } } +template +long int model_length(const M &model) { + if (!model) { + return 0; + } else { + model->track_row_count_changes(); + return model->row_count(); + } +} + } // namespace private_api /// \rst diff --git a/internal/compiler/generator/cpp.rs b/internal/compiler/generator/cpp.rs index 5d4b4d9bf..c3d367625 100644 --- a/internal/compiler/generator/cpp.rs +++ b/internal/compiler/generator/cpp.rs @@ -3035,8 +3035,7 @@ fn compile_builtin_function_call( format!("{}.size()", a.next().unwrap()) } BuiltinFunction::ArrayLength => { - // note: cast to "long" to avoid signed vs signed comparison warning, because all other integers coming from slint are signed - format!("[](const auto &model){{ (*model).track_row_count_changes(); return long((*model).row_count()); }}({})", a.next().unwrap()) + format!("slint::private_api::model_length({})", a.next().unwrap()) } BuiltinFunction::Rgb => { format!("slint::Color::from_argb_uint8(std::clamp(static_cast({a}) * 255., 0., 255.), std::clamp(static_cast({r}), 0, 255), std::clamp(static_cast({g}), 0, 255), std::clamp(static_cast({b}), 0, 255))", diff --git a/tests/cases/models/array.slint b/tests/cases/models/array.slint index d5732804f..d8bcff4fa 100644 --- a/tests/cases/models/array.slint +++ b/tests/cases/models/array.slint @@ -24,6 +24,7 @@ const TestCase &instance = *handle; assert_eq(instance.get_num_ints(), 5); assert_eq(instance.get_n(), 4); assert_eq(instance.get_third_int(), 3); +assert_eq(instance.get_test(), true); auto model = std::make_shared>(std::vector{1, 2, 3, 4, 5, 6, 7}); instance.set_ints(model); @@ -45,6 +46,7 @@ let instance = TestCase::new().unwrap(); assert_eq!(instance.get_num_ints(), 5); assert_eq!(instance.get_n(), 4); assert_eq!(instance.get_third_int(), 3); +assert_eq!(instance.get_test(), true); let model: std::rc::Rc> = std::rc::Rc::new(vec![1, 2, 3, 4, 5, 6, 7].into()); instance.set_ints(slint::ModelRc::from(model.clone()));