Skip to content

feat: implement preserve_fds support and fix file descriptor handling#114

Merged
ComixHe merged 1 commit into
OpenAtom-Linyaps:masterfrom
ComixHe:master
Sep 1, 2025
Merged

feat: implement preserve_fds support and fix file descriptor handling#114
ComixHe merged 1 commit into
OpenAtom-Linyaps:masterfrom
ComixHe:master

Conversation

@ComixHe

@ComixHe ComixHe commented Sep 1, 2025

Copy link
Copy Markdown
Collaborator
  • Add --preserve-fds command line option for runtime
  • Refactor container creation with unified options structure
  • Improve file_descriptor class API

- Add --preserve-fds command line option for runtime
- Refactor container creation with unified options structure
- Improve file_descriptor class API

Signed-off-by: ComixHe <ComixHe1895@outlook.com>
@deepsource-io

deepsource-io Bot commented Sep 1, 2025

Copy link
Copy Markdown

Here's the code health analysis summary for commits b1c7fa1..c9c71a6. View details on DeepSource ↗.

Analysis Summary

AnalyzerStatusSummaryLink
DeepSource C & C++ LogoC & C++❌ Failure
❗ 5 occurences introduced
🎯 1 occurence resolved
View Check ↗
DeepSource Shell LogoShell✅ SuccessView Check ↗
DeepSource Secrets LogoSecrets✅ SuccessView Check ↗
DeepSource Test coverage LogoTest coverage⚠️ Artifact not reportedTimed out: Artifact was never reportedView Check ↗

💡 If you’re a repository administrator, you can configure the quality gates from the settings.

@ComixHe
ComixHe merged commit 24a6a99 into OpenAtom-Linyaps:master Sep 1, 2025
15 of 17 checks passed
Comment on lines 61 to 63
cmd_run->add_option("-b,--bundle", run_opt.bundle, "Path to the OCI bundle")->default_val(".");
cmd_run->add_option("-f,--config", run_opt.config, "Override the configuration file to use")
->default_val("config.json");

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Security Concern: Default Bundle Path

The default value for the bundle path is set to the current directory (.). This could pose a security risk if the directory contains sensitive files or is not the intended directory for OCI bundles. It is recommended to either:

  • Set a more secure and explicit default path that is less likely to contain sensitive or unrelated files.
  • Implement validation to ensure the provided path is safe and correct, possibly rejecting paths that do not meet specific criteria.

Comment on lines 61 to 63
cmd_run->add_option("-b,--bundle", run_opt.bundle, "Path to the OCI bundle")->default_val(".");
cmd_run->add_option("-f,--config", run_opt.config, "Override the configuration file to use")
->default_val("config.json");

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Maintainability Issue: Hardcoded Default Values

The default values for the bundle path and configuration file are hardcoded ('.' and 'config.json' respectively). This approach lacks flexibility and might not suit all deployment environments or use cases. Consider allowing these defaults to be configurable through environment variables or a configuration file, enhancing the adaptability and maintainability of the application.

Comment on lines 62 to +65
std::string ID;
std::string bundle;
std::string config;
uint preserve_fds;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The members ID, bundle, config, and preserve_fds in the run_options struct are not initialized in the constructor, which can lead to undefined behavior if they are accessed before being set. Recommendation: Initialize all members within the constructor to ensure they have valid values.

Example:

run_options(global_options &global) : global_(global), ID(""), bundle(""), config(""), preserve_fds(0) {}

std::string ID;
std::string bundle;
std::string config;
uint preserve_fds;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The preserve_fds member uses uint, which is not a standard type in C++. This can lead to portability issues across different compilers and platforms. Recommendation: Use unsigned int or another standard C++ type to ensure compatibility.

Example:

unsigned int preserve_fds;

Comment on lines 15 to 23
runtime_t runtime(std::move(dir));
runtime_t::create_container_options_t create_container_options;
create_container_options.bundle = options.bundle;
create_container_options.config = options.config;
create_container_options.ID = options.ID;
create_container_options.manager = options.global_.get().manager;
const create_container_options_t create_container_options{ options.global_.get().manager,
options.preserve_fds,
options.ID,
options.bundle,
options.config };

auto container = runtime.create_container(create_container_options);

return container.run(container.get_config().process);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Error Handling and Exception Safety

The code lacks explicit error handling for operations that could potentially fail, such as the construction of runtime_t and create_container. Failure in these operations could lead to unhandled exceptions or undefined behaviors.

Recommendation:

  • Implement try-catch blocks around the operations that could throw exceptions.
  • Check the validity of the container object before calling run on it to prevent potential crashes if create_container fails.

Comment thread src/linyaps_box/runtime.h
cgroup_manager_t manager;
};

auto create_container(const create_container_options_t &options) -> container;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Returning container by value in create_container function might cause performance inefficiencies if container is a large or complex object. If the design allows, returning a smart pointer or a reference could be more efficient, especially if object ownership needs to be shared or transferred.

Suggested Change:

auto create_container(const create_container_options_t &options) -> std::unique_ptr<container>;

Comment on lines 48 to 49
*this = std::move(other);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Using the move assignment operator within the move constructor is unconventional. Typically, the move constructor should directly initialize its members rather than delegating to the move assignment operator. This can improve performance by eliminating unnecessary operations:

file_descriptor(file_descriptor&& other) noexcept : fd_(other.fd_) {
    other.fd_ = -1;
}

This change directly sets fd_ and marks the other's file descriptor as invalid, which is more straightforward and efficient.

Comment on lines +56 to +59
if (::close(ret) < 0) {
auto msg{ "failed to close file descriptor " + std::to_string(ret) + ": "
+ ::strerror(errno) };
throw file_descriptor_invalid_exception(msg);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The release method attempts to close a file descriptor without checking if it was valid (non-negative). This could lead to unnecessary system call errors if the descriptor is invalid. It's recommended to add a check before attempting to close the descriptor:

if (ret >= 0 && ::close(ret) < 0) {
    auto msg = "failed to close file descriptor " + std::to_string(ret) + ": " + ::strerror(errno);
    throw file_descriptor_invalid_exception(msg);
}

This ensures that close is only called with valid descriptors, preventing misleading errors.


file_descriptor(file_descriptor &&other) noexcept;

auto operator=(file_descriptor &&other) noexcept -> file_descriptor &;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The implementation details of the move assignment operator (operator=(file_descriptor &&other) noexcept) are not visible here. It's crucial to ensure that this operator handles self-assignment gracefully and manages the resources (file descriptors) correctly to prevent resource leaks or double deletion issues. Recommended Solution: Implement the move assignment operator to first check for self-assignment, release any existing resources, and then transfer ownership of the resources from the source object.

auto release() && noexcept -> int;
auto release() -> void;

[[nodiscard]] auto duplicate() const -> file_descriptor;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The duplicate method is expected to handle system calls that may fail, such as dup or dup2. It is important to ensure that this method handles such failures by throwing appropriate exceptions or returning an error code. This is crucial for robust error handling and to prevent the application from operating on an invalid file descriptor. Recommended Solution: Implement error handling in the duplicate method to check the return value of the system call and throw an exception or handle the error if the duplication fails.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant