python accessing freed shared memory object (#1253)

* added a 'isValid' member in shared memory (also updated shm version) with default true, any access to shared memory() checks also for validity. any free will set this to false and then unmap shm. Any access to shm will then check validity in python.

* fixed tests for shm

* added tests in python as well

---------

Co-authored-by: Alice <alice.mazzoleni@psi.ch>
This commit is contained in:
2025-08-05 11:26:49 +02:00
committed by GitHub
parent f714aa22c5
commit f594826e95
11 changed files with 258 additions and 40 deletions

View File

@@ -56,6 +56,7 @@ class CtbConfig {
std::string getSlowADCName(size_t index) const;
std::vector<std::string> getSlowADCNames() const;
static const char *shm_tag();
bool isValid{true}; // false if freed to block access from python or c++ api
};
} // namespace sls

View File

@@ -29,6 +29,8 @@ void freeSharedMemory(const int detectorIndex, const int moduleIndex) {
if (moduleIndex >= 0) {
SharedMemory<sharedModule> moduleShm(detectorIndex, moduleIndex);
if (moduleShm.exists()) {
moduleShm.openSharedMemory(false);
moduleShm()->isValid = false;
moduleShm.removeSharedMemory();
}
return;
@@ -41,18 +43,26 @@ void freeSharedMemory(const int detectorIndex, const int moduleIndex) {
if (detectorShm.exists()) {
detectorShm.openSharedMemory(false);
numDetectors = detectorShm()->totalNumberOfModules;
detectorShm()->isValid = false;
detectorShm.removeSharedMemory();
}
for (int i = 0; i < numDetectors; ++i) {
SharedMemory<sharedModule> moduleShm(detectorIndex, i);
if (moduleShm.exists()) {
moduleShm.openSharedMemory(false);
moduleShm()->isValid = false;
}
moduleShm.removeSharedMemory();
}
// Ctb configuration
SharedMemory<CtbConfig> ctbShm(detectorIndex, -1, CtbConfig::shm_tag());
if (ctbShm.exists())
if (ctbShm.exists()) {
ctbShm.openSharedMemory(false);
ctbShm()->isValid = false;
ctbShm.removeSharedMemory();
}
}
using defs = slsDetectorDefs;

View File

@@ -24,7 +24,7 @@ class detectorData;
class Module;
#define DETECTOR_SHMAPIVERSION 0x190809
#define DETECTOR_SHMVERSION 0x250616
#define DETECTOR_SHMVERSION 0x250729
#define SHORT_STRING_LENGTH 50
/**
@@ -51,6 +51,8 @@ struct sharedDetector {
int totalNumberOfModules;
slsDetectorDefs::detectorType detType;
bool isValid{true}; // false if freed to block access from python or c++ api
/** END OF FIXED PATTERN
* -----------------------------------------------*/

View File

@@ -19,7 +19,7 @@ namespace sls {
class ServerInterface;
#define MODULE_SHMAPIVERSION 0x190726
#define MODULE_SHMVERSION 0x230913
#define MODULE_SHMVERSION 0x250729
/**
* @short structure allocated in shared memory to store Module settings for
@@ -32,6 +32,7 @@ struct sharedModule {
int shmversion;
char hostname[MAX_STR_LENGTH];
slsDetectorDefs::detectorType detType;
bool isValid{true}; // false if freed to block access from python or c++ api
/** END OF FIXED PATTERN -----------------------------------------------*/

View File

@@ -10,6 +10,7 @@
*@short functions basic implemenation of shared memory
*/
#include "sls/TypeTraits.h"
#include "sls/logger.h"
#include "sls/sls_detector_exceptions.h"
@@ -26,11 +27,18 @@
namespace sls {
struct sharedDetector;
#define SHM_DETECTOR_PREFIX "/slsDetectorPackage_detector_"
#define SHM_MODULE_PREFIX "_module_"
#define SHM_ENV_NAME "SLSDETNAME"
template <typename T> class SharedMemory {
static_assert(has_bool_isValid<T>::value,
"SharedMemory requires the struct to have a bool member "
"named 'isValid'");
static constexpr int NAME_MAX_LENGTH = 255;
std::string name;
T *shared_struct{nullptr};
@@ -65,15 +73,21 @@ template <typename T> class SharedMemory {
}
T *operator()() {
if (shared_struct)
return shared_struct;
throw SharedMemoryError(getNoShmAccessMessage());
if (!shared_struct)
throw SharedMemoryError(getNoShmAccessMessage());
if (!shared_struct->isValid) {
throw SharedMemoryError(getInvalidShmMessage());
}
return shared_struct;
}
const T *operator()() const {
if (shared_struct)
return shared_struct;
throw SharedMemoryError(getNoShmAccessMessage());
if (!shared_struct)
throw SharedMemoryError(getNoShmAccessMessage());
if (!shared_struct->isValid) {
throw SharedMemoryError(getInvalidShmMessage());
}
return shared_struct;
}
std::string getName() const { return name; }
@@ -215,10 +229,15 @@ template <typename T> class SharedMemory {
}
}
const char *getNoShmAccessMessage() const {
inline const char *getNoShmAccessMessage() const {
return ("No shared memory to access. Create it first with "
"hostname or config command.");
};
inline const char *getInvalidShmMessage() const {
return ("Shared memory is invalid or freed. Close resources before "
"access.");
};
};
} // namespace sls

View File

@@ -10,7 +10,7 @@
namespace sls {
TEST_CASE("Default construction") {
static_assert(sizeof(CtbConfig) == ((18 + 32 + 64 + 5 + 8) * 20),
static_assert(sizeof(CtbConfig) == ((18 + 32 + 64 + 5 + 8) * 20 + 1),
"Size of CtbConfig does not match");
CtbConfig c;

View File

@@ -5,27 +5,35 @@
#include "catch.hpp"
#include "sls/string_utils.h"
#include <iostream>
namespace sls {
struct Data {
int x;
double y;
char mess[50];
bool isValid{true};
};
void freeShm(const int dindex, const int mIndex) {
SharedMemory<Data> shm(dindex, mIndex);
if (shm.exists()) {
shm.openSharedMemory(false);
shm()->isValid = false;
shm.removeSharedMemory();
}
}
constexpr int shm_id = 10;
TEST_CASE("Create SharedMemory read and write", "[detector]") {
const char *env_p = std::getenv("SLSDETNAME");
std::string env_name = env_p ? ("_" + std::string(env_p)) : "";
SharedMemory<Data> shm(shm_id, -1);
if (shm.exists()) {
shm.removeSharedMemory();
}
shm.createSharedMemory();
const char *env_p = std::getenv("SLSDETNAME");
std::string env_name = env_p ? ("_" + std::string(env_p)) : "";
CHECK(shm.getName() == std::string("/slsDetectorPackage_detector_") +
std::to_string(shm_id) + env_name);
@@ -44,16 +52,19 @@ TEST_CASE("Create SharedMemory read and write", "[detector]") {
}
TEST_CASE("Open existing SharedMemory and read", "[detector]") {
{
SharedMemory<double> shm(shm_id, -1);
SharedMemory<Data> shm(shm_id, -1);
if (shm.exists()) {
shm.removeSharedMemory();
}
shm.createSharedMemory();
*shm() = 5.3;
shm()->x = 3;
shm()->y = 5.9;
}
SharedMemory<double> shm2(shm_id, -1);
SharedMemory<Data> shm2(shm_id, -1);
shm2.openSharedMemory(true);
CHECK(*shm2() == 5.3);
CHECK(shm2()->y == 5.9);
shm2.removeSharedMemory();
}
@@ -61,8 +72,8 @@ TEST_CASE("Open existing SharedMemory and read", "[detector]") {
TEST_CASE("Creating a second shared memory with the same name throws",
"[detector]") {
SharedMemory<double> shm0(shm_id, -1);
SharedMemory<double> shm1(shm_id, -1);
SharedMemory<Data> shm0(shm_id, -1);
SharedMemory<Data> shm1(shm_id, -1);
shm0.createSharedMemory();
CHECK_THROWS(shm1.createSharedMemory());
@@ -120,19 +131,18 @@ TEST_CASE("Create several shared memories", "[detector]") {
std::string env_name = env_p ? ("_" + std::string(env_p)) : "";
constexpr int N = 5;
std::vector<SharedMemory<int>> v;
std::vector<SharedMemory<Data>> v;
v.reserve(N);
for (int i = 0; i != N; ++i) {
std::cout << "i:" << i << std::endl;
v.emplace_back(shm_id + i, -1);
CHECK(v[i].exists() == false);
v[i].createSharedMemory();
*v[i]() = i;
CHECK(*v[i]() == i);
v[i]()->x = i;
CHECK(v[i]()->x == i);
}
for (int i = 0; i != N; ++i) {
CHECK(*v[i]() == i);
CHECK(v[i]()->x == i);
CHECK(v[i].getName() == std::string("/slsDetectorPackage_detector_") +
std::to_string(i + shm_id) + env_name);
}
@@ -147,7 +157,7 @@ TEST_CASE("Create create a shared memory with a tag") {
const char *env_p = std::getenv("SLSDETNAME");
std::string env_name = env_p ? ("_" + std::string(env_p)) : "";
SharedMemory<int> shm(0, -1, "ctbdacs");
SharedMemory<Data> shm(0, -1, "ctbdacs");
REQUIRE(shm.getName() ==
"/slsDetectorPackage_detector_0" + env_name + "_ctbdacs");
}
@@ -162,7 +172,7 @@ TEST_CASE("Create create a shared memory with a tag when SLSDETNAME is set") {
unsetenv(SHM_ENV_NAME);
setenv(SHM_ENV_NAME, "myprefix", 1);
SharedMemory<int> shm(0, -1, "ctbdacs");
SharedMemory<Data> shm(0, -1, "ctbdacs");
REQUIRE(shm.getName() == "/slsDetectorPackage_detector_0_myprefix_ctbdacs");
// Clean up after us
@@ -172,15 +182,14 @@ TEST_CASE("Create create a shared memory with a tag when SLSDETNAME is set") {
setenv(SHM_ENV_NAME, old_slsdetname.c_str(), 1);
}
TEST_CASE("map int64 to int32 throws") {
SharedMemory<int32_t> shm(shm_id, -1);
TEST_CASE("Access to already freed shm object", "[detector]") {
SharedMemory<Data> shm(shm_id, -1);
shm.createSharedMemory();
*shm() = 7;
shm()->x = 10;
SharedMemory<int64_t> shm2(shm_id, -1);
REQUIRE_THROWS(shm2.openSharedMemory(true));
shm.removeSharedMemory();
freeShm(shm_id, -1);
CHECK(shm.exists() == false);
REQUIRE_THROWS(shm()); // trying to access should throw
}
} // namespace sls