From 8c4b516f3655c8c22e986eeda357b3a056da3e77 Mon Sep 17 00:00:00 2001 From: AlexWells Date: Fri, 12 Jul 2024 09:01:59 +0100 Subject: [PATCH] Ensure returned arrays are not writeable --- CHANGELOG.rst | 1 + softioc/device.py | 7 ++++++- tests/test_records.py | 13 +++++++++++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 1d809e51..b7957daa 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -23,6 +23,7 @@ Removed: Changed: - `AsyncioDispatcher cleanup tasks atexit <../../pull/138>`_ +- `Ensure returned numpy arrays are not writeable <../../pull/164>`_ Fixed: diff --git a/softioc/device.py b/softioc/device.py index 56364681..8c133fad 100644 --- a/softioc/device.py +++ b/softioc/device.py @@ -467,7 +467,12 @@ def _value_to_epics(self, value): # common class of bug, at the cost of duplicated code and data, here we # ensure a copy is taken of the value. assert len(value) <= self._nelm, 'Value too long for waveform' - return numpy.copy(value) + + value = numpy.copy(value) + # As we return a reference to the numpy array, ensure it cannot be + # modified under our noses + value.flags.writeable = False + return value def _epics_to_value(self, value): if self._dtype.char == 'S': diff --git a/tests/test_records.py b/tests/test_records.py index 1f30d63b..cb3c2b0e 100644 --- a/tests/test_records.py +++ b/tests/test_records.py @@ -340,6 +340,19 @@ def test_record_wrapper_str(): # If we never receive R it probably means an assert failed select_and_recv(parent_conn, "R") +def test_waveform_values_not_modifiable(): + """Test that arrays returned from waveform records are not modifiable""" + + wi = builder.WaveformIn("WI", [1, 2, 3]) + wo = builder.WaveformOut("WO", [1, 2, 3]) + + with pytest.raises(ValueError): + wi.get()[0] = 5 + + with pytest.raises(ValueError): + wo.get()[0] = 5 + + def validate_fixture_names(params): """Provide nice names for the out_records fixture in TestValidate class""" return params[0].__name__