Skip to content

Commit 70dab96

Browse files
committed
Add test to ensure correct masking
1 parent ffd9b3a commit 70dab96

2 files changed

Lines changed: 114 additions & 0 deletions

File tree

ecal/tests/cpp/event_test/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ find_package(GTest REQUIRED)
2323

2424
set(event_test_src
2525
src/event_test.cpp
26+
$<$<BOOL:${UNIX}>:src/shm_region_test.cpp>
2627
)
2728

2829
ecal_add_gtest(${PROJECT_NAME} ${event_test_src})
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
/* ========================= eCAL LICENSE =================================
2+
*
3+
* Copyright (C) 2016 - 2025 Continental Corporation
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*
17+
* ========================= eCAL LICENSE =================================
18+
*/
19+
20+
#include "io/shm/linux/posix_shm_region.h"
21+
22+
#include <gtest/gtest.h>
23+
#include <thread>
24+
25+
#include <sys/stat.h>
26+
#include <sys/types.h>
27+
28+
#include <ecal_utils/barrier.h>
29+
30+
// This test ensures that all SHM files are created with correct file permissions
31+
// and concurrent creation of files do not lead to incorrect file permissons
32+
TEST(core_cpp_internal, shm_region_umask_test)
33+
{
34+
constexpr int number_of_threads = 100;
35+
constexpr mode_t expected_permissions = 0666;
36+
37+
Barrier barrier(number_of_threads);
38+
39+
auto initializer = [](void* /*mapped_addr*/) { return true; };
40+
41+
std::vector<std::string> shm_names;
42+
shm_names.reserve(number_of_threads);
43+
44+
for (int i = 0; i < number_of_threads; ++i)
45+
shm_names.emplace_back("shm_region_umask_test_" + std::to_string(i));
46+
47+
std::vector<std::optional<eCAL::posix::ShmRegion>> regions(number_of_threads);
48+
std::vector<std::thread> threads;
49+
threads.reserve(number_of_threads);
50+
51+
// Restrictive umask on purpose: the implementation under test should still
52+
// create the shm objects with 0666 permissions.
53+
const mode_t old_umask = ::umask(0077);
54+
55+
for (int i = 0; i < number_of_threads; ++i)
56+
{
57+
threads.emplace_back([&, i]()
58+
{
59+
barrier.wait();
60+
61+
regions[i].emplace(
62+
eCAL::posix::open_or_create_mapped_region(
63+
shm_names[i],
64+
100,
65+
initializer
66+
)
67+
);
68+
});
69+
}
70+
71+
for (auto& t : threads)
72+
t.join();
73+
74+
::umask(old_umask);
75+
76+
auto to_octal_string = [](mode_t mode)
77+
{
78+
std::ostringstream oss;
79+
oss << '0' << std::oct << mode;
80+
return oss.str();
81+
};
82+
83+
for (int i = 0; i < number_of_threads; ++i)
84+
{
85+
ASSERT_TRUE(regions[i].has_value()) << "Region creation failed for " << shm_names[i];
86+
87+
// Adjust this path if your implementation uses a leading slash internally
88+
// or another backing location.
89+
const std::string shm_path = "/dev/shm/" + shm_names[i];
90+
91+
struct stat st {};
92+
ASSERT_EQ(::stat(shm_path.c_str(), &st), 0)
93+
<< "stat() failed for " << shm_path;
94+
95+
const mode_t actual_permissions = (st.st_mode & 0777);
96+
EXPECT_EQ(actual_permissions, expected_permissions)
97+
<< "Wrong permissions for " << shm_path
98+
<< ", expected " << to_octal_string(expected_permissions)
99+
<< ", got " << to_octal_string(actual_permissions);
100+
}
101+
102+
// Cleanup from main thread, as requested.
103+
for (int i = 0; i < number_of_threads; ++i)
104+
{
105+
ASSERT_TRUE(regions[i].has_value());
106+
107+
eCAL::posix::close_region(*regions[i]);
108+
109+
// If your API provides only a name-based unlink, replace this with:
110+
// eCAL::posix::unlink_region(shm_names[i]);
111+
eCAL::posix::unlink_region(*regions[i]);
112+
}
113+
}

0 commit comments

Comments
 (0)