[v1] libcamera: controls: ControlList::set(): Ensure init list size and type
diff mbox series

Message ID 20251210182450.2782689-1-barnabas.pocze@ideasonboard.com
State New
Headers show
Series
  • [v1] libcamera: controls: ControlList::set(): Ensure init list size and type
Related show

Commit Message

Barnabás Pőcze Dec. 10, 2025, 6:24 p.m. UTC
The initializer list should have the same type as the control, otherwise
the `ControlValue` will have a type different from what is indicated in
the template parameter of the control. This leads to an assertion failure
when the control is later retrieved. Ensure that by using the same template
parameter for the init list.

The same applies to the size of the init list. If the size of the control
is static, then the init list must have the same size. Ensure that by
adding an `assert()` for statically sized controls.

For example, previously

  list.set(controls::FrameDurationLimits, { 1000, 2000 });

would lead to an assertion failure when the control was retrieved since the
deduced type in the init list would be `int`, making the `ControlValue` be of
`ControlTypeInteger32` instead of the expected `ControlTypeInteger64`.

Signed-off-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com>
---
 include/libcamera/controls.h   | 10 +++++++---
 src/libcamera/controls.cpp     |  3 ++-
 test/controls/control_list.cpp | 14 ++++++++++++++
 3 files changed, 23 insertions(+), 4 deletions(-)

Patch
diff mbox series

diff --git a/include/libcamera/controls.h b/include/libcamera/controls.h
index c970e4b7b8..2a891f4f0c 100644
--- a/include/libcamera/controls.h
+++ b/include/libcamera/controls.h
@@ -457,14 +457,18 @@  public:
 		val->set<T>(value);
 	}
 
-	template<typename T, typename V, size_t Size>
-	void set(const Control<Span<T, Size>> &ctrl, const std::initializer_list<V> &value)
+	template<typename T, size_t Size>
+	void set(const Control<Span<T, Size>> &ctrl,
+		 const std::initializer_list<std::remove_cv_t<T>> &value)
 	{
+		if constexpr (Size != dynamic_extent)
+			assert(Size == value.size());
+
 		ControlValue *val = find(ctrl.id());
 		if (!val)
 			return;
 
-		val->set(Span<const typename std::remove_cv_t<V>, Size>{ value.begin(), value.size() });
+		val->set(Span<const T, Size>{ value.begin(), value.size() });
 	}
 
 	const ControlValue &get(unsigned int id) const;
diff --git a/src/libcamera/controls.cpp b/src/libcamera/controls.cpp
index 1e1b49e6bd..90f89947ce 100644
--- a/src/libcamera/controls.cpp
+++ b/src/libcamera/controls.cpp
@@ -1074,7 +1074,8 @@  bool ControlList::contains(unsigned int id) const
  */
 
 /**
- * \fn ControlList::set(const Control<Span<T, Size>> &ctrl, const std::initializer_list<V> &value)
+ * \fn ControlList::set(const Control<Span<T, Size>> &ctrl,
+ *                      const std::initializer_list<std::remove_cv_t<T>> &value)
  * \copydoc ControlList::set(const Control<T> &ctrl, const V &value)
  */
 
diff --git a/test/controls/control_list.cpp b/test/controls/control_list.cpp
index e27325c30c..0e6b0bd27c 100644
--- a/test/controls/control_list.cpp
+++ b/test/controls/control_list.cpp
@@ -246,6 +246,20 @@  protected:
 			return TestFail;
 		}
 
+		ControlList list2;
+
+		/* Check deduced type of init list */
+		{
+			const auto &ctrl = controls::FrameDurationLimits;
+
+			list2.set(ctrl, { 1, 2 });
+
+			if (list2.get(ctrl.id()).type() != static_cast<const ControlId &>(ctrl).type()) {
+				cout << "Type of init list has been incorrectly deduced";
+				return TestFail;
+			}
+		}
+
 		return TestPass;
 	}
 };