fix(io): check mremap return value to prevent potential crash#1725
Hidden character warning
fix(io): check mremap return value to prevent potential crash#1725LHT129 wants to merge 1 commit intoantgroup:mainfrom
Conversation
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request enhances the robustness of memory-mapped I/O operations on Linux by introducing critical error checking for Highlights
🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console. Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request correctly addresses a potential crash by adding return value checks for mremap calls on Linux. This prevents assigning MAP_FAILED to the memory pointer, which could lead to segmentation faults. The change is well-implemented and aligns the Linux error handling with the existing macOS implementation. I have one suggestion to improve code maintainability by refactoring the duplicated error handling logic.
| void* new_addr = mremap(this->start_, old_size, new_size, MREMAP_MAYMOVE); | ||
| if (new_addr == MAP_FAILED) { | ||
| throw VsagException(ErrorType::INTERNAL_ERROR, | ||
| fmt::format("mremap failed: {}", strerror(errno))); | ||
| } | ||
| this->start_ = static_cast<uint8_t*>(new_addr); |
There was a problem hiding this comment.
This error handling logic for mremap is duplicated in three places in this file (WriteImpl and twice in ResizeImpl). To improve maintainability and reduce code duplication, consider extracting this logic into a private helper function or a free function in an anonymous namespace.
For example:
namespace {
void* checked_mremap(void* old_address, size_t old_size, size_t new_size, int flags) {
void* new_addr = mremap(old_address, old_size, new_size, flags);
if (new_addr == MAP_FAILED) {
throw VsagException(ErrorType::INTERNAL_ERROR,
fmt::format("mremap failed: {}", strerror(errno)));
}
return new_addr;
}
} // anonymous namespaceThen you could simplify the call sites to:
this->start_ = static_cast<uint8_t*>(checked_mremap(this->start_, old_size, new_size, MREMAP_MAYMOVE));There was a problem hiding this comment.
Pull request overview
Adds Linux-side error handling for mremap in MMapIO to prevent crashes when remapping fails, aligning behavior with the existing macOS path.
Changes:
- Check
mremapreturn values inWriteImplandResizeImpl(grow/shrink) Linux branches - Throw
VsagExceptiononMAP_FAILEDwith an errno-derived message
src/io/mmap_io.cpp
Outdated
| throw VsagException(ErrorType::INTERNAL_ERROR, | ||
| fmt::format("mremap failed: {}", strerror(errno))); |
src/io/mmap_io.cpp
Outdated
| void* new_addr = mremap(this->start_, old_size, new_size, MREMAP_MAYMOVE); | ||
| if (new_addr == MAP_FAILED) { | ||
| throw VsagException(ErrorType::INTERNAL_ERROR, | ||
| fmt::format("mremap failed: {}", strerror(errno))); |
27d4d74 to
4922946
Compare
Review ResponseI've addressed the feedback:
All changes are in commit 4922946. Thanks for the suggestions! |
There was a problem hiding this comment.
Pull request overview
Adds robust Linux error handling for mremap in MMapIO to avoid crashes when remapping fails, aligning behavior with the existing macOS checks.
Changes:
- Add
MAP_FAILEDchecks for Linuxmremapcalls inWriteImplandResizeImpl - Improve error messages for
open,mmap, andmremapto includeerrnodetails viastd::error_code
src/io/mmap_io.cpp
Outdated
| fmt::format("open file {} failed (errno={}): {}", | ||
| this->filepath_, | ||
| errno, | ||
| std::error_code(errno, std::generic_category()).message())); |
src/io/mmap_io.cpp
Outdated
| void* new_addr = mremap(this->start_, old_size, new_size, MREMAP_MAYMOVE); | ||
| if (new_addr == MAP_FAILED) { | ||
| throw VsagException( | ||
| ErrorType::INTERNAL_ERROR, | ||
| fmt::format("mremap(old_size={}, new_size={}) failed (errno={}): {}", | ||
| old_size, | ||
| new_size, | ||
| errno, | ||
| std::error_code(errno, std::generic_category()).message())); |
src/io/mmap_io.cpp
Outdated
| fmt::format("mmap(size={}) failed (errno={}): {}", | ||
| mmap_size, | ||
| errno, | ||
| std::error_code(errno, std::generic_category()).message())); |
| void* new_addr = mremap(this->start_, old_size, new_size, MREMAP_MAYMOVE); | ||
| if (new_addr == MAP_FAILED) { | ||
| throw VsagException( | ||
| ErrorType::INTERNAL_ERROR, | ||
| fmt::format("mremap(old_size={}, new_size={}) failed (errno={}): {}", | ||
| old_size, | ||
| new_size, | ||
| errno, | ||
| std::error_code(errno, std::generic_category()).message())); | ||
| } |
ad11b5b to
83a87eb
Compare
LHT129
left a comment
There was a problem hiding this comment.
@gemini-code-assist 感谢详细的 review feedback。
我已经修复了所有指出的问题:
-
std::system_category(): 将所有 std::generic_category() 替换为 std::system_category(),因为对于系统调用返回的 errno,system_category 是正确的错误类别。
-
立即保存 errno: 在所有系统调用失败后,立即将 errno 保存到局部变量 saved_errno,避免被后续操作覆盖。
-
PR 描述更新: 已更新 PR 描述,明确说明使用 std::system_category() 和立即保存 errno 的设计。
关于错误处理逻辑重复的问题,虽然代码模式相似,但每处调用的上下文和错误信息略有不同(如不同的 old_size/new_size 值),提取为通用函数可能会增加复杂度。当前实现已经清晰且易于理解。
请查看更新后的代码和 PR 描述,如有进一步建议欢迎提出。
There was a problem hiding this comment.
Pull request overview
This PR hardens MMapIO’s Linux mremap paths by checking for MAP_FAILED and surfacing syscall failures via VsagException, aligning behavior with the existing macOS error-handling approach to prevent crashes on remap failure.
Changes:
- Add
mremapreturn-value checks for Linux inWriteImpland both expand/shrink branches ofResizeImpl. - Improve
open()andmmap()failure messages by capturingerrnoimmediately and formatting viastd::error_code(..., std::system_category()). - Add
<system_error>include to support the new error-code formatting.
| this->fd_ = open(filepath_.c_str(), O_CREAT | O_RDWR, 0644); | ||
| if (this->fd_ < 0) { | ||
| throw VsagException(ErrorType::INTERNAL_ERROR, | ||
| fmt::format("open file {} error {}", this->filepath_, strerror(errno))); | ||
| auto saved_errno = errno; | ||
| throw VsagException( | ||
| ErrorType::INTERNAL_ERROR, | ||
| fmt::format("open file {} failed (errno={}): {}", |
There was a problem hiding this comment.
errno is used in this constructor (and in the new mremap checks), but this file does not include <cerrno>/<errno.h>. Relying on transitive includes for errno is non-portable and can break builds on some platforms/toolchains; please include <cerrno> explicitly.
| void* addr = mmap(nullptr, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED, this->fd_, 0); | ||
| if (addr == MAP_FAILED) { | ||
| throw VsagException(ErrorType::INTERNAL_ERROR, | ||
| fmt::format("mmap failed: {}", strerror(errno))); | ||
| auto saved_errno = errno; | ||
| throw VsagException( | ||
| ErrorType::INTERNAL_ERROR, |
There was a problem hiding this comment.
If mmap fails in the constructor, the file descriptor opened earlier is leaked because the constructor throws before ~MMapIO() can run. Consider closing fd_ (and setting it to -1) before throwing, or using an RAII wrapper for the descriptor so it is reliably released on constructor failure paths.
25af136 to
3b4cc24
Compare
- Add #include <cerrno> for explicit errno usage - Extract ThrowMremapError() helper to eliminate duplicated code - Fix fd leak when mmap/ftruncate fails in constructor Addresses review feedback from PR antgroup#1725: - gemini-code-assist: extract mremap error handling to helper function - Copilot: include <cerrno> explicitly, close fd on error paths Signed-off-by: LHT129 <tianlan.lht@antgroup.com> Co-authored-by: Kimi-K2.5 <assistant@example.com>
| close(this->fd_); | ||
| throw VsagException(ErrorType::INTERNAL_ERROR, "ftruncate failed"); |
There was a problem hiding this comment.
The new open()/mmap() error paths include errno and an OS-provided message, but the ftruncate failure still throws a generic "ftruncate failed" without the error code/message. Capture errno before close() and include it (and ideally the target mmap_size) in the exception message using std::error_code(saved_errno, std::system_category()).message() for consistent and actionable diagnostics.
| close(this->fd_); | |
| throw VsagException(ErrorType::INTERNAL_ERROR, "ftruncate failed"); | |
| auto saved_errno = errno; | |
| close(this->fd_); | |
| throw VsagException( | |
| ErrorType::INTERNAL_ERROR, | |
| fmt::format("ftruncate(size={}) failed (errno={}): {}", | |
| mmap_size, | |
| saved_errno, | |
| std::error_code(saved_errno, std::system_category()).message())); |
src/io/mmap_io.cpp
Outdated
| ThrowMremapError(uint64_t old_size, uint64_t new_size) { | ||
| const int saved_errno = errno; | ||
| throw VsagException( | ||
| ErrorType::INTERNAL_ERROR, | ||
| fmt::format("mremap(old_size={}, new_size={}) failed (errno={}): {}", | ||
| old_size, | ||
| new_size, | ||
| saved_errno, | ||
| std::error_code(saved_errno, std::system_category()).message())); |
There was a problem hiding this comment.
ThrowMremapError implicitly relies on global errno. To better match the stated intent of “save errno immediately after syscall failure” and make the helper robust if any code is inserted between the failed syscall and the throw, capture errno at the call site and pass it into ThrowMremapError (e.g., ThrowMremapError(old_size, new_size, saved_errno)). This avoids any accidental errno clobbering from future changes before the helper reads it.
- Add #include <cerrno> for explicit errno usage - Extract ThrowMremapError() helper to eliminate duplicated code - Fix fd leak when mmap/ftruncate fails in constructor Addresses review feedback from PR antgroup#1725: - gemini-code-assist: extract mremap error handling to helper function - Copilot: include <cerrno> explicitly, close fd on error paths Signed-off-by: LHT129 <tianlan.lht@antgroup.com> Co-authored-by: Kimi-K2.5 <assistant@example.com>
ad3323b to
725f883
Compare
| void* new_addr = mremap(this->start_, old_size, new_size, MREMAP_MAYMOVE); | ||
| if (new_addr == MAP_FAILED) { | ||
| throw_mremap_error(old_size, new_size); | ||
| } | ||
| this->start_ = static_cast<uint8_t*>(new_addr); |
There was a problem hiding this comment.
The PR description says errno is saved “immediately after syscall failure”, but for mremap() it’s currently captured inside throw_mremap_error() rather than at the failure site. Even though the call is currently immediate, it’s fragile if any code is added between the failure check and the throw later. Consider saving errno in the caller right after mremap() returns MAP_FAILED, and pass the saved value into throw_mremap_error(...) so the intended invariant is explicit and matches the description.
- Add #include <cerrno> for explicit errno usage - Extract ThrowMremapError() helper to eliminate duplicated code - Fix fd leak when mmap/ftruncate fails in constructor Addresses review feedback from PR antgroup#1725: - gemini-code-assist: extract mremap error handling to helper function - Copilot: include <cerrno> explicitly, close fd on error paths Signed-off-by: LHT129 <tianlan.lht@antgroup.com> Co-authored-by: Kimi-K2.5 <assistant@example.com>
a726e0b to
d255e4a
Compare
Add proper return value check for mremap syscall in MMapIO. Extract error handling into ThrowMremapError helper function. Signed-off-by: LHT129 <tianlan.lht@antgroup.com>
d255e4a to
c880cf0
Compare
Summary
Add return value check for mremap calls in MMapIO on Linux platform to prevent potential segmentation faults when memory remapping fails.
Background
In src/io/mmap_io.cpp, the Linux code path has three mremap calls that do not check the return value. When mremap fails, it returns MAP_FAILED. Directly assigning this to this->start_ causes subsequent memory operations to access invalid addresses, leading to segmentation faults.
The macOS branch already correctly checks for MAP_FAILED and throws an exception. This PR aligns Linux error handling with macOS.
Changes
Implementation Details
Why std::system_category() instead of std::generic_category()?
When constructing std::error_code from errno values, std::system_category() is the correct category for OS error codes (like errno from system calls). std::generic_category() is for portable error codes.
Why save errno immediately?
errno can be overwritten by subsequent function calls (including the error message formatting). We save errno into a local variable immediately after the failing syscall.
Files Changed
Testing
Related Issues
Checklist