Skip to content
Merged
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
134 changes: 100 additions & 34 deletions sherpa-onnx/csrc/file-utils.cc
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,27 @@
#ifdef _WIN32
#include <windows.h>
#else
#include <sys/stat.h>
#include <unistd.h>
#include <limits.h>
Comment thread
XiaoBaiCanDo marked this conversation as resolved.
#include <stdlib.h>
#endif

#include "sherpa-onnx/csrc/macros.h"

namespace sherpa_onnx {
std::wstring ToWideString(const std::string &s);
std::string ToString(const std::wstring &s);
Comment on lines 23 to +26

Copilot AI Mar 5, 2026

Copy link

Choose a reason for hiding this comment

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

ToWideString/ToString are forward-declared here but defined in text-utils.h/.cc. Prefer including the header instead of duplicating declarations so the dependency is explicit and signatures stay in sync.

Suggested change
namespace sherpa_onnx {
std::wstring ToWideString(const std::string &s);
std::string ToString(const std::wstring &s);
#include "sherpa-onnx/csrc/text-utils.h"
namespace sherpa_onnx {

Copilot uses AI. Check for mistakes.

bool FileExists(const std::string &filename) {
return std::ifstream(filename).good();
#ifdef _WIN32
DWORD attributes = GetFileAttributesW(ToWideString(filename).c_str());

return attributes != INVALID_FILE_ATTRIBUTES && !(attributes & FILE_ATTRIBUTE_DIRECTORY);
#else
struct stat file_stat;
return stat(filename.c_str(), &file_stat) == 0 && S_ISREG(file_stat.st_mode);
#endif
}

void AssertFileExists(const std::string &filename) {
Expand All @@ -33,20 +44,70 @@ void AssertFileExists(const std::string &filename) {
}

std::vector<char> ReadFile(const std::string &filename) {
std::ifstream file(filename, std::ios::binary | std::ios::ate);
if (!file.is_open()) {
if (filename.empty()) {
return {};
}

std::streamsize size = file.tellg();
file.seekg(0, std::ios::beg);

std::vector<char> buffer(size);
if (!file.read(buffer.data(), size)) {
try {
#ifdef _WIN32
HANDLE hFile = CreateFileW(
ToWideString(filename).c_str(),
GENERIC_READ,
FILE_SHARE_READ,
nullptr,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
nullptr
);

if (hFile == INVALID_HANDLE_VALUE) {
return {};
}

std::unique_ptr<void, decltype(&CloseHandle)> file_guard(
hFile, CloseHandle);

LARGE_INTEGER file_size;
if (!GetFileSizeEx(hFile, &file_size) || file_size.QuadPart > SIZE_MAX) {
return {};
}

std::vector<char> buffer(static_cast<size_t>(file_size.QuadPart));

DWORD bytes_read = 0;
bool read_success = ::ReadFile(
hFile,
buffer.data(),
static_cast<DWORD>(buffer.size()),
&bytes_read,
nullptr
);
if (!read_success || bytes_read != buffer.size()) {
return {};
}

Comment on lines +76 to +87

Copilot AI Mar 5, 2026

Copy link

Choose a reason for hiding this comment

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

Windows ReadFile casts buffer.size() to DWORD for the ReadFile() call. For files >4GiB this overflows / truncates the requested read size; the function will then fail even though SIZE_MAX is larger. Consider rejecting sizes > DWORD max explicitly or reading in a loop/chunks.

Suggested change
DWORD bytes_read = 0;
if (!::ReadFile(hFile, buffer.data(), static_cast<DWORD>(buffer.size()), &bytes_read, nullptr) ||
bytes_read != buffer.size()) {
return {};
}
size_t total_read = 0;
while (total_read < buffer.size()) {
size_t remaining = buffer.size() - total_read;
DWORD to_read = remaining > static_cast<size_t>(MAXDWORD)
? MAXDWORD
: static_cast<DWORD>(remaining);
DWORD bytes_read = 0;
if (!::ReadFile(hFile, buffer.data() + total_read, to_read, &bytes_read, nullptr)) {
return {};
}
if (bytes_read == 0) {
// Unexpected end of file
return {};
}
total_read += bytes_read;
}

Copilot uses AI. Check for mistakes.
return buffer;
#else
std::ifstream file(filename, std::ios::binary | std::ios::ate);
if (!file.is_open()) {
return {};
}

std::streamsize size = file.tellg();
if (size < 0) {
return {};
}
file.seekg(0, std::ios::beg);

std::vector<char> buffer(static_cast<size_t>(size));
if (!file.read(buffer.data(), size)) {
return {};
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Comment on lines +95 to +103

Copilot AI Mar 5, 2026

Copy link

Choose a reason for hiding this comment

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

In the non-Windows ReadFile path, tellg() can return -1 on failure; constructing std::vector<char> buffer(size) would then attempt a huge allocation due to signed-to-unsigned conversion. Check that size >= 0 (and that the stream is in a good state) before allocating.

Copilot uses AI. Check for mistakes.
}

return buffer;
#endif
} catch (const std::exception&) {
return {};
}

return buffer;
}

#if __ANDROID_API__ >= 9
Expand Down Expand Up @@ -119,33 +180,38 @@ std::string ResolveAbsolutePath(const std::string &path) {
return path;
}

try {
#ifdef _WIN32
// Check if path is already absolute (drive letter or UNC path)
if ((path.size() > 1 && path[1] == ':') ||
(path.size() > 1 && path[0] == '\\' && path[1] == '\\')) {
return path;
}

char buffer[MAX_PATH];
if (GetFullPathNameA(path.c_str(), MAX_PATH, buffer, nullptr)) {
return std::string(buffer);
}

return path; // fallback on failure

std::wstring wide_path = ToWideString(path);
DWORD required_size = GetFullPathNameW(wide_path.c_str(), 0, nullptr, nullptr);
if (required_size == 0) {
return path;
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

std::vector<wchar_t> buffer(required_size);
DWORD actual_size = GetFullPathNameW(
wide_path.c_str(),
required_size,
buffer.data(),
nullptr
);

if (actual_size == 0 || actual_size >= required_size) {
return path;
}

std::wstring resolved_wide(buffer.data(), actual_size);
return ToString(resolved_wide);
#else
// POSIX: absolute paths start with '/'
if (path[0] == '/') {
char resolved_path[PATH_MAX];
if (realpath(path.c_str(), resolved_path) == nullptr) {
return path;
}
return std::string(resolved_path);
#endif
} catch (const std::exception&) {
return path;
}

char buffer[PATH_MAX];
if (realpath(path.c_str(), buffer)) {
return std::string(buffer);
}

return path; // fallback on failure
#endif
}

} // namespace sherpa_onnx