Skip to content

[libc] Add shm_open/shm_unlink #84974

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 15 commits into from
Mar 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions libc/config/linux/aarch64/entrypoints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,8 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.sys.mman.mlockall
libc.src.sys.mman.munlockall
libc.src.sys.mman.msync
libc.src.sys.mman.shm_open
libc.src.sys.mman.shm_unlink

# sys/random.h entrypoints
libc.src.sys.random.getrandom
Expand Down
2 changes: 1 addition & 1 deletion libc/config/linux/api.td
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ def SchedAPI : PublicAPI<"sched.h"> {
}

def SysMManAPI : PublicAPI<"sys/mman.h"> {
let Types = ["off_t", "size_t"];
let Types = ["off_t", "size_t", "mode_t"];
}

def SignalAPI : PublicAPI<"signal.h"> {
Expand Down
2 changes: 2 additions & 0 deletions libc/config/linux/riscv/entrypoints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,8 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.sys.mman.mlockall
libc.src.sys.mman.munlockall
libc.src.sys.mman.msync
libc.src.sys.mman.shm_open
libc.src.sys.mman.shm_unlink

# sys/random.h entrypoints
libc.src.sys.random.getrandom
Expand Down
2 changes: 2 additions & 0 deletions libc/config/linux/x86_64/entrypoints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,8 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.sys.mman.mlockall
libc.src.sys.mman.munlockall
libc.src.sys.mman.msync
libc.src.sys.mman.shm_open
libc.src.sys.mman.shm_unlink

# sys/random.h entrypoints
libc.src.sys.random.getrandom
Expand Down
4 changes: 4 additions & 0 deletions libc/docs/dev/undefined_behavior.rst
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,7 @@ Design Decisions
Resizable Tables for hsearch
----------------------------
The POSIX.1 standard does not delineate the behavior consequent to invoking hsearch or hdestroy without prior initialization of the hash table via hcreate. Furthermore, the standard does not specify the outcomes of successive invocations of hsearch absent intervening hdestroy calls. Libraries such as MUSL and Glibc do not apply checks to these scenarios, potentially leading to memory corruption or leakage. Conversely, FreeBSD's libc and Bionic automatically initialize the hash table to a minimal size if it is found uninitialized, and proceeding to destroy the table only if initialization has occurred. This approach also avoids redundant table allocation if an initialized hash table is already present. Given that the hash table starts with a minimal size, resizing becomes necessary to accommodate additional user insertions. LLVM's libc mirrors the approach of FreeBSD's libc and Bionic, owing to its enhanced robustness and user-friendliness. Notably, such resizing behavior itself aligns with POSIX.1 standards, which explicitly permit implementations to modify the capacity of the hash table.

Path without Leading Slashs in shm_open
----------------------------------------
POSIX.1 leaves that when the name of a shared memory object does not begin with a slash, the behavior is implementation defined. In such cases, the shm_open in LLVM libc is implemented to behave as if the name began with a slash.
11 changes: 11 additions & 0 deletions libc/spec/posix.td
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ def POSIX : StandardSpec<"POSIX"> {
[
SizeTType,
OffTType,
ModeTType,
],
[], // Enumerations
[
Expand Down Expand Up @@ -314,6 +315,16 @@ def POSIX : StandardSpec<"POSIX"> {
RetValSpec<IntType>,
[ArgSpec<VoidPtr>, ArgSpec<SizeTType>, ArgSpec<IntType>]
>,
FunctionSpec<
"shm_open",
RetValSpec<IntType>,
[ArgSpec<ConstCharPtr>, ArgSpec<IntType>, ArgSpec<ModeTType>]
>,
FunctionSpec<
"shm_unlink",
RetValSpec<IntType>,
[ArgSpec<ConstCharPtr>]
>,
]
>;

Expand Down
21 changes: 19 additions & 2 deletions libc/src/__support/CPP/string_view.h
Original file line number Diff line number Diff line change
Expand Up @@ -179,21 +179,38 @@ class string_view {
LIBC_INLINE char back() const { return Data[Len - 1]; }

// Finds the first occurence of c in this view, starting at position From.
LIBC_INLINE size_t find_first_of(const char c, size_t From = 0) const {
LIBC_INLINE constexpr size_t find_first_of(const char c,
size_t From = 0) const {
for (size_t Pos = From; Pos < size(); ++Pos)
if ((*this)[Pos] == c)
return Pos;
return npos;
}

// Finds the last occurence of c in this view, ending at position End.
LIBC_INLINE size_t find_last_of(const char c, size_t End = npos) const {
LIBC_INLINE constexpr size_t find_last_of(const char c,
size_t End = npos) const {
End = End >= size() ? size() : End + 1;
for (; End > 0; --End)
if ((*this)[End - 1] == c)
return End - 1;
return npos;
}

// Finds the first character not equal to c in this view, starting at position
// From.
LIBC_INLINE constexpr size_t find_first_not_of(const char c,
size_t From = 0) const {
for (size_t Pos = From; Pos < size(); ++Pos)
if ((*this)[Pos] != c)
return Pos;
return npos;
}

// Check if this view contains the given character.
LIBC_INLINE constexpr bool contains(char c) const {
return find_first_of(c) != npos;
}
};

} // namespace cpp
Expand Down
14 changes: 14 additions & 0 deletions libc/src/sys/mman/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,17 @@ add_entrypoint_object(
DEPENDS
.${LIBC_TARGET_OS}.msync
)

add_entrypoint_object(
shm_open
ALIAS
DEPENDS
.${LIBC_TARGET_OS}.shm_open
)

add_entrypoint_object(
shm_unlink
ALIAS
DEPENDS
.${LIBC_TARGET_OS}.shm_unlink
)
37 changes: 37 additions & 0 deletions libc/src/sys/mman/linux/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -152,3 +152,40 @@ add_entrypoint_object(
libc.src.__support.OSUtil.osutil
libc.src.errno.errno
)

add_header_library(
shm_common
HDRS
shm_common.h
DEPENDS
libc.src.__support.CPP.array
libc.src.__support.CPP.string_view
libc.src.__support.CPP.optional
libc.src.__support.common
libc.src.errno.errno
libc.src.string.memory_utils.inline_memcpy
)

add_entrypoint_object(
shm_open
SRCS
shm_open.cpp
HDRS
../shm_open.h
DEPENDS
libc.src.fcntl.open
libc.include.llvm-libc-macros.fcntl_macros
libc.include.llvm-libc-types.mode_t
.shm_common
)

add_entrypoint_object(
shm_unlink
SRCS
shm_unlink.cpp
HDRS
../shm_unlink.h
DEPENDS
libc.src.unistd.unlink
.shm_common
)
53 changes: 53 additions & 0 deletions libc/src/sys/mman/linux/shm_common.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
//===---------- Shared implementations for shm_open/shm_unlink ------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "src/__support/CPP/array.h"
#include "src/__support/CPP/optional.h"
#include "src/__support/CPP/string_view.h"
#include "src/errno/libc_errno.h"
#include "src/string/memory_utils/inline_memcpy.h"

// TODO: Get PATH_MAX via https://github.com/llvm/llvm-project/issues/85121
#include <linux/limits.h>

namespace LIBC_NAMESPACE {

namespace shm_common {

LIBC_INLINE_VAR constexpr cpp::string_view SHM_PREFIX = "/dev/shm/";
using SHMPath = cpp::array<char, NAME_MAX + SHM_PREFIX.size() + 1>;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider moving this using statement (and definition of SHM_PREFIX) inside of the get_shm_name function. Otherwise it's polluting the LIBC_NAMESPACE namespace in a header.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is a little bit annoying that I actually use the type in the function signature. I surround the shared code in a shm_common namespace instead.


LIBC_INLINE cpp::optional<SHMPath> translate_name(cpp::string_view name) {
// trim leading slashes
size_t offset = name.find_first_not_of('/');
if (offset == cpp::string_view::npos) {
libc_errno = EINVAL;
return cpp::nullopt;
}
name = name.substr(offset);

// check the name
if (name.size() > NAME_MAX) {
libc_errno = ENAMETOOLONG;
return cpp::nullopt;
}
if (name == "." || name == ".." || name.contains('/')) {
libc_errno = EINVAL;
return cpp::nullopt;
}

// prepend the prefix
SHMPath buffer;
inline_memcpy(buffer.data(), SHM_PREFIX.data(), SHM_PREFIX.size());
inline_memcpy(buffer.data() + SHM_PREFIX.size(), name.data(), name.size());
buffer[SHM_PREFIX.size() + name.size()] = '\0';
return buffer;
}
} // namespace shm_common

} // namespace LIBC_NAMESPACE
25 changes: 25 additions & 0 deletions libc/src/sys/mman/linux/shm_open.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//===---------- Linux implementation of the shm_open function -------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "src/sys/mman/shm_open.h"
#include "llvm-libc-macros/fcntl-macros.h"
#include "src/fcntl/open.h"
#include "src/sys/mman/linux/shm_common.h"

namespace LIBC_NAMESPACE {

static constexpr int DEFAULT_OFLAGS = O_NOFOLLOW | O_CLOEXEC | O_NONBLOCK;

LLVM_LIBC_FUNCTION(int, shm_open, (const char *name, int oflags, mode_t mode)) {
using namespace shm_common;
if (cpp::optional<SHMPath> buffer = translate_name(name))
return open(buffer->data(), oflags | DEFAULT_OFLAGS, mode);
return -1;
}

} // namespace LIBC_NAMESPACE
22 changes: 22 additions & 0 deletions libc/src/sys/mman/linux/shm_unlink.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//===---------- Linux implementation of the shm_unlink function -----------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "src/sys/mman/shm_unlink.h"
#include "src/sys/mman/linux/shm_common.h"
#include "src/unistd/unlink.h"

namespace LIBC_NAMESPACE {

LLVM_LIBC_FUNCTION(int, shm_unlink, (const char *name)) {
using namespace shm_common;
if (cpp::optional<SHMPath> buffer = translate_name(name))
return unlink(buffer->data());
return -1;
}

} // namespace LIBC_NAMESPACE
20 changes: 20 additions & 0 deletions libc/src/sys/mman/shm_open.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//===-- Implementation header for shm_open function -------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIBC_SRC_SYS_MMAN_SHM_OPEN_H
#define LLVM_LIBC_SRC_SYS_MMAN_SHM_OPEN_H

#include <llvm-libc-types/mode_t.h>

namespace LIBC_NAMESPACE {

int shm_open(const char *name, int oflag, mode_t mode);

} // namespace LIBC_NAMESPACE

#endif // LLVM_LIBC_SRC_SYS_MMAN_SHM_OPEN_H
18 changes: 18 additions & 0 deletions libc/src/sys/mman/shm_unlink.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//===-- Implementation header for shm_unlink function ------------*- C++-*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIBC_SRC_SYS_MMAN_SHM_UNLINK_H
#define LLVM_LIBC_SRC_SYS_MMAN_SHM_UNLINK_H

namespace LIBC_NAMESPACE {

int shm_unlink(const char *name);

} // namespace LIBC_NAMESPACE

#endif // LLVM_LIBC_SRC_SYS_MMAN_SHM_UNLINK_H
Loading