This issue is a result of a Codex global repository scan.
The binary restart helpers call POSIX write() and read() once and only treat -1 as failure. POSIX allows a positive return smaller than the requested byte count. In that case these helpers currently report success even though only part of the restart payload was transferred.
|
bool Restart::write_file2(const std::string& file_name, const void* const ptr, const size_t size, const bool error_quit) const |
|
{ |
|
const int file = open(file_name.c_str(), O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR); |
|
if (-1 == file){ |
|
if (error_quit){ |
|
throw std::runtime_error("can't open restart save file. \nerrno=" + ModuleBase::GlobalFunc::TO_STRING(errno) + ".\n" + std::string(__FILE__) + " line " + std::to_string(__LINE__)); |
|
} else { |
|
return false; |
|
} |
|
} |
|
auto error = write(file, ptr, size); |
|
if (-1 == error) { |
|
if (error_quit) { |
|
throw std::runtime_error("can't write restart save file. \nerrno=" + ModuleBase::GlobalFunc::TO_STRING(errno) + ".\n" + std::string(__FILE__) + " line " + std::to_string(__LINE__)); |
|
} else { |
|
return false; |
|
} |
|
} |
|
close(file); |
|
return true; |
|
bool Restart::read_file2(const std::string& file_name, void* const ptr, const size_t size, const bool error_quit) const |
|
{ |
|
const int file = open(file_name.c_str(), O_RDONLY); |
|
if (-1 == file) { |
|
if (error_quit) { |
|
throw std::runtime_error("can't open restart load file. \nerrno=" + ModuleBase::GlobalFunc::TO_STRING(errno) + ".\n" + std::string(__FILE__) + " line " + std::to_string(__LINE__)); |
|
} else { |
|
return false; |
|
} |
|
} |
|
auto error = read(file, ptr, size); |
|
if (-1 == error) { |
|
if (error_quit) { |
|
throw std::runtime_error("can't read restart load file. \nerrno=" + ModuleBase::GlobalFunc::TO_STRING(errno) + ".\n" + std::string(__FILE__) + " line " + std::to_string(__LINE__)); |
|
} else { |
|
return false; |
|
} |
|
} |
|
close(file); |
|
return true; |
Caller-facing byte count construction:
|
template<typename T> |
|
bool save_disk(const std::string label, const int index, const int size, T* data, const bool error_quit = true) const |
|
{ |
|
return write_file2(folder + label + "_" + ModuleBase::GlobalFunc::TO_STRING(GlobalV::MY_RANK) + "_" |
|
+ ModuleBase::GlobalFunc::TO_STRING(index), |
|
data, |
|
size * sizeof(T), |
Relevant code:
auto error = write(file, ptr, size);
if (-1 == error) { ... }
...
auto error = read(file, ptr, size);
if (-1 == error) { ... }
Impact:
A truncated restart shard can be accepted as successfully loaded, leaving part of the destination buffer stale and making restart behavior non-deterministic.
Suggested fix:
Loop until exactly size bytes are transferred, or return/throw on EOF or a short write. Use RAII for the file descriptor so open descriptors are closed on all error paths.
This issue is a result of a Codex global repository scan.
The binary restart helpers call POSIX
write()andread()once and only treat-1as failure. POSIX allows a positive return smaller than the requested byte count. In that case these helpers currently report success even though only part of the restart payload was transferred.abacus-develop/source/source_io/module_restart/restart.cpp
Lines 36 to 55 in 84ca04b
abacus-develop/source/source_io/module_restart/restart.cpp
Lines 63 to 82 in 84ca04b
Caller-facing byte count construction:
abacus-develop/source/source_io/module_restart/restart.h
Lines 32 to 38 in 84ca04b
Relevant code:
Impact:
A truncated restart shard can be accepted as successfully loaded, leaving part of the destination buffer stale and making restart behavior non-deterministic.
Suggested fix:
Loop until exactly
sizebytes are transferred, or return/throw on EOF or a short write. Use RAII for the file descriptor so open descriptors are closed on all error paths.