From 8372a1c038bec3b9b1c4926f498a51b69e217fa5 Mon Sep 17 00:00:00 2001 From: Sahil Lenka Date: Fri, 15 May 2026 23:17:58 +0530 Subject: [PATCH 1/6] Fix SHM truncation handling --- concore.hpp | 28 ++++++++--- tests/test_shm_abort.py | 106 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 126 insertions(+), 8 deletions(-) create mode 100644 tests/test_shm_abort.py diff --git a/concore.hpp b/concore.hpp index e3fb5e1..e6d4e68 100644 --- a/concore.hpp +++ b/concore.hpp @@ -40,6 +40,10 @@ class Concore{ string inpath = "./in"; string outpath = "./out"; + // Shared memory segment size in bytes. + // Increase this constant if your payloads exceed 4096 bytes. + // All nodes in a study must be compiled with the same SHM_SIZE. + // Payloads >= SHM_SIZE throw std::runtime_error (no silent truncation). static constexpr size_t SHM_SIZE = 4096; int shmId_create = -1; @@ -683,9 +687,13 @@ class Concore{ outfile<= SHM_SIZE) { - std::cerr << "ERROR: write_SM payload (" << result.size() - << " bytes) exceeds " << SHM_SIZE - 1 - << "-byte shared memory limit. Data truncated!" << std::endl; + throw std::runtime_error( + "concore SHM write failed: payload (" + + std::to_string(result.size()) + + " bytes) exceeds SHM_SIZE (" + + std::to_string(SHM_SIZE) + + "). Aborting. No data written. Increase SHM_SIZE in concore.hpp." + ); } std::strncpy(sharedData_create, result.c_str(), SHM_SIZE - 1); sharedData_create[SHM_SIZE - 1] = '\0'; @@ -711,15 +719,19 @@ class Concore{ void write_SM(int port, string name, string val, int delta=0){ chrono::milliseconds timespan((int)(2000*delay)); this_thread::sleep_for(timespan); + if (val.size() >= SHM_SIZE) { + throw std::runtime_error( + "concore SHM write failed: payload (" + + std::to_string(val.size()) + + " bytes) exceeds SHM_SIZE (" + + std::to_string(SHM_SIZE) + + "). Aborting. No data written. Increase SHM_SIZE in concore.hpp." + ); + } try { if(shmId_create != -1){ if (sharedData_create == nullptr) throw 506; - if (val.size() >= SHM_SIZE) { - std::cerr << "ERROR: write_SM payload (" << val.size() - << " bytes) exceeds " << SHM_SIZE - 1 - << "-byte shared memory limit. Data truncated!" << std::endl; - } std::strncpy(sharedData_create, val.c_str(), SHM_SIZE - 1); sharedData_create[SHM_SIZE - 1] = '\0'; } diff --git a/tests/test_shm_abort.py b/tests/test_shm_abort.py new file mode 100644 index 0000000..b6a0eb6 --- /dev/null +++ b/tests/test_shm_abort.py @@ -0,0 +1,106 @@ +import shutil +import subprocess +import sys +import tempfile +import textwrap +from pathlib import Path + +import pytest + + +REPO_ROOT = Path(__file__).resolve().parent.parent + +pytestmark = pytest.mark.skipif( + shutil.which("g++") is None, + reason="g++ not available", +) + + +@pytest.fixture(autouse=True) +def _skip_windows(): + if sys.platform == "win32": + pytest.skip("SHM requires POSIX") + + +def _compile_and_run(payload_size): + with tempfile.TemporaryDirectory(prefix="concore_shm_test_") as temp_dir: + temp_path = Path(temp_dir) + (temp_path / "concore.oport").write_text('{"1": "1"}', encoding="utf-8") + + source_file = temp_path / "shm_abort_test.cpp" + binary_file = temp_path / "shm_abort_test" + source_file.write_text( + textwrap.dedent( + f''' + #include "concore.hpp" + #include + #include + + int main() {{ + try {{ + Concore concore; + concore.delay = 0; + concore.simtime = 0; + std::string payload({payload_size}, 'a'); + concore.write(1, "payload", payload); + return 0; + }} catch (const std::exception& error) {{ + std::cerr << error.what() << std::endl; + return 1; + }} + }} + ''' + ).lstrip(), + encoding="utf-8", + ) + + compile_result = subprocess.run( + [ + "g++", + "-std=c++17", + "-I", + str(REPO_ROOT), + "-o", + str(binary_file), + str(source_file), + ], + capture_output=True, + text=True, + timeout=60, + cwd=temp_path, + ) + if compile_result.returncode != 0: + pytest.fail(f"g++ compile failed:\n{compile_result.stderr}") + + return subprocess.run( + [str(binary_file)], + capture_output=True, + text=True, + timeout=10, + cwd=temp_path, + ) + + +def test_oversized_payload_throws(): + result = _compile_and_run(5000) + assert result.returncode != 0 + assert "Aborting" in result.stderr + assert "truncated" not in result.stderr.lower() + + +def test_within_limit_succeeds(): + result = _compile_and_run(100) + assert result.returncode == 0 + assert result.stderr == "" + + +def test_exactly_at_limit_throws(): + result = _compile_and_run(4096) + assert result.returncode != 0 + assert "Aborting" in result.stderr + + +def test_one_under_limit_succeeds(): + result = _compile_and_run(4095) + assert result.returncode == 0 + assert result.stderr == "" From 835ca713b688a8b37162f59ec47d4a763d78dfda Mon Sep 17 00:00:00 2001 From: Sahil Lenka Date: Fri, 15 May 2026 23:28:51 +0530 Subject: [PATCH 2/6] Remove SHM comment block per request --- concore.hpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/concore.hpp b/concore.hpp index e6d4e68..907e028 100644 --- a/concore.hpp +++ b/concore.hpp @@ -40,10 +40,6 @@ class Concore{ string inpath = "./in"; string outpath = "./out"; - // Shared memory segment size in bytes. - // Increase this constant if your payloads exceed 4096 bytes. - // All nodes in a study must be compiled with the same SHM_SIZE. - // Payloads >= SHM_SIZE throw std::runtime_error (no silent truncation). static constexpr size_t SHM_SIZE = 4096; int shmId_create = -1; From b3fcd65dd18b21a3b8b58bf2dd75a1fdbef34248 Mon Sep 17 00:00:00 2001 From: Sahil Lenka Date: Fri, 15 May 2026 23:28:52 +0530 Subject: [PATCH 3/6] Remove SHM comment block per request From b67fd7b96196d3f4382488240bd8ac284b0e5e19 Mon Sep 17 00:00:00 2001 From: Sahil Lenka Date: Fri, 15 May 2026 23:39:32 +0530 Subject: [PATCH 4/6] Fix lint: format test_shm_abort.py and keep concore.hpp exception behavior --- concore.hpp | 17 +++++++++++++---- tests/test_shm_abort.py | 4 ++-- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/concore.hpp b/concore.hpp index 907e028..ac0901d 100644 --- a/concore.hpp +++ b/concore.hpp @@ -632,8 +632,14 @@ class Concore{ } } - catch(...){ - cout<<"skipping +"< #include @@ -49,7 +49,7 @@ def _compile_and_run(payload_size): return 1; }} }} - ''' + """ ).lstrip(), encoding="utf-8", ) From 3911f3e23dc6f774f30739b81db476f16cde6d85 Mon Sep 17 00:00:00 2001 From: Sahil Lenka Date: Mon, 18 May 2026 01:07:14 +0530 Subject: [PATCH 5/6] ensure SHM write exceptions are logged and rethrown --- concore.hpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/concore.hpp b/concore.hpp index ac0901d..5b8d549 100644 --- a/concore.hpp +++ b/concore.hpp @@ -709,8 +709,11 @@ class Concore{ } } - catch(...){ - cout<<"skipping +"< Date: Mon, 18 May 2026 01:26:05 +0530 Subject: [PATCH 6/6] test: verify SHM path in SHM abort regression --- tests/test_shm_abort.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/tests/test_shm_abort.py b/tests/test_shm_abort.py index 1f19ae1..68e385f 100644 --- a/tests/test_shm_abort.py +++ b/tests/test_shm_abort.py @@ -34,15 +34,21 @@ def _compile_and_run(payload_size): f""" #include "concore.hpp" #include + #include #include int main() {{ try {{ Concore concore; + std::filesystem::create_directories("out/1"); concore.delay = 0; concore.simtime = 0; std::string payload({payload_size}, 'a'); concore.write(1, "payload", payload); + if (std::filesystem::exists("out/1/payload")) {{ + std::cerr << "write used the file path instead of shared memory" << std::endl; + return 2; + }} return 0; }} catch (const std::exception& error) {{ std::cerr << error.what() << std::endl; @@ -91,7 +97,8 @@ def test_oversized_payload_throws(): def test_within_limit_succeeds(): result = _compile_and_run(100) assert result.returncode == 0 - assert result.stderr == "" + assert "Aborting" not in result.stderr + assert "write used the file path instead of shared memory" not in result.stderr def test_exactly_at_limit_throws(): @@ -103,4 +110,5 @@ def test_exactly_at_limit_throws(): def test_one_under_limit_succeeds(): result = _compile_and_run(4095) assert result.returncode == 0 - assert result.stderr == "" + assert "Aborting" not in result.stderr + assert "write used the file path instead of shared memory" not in result.stderr