mirror of
https://github.com/InstanceBrick/nightcap.git
synced 2026-10-21 08:00:53 +02:00
fix(compat): bound Bionic strerror_r by errno table and gate atoi shim to non-glibc
strerror_r: Bionic's message table covers errno 0..133 except the unassigned 41 and 58. Numbers outside that set now get "Unknown error N" without consulting the host, so the text is the same on glibc and musl and no longer relies on comparing against strerror_r(-1). atoi: glibc's atoi is (int)strtol() like Bionic's, so the host symbol is used there as before. The Bionic shim is registered only on libcs where that is not true (musl). linker_registry_test expects the matching result.
This commit is contained in:
1 parent
fe2f641a9e
commit
6cb3dd00a9
5 files changed
+41
-16
No files matched your search
@@ -11,6 +11,14 @@
|
||||
|
||||
namespace mocktail::compat {
|
||||
|
||||
// glibc's atoi is (int)strtol(), exactly like Bionic's, so the host symbol is
|
||||
// used as-is there. Other libcs (musl) differ on overflow and need the shim.
|
||||
#ifdef __GLIBC__
|
||||
inline constexpr bool kHostAtoiMatchesBionic = true;
|
||||
#else
|
||||
inline constexpr bool kHostAtoiMatchesBionic = false;
|
||||
#endif
|
||||
|
||||
// Android uses size_t fields here; glibc uses int and musl has no equivalent.
|
||||
// An all-zero fallback means unknown, not zero usage.
|
||||
struct BionicMallinfoSnapshot {
|
||||
|
||||
@@ -150,6 +150,15 @@ Result ParseInHostCLocale(Parser parser) noexcept {
|
||||
return result;
|
||||
}
|
||||
|
||||
// Highest errno in Bionic's message table (EHWPOISON). Numbers 41 and 58 are
|
||||
// unassigned in the generic Linux errno list, so Bionic has no text for them.
|
||||
constexpr int kBionicMaxErrno = 133;
|
||||
|
||||
constexpr bool HasBionicErrnoMessage(int error_number) noexcept {
|
||||
return error_number >= 0 && error_number <= kBionicMaxErrno &&
|
||||
error_number != 41 && error_number != 58;
|
||||
}
|
||||
|
||||
template <typename Result>
|
||||
const char* HostStrErrorResult(Result result, char* buffer) noexcept {
|
||||
if constexpr (std::is_integral_v<Result>) {
|
||||
@@ -318,18 +327,19 @@ int BionicStrError(int error_number, char* buffer,
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Bionic's table ends at EHWPOISON. Unknown numbers get the same text on
|
||||
// every host instead of whatever the host libc prints (musl has no
|
||||
// "Unknown error N" form).
|
||||
std::array<char, 256> host_buffer{};
|
||||
auto host_result =
|
||||
::strerror_r(error_number, host_buffer.data(), host_buffer.size());
|
||||
const char* message = HostStrErrorResult(host_result, host_buffer.data());
|
||||
const char* message = nullptr;
|
||||
if (HasBionicErrnoMessage(error_number)) {
|
||||
auto host_result =
|
||||
::strerror_r(error_number, host_buffer.data(), host_buffer.size());
|
||||
message = HostStrErrorResult(host_result, host_buffer.data());
|
||||
}
|
||||
|
||||
std::array<char, 256> unknown_buffer{};
|
||||
const char* unknown_message = HostStrErrorResult(
|
||||
::strerror_r(-1, unknown_buffer.data(), unknown_buffer.size()),
|
||||
unknown_buffer.data());
|
||||
if (message == nullptr ||
|
||||
(error_number != 0 && unknown_message != nullptr &&
|
||||
std::strcmp(message, unknown_message) == 0)) {
|
||||
std::array<char, 64> unknown_buffer{};
|
||||
if (message == nullptr) {
|
||||
std::snprintf(unknown_buffer.data(), unknown_buffer.size(),
|
||||
"Unknown error %d", error_number);
|
||||
message = unknown_buffer.data();
|
||||
|
||||
@@ -134,7 +134,8 @@ bool IsBionicLibcOnlySymbol(std::string_view symbol) {
|
||||
}
|
||||
return symbol == "__cmsg_nxthdr" || symbol == "__cxa_thread_atexit_impl" ||
|
||||
symbol == "__readlink_chk" || symbol == "__register_atfork" ||
|
||||
symbol == "arc4random_buf" || symbol == "atoi" || symbol == "geteuid" ||
|
||||
symbol == "arc4random_buf" || symbol == "geteuid" ||
|
||||
(!mocktail::compat::kHostAtoiMatchesBionic && symbol == "atoi") ||
|
||||
symbol == "getuid" || symbol == "lseek64" ||
|
||||
symbol == "mallinfo" || symbol == "pread64" || symbol == "pwrite64" ||
|
||||
symbol == "sigaction" || symbol == "strerror_r" ||
|
||||
@@ -384,8 +385,10 @@ void RegisterBionicHostLibcRuntimeForLibc() {
|
||||
RegisterSyntheticSymbol("libc.so", "arc4random_buf",
|
||||
reinterpret_cast<void*>(
|
||||
mocktail_bionic_arc4random_buf));
|
||||
RegisterSyntheticSymbol("libc.so", "atoi",
|
||||
reinterpret_cast<void*>(mocktail_bionic_atoi));
|
||||
if (!mocktail::compat::kHostAtoiMatchesBionic) {
|
||||
RegisterSyntheticSymbol("libc.so", "atoi",
|
||||
reinterpret_cast<void*>(mocktail_bionic_atoi));
|
||||
}
|
||||
RegisterSyntheticSymbol("libc.so", "mallinfo",
|
||||
reinterpret_cast<void*>(mocktail_bionic_mallinfo));
|
||||
RegisterSyntheticSymbol("libc.so", "sysinfo",
|
||||
|
||||
@@ -234,7 +234,7 @@ TEST(BionicHostLibcRuntimeTest, UsesBionicPosixStrErrorContract) {
|
||||
EXPECT_STREQ(buffer.data(), std::strerror(0));
|
||||
EXPECT_EQ(errno, EDOM);
|
||||
|
||||
for (const int error_number : {-1, 4567, INT_MIN, INT_MAX}) {
|
||||
for (const int error_number : {-1, 41, 58, 134, 4567, INT_MIN, INT_MAX}) {
|
||||
errno = EDOM;
|
||||
ASSERT_EQ(mocktail_bionic_strerror_r(error_number, buffer.data(),
|
||||
buffer.size()), 0);
|
||||
|
||||
@@ -130,8 +130,12 @@ TEST(LinkerRegistryTest, KeepsHostIndependentBionicAbiOwnedByLibc) {
|
||||
reinterpret_cast<void *>(mocktail___readlink_chk));
|
||||
EXPECT_EQ(symbols.at("arc4random_buf"),
|
||||
reinterpret_cast<void *>(mocktail_bionic_arc4random_buf));
|
||||
EXPECT_EQ(symbols.at("atoi"),
|
||||
reinterpret_cast<void *>(mocktail_bionic_atoi));
|
||||
if (mocktail::compat::kHostAtoiMatchesBionic) {
|
||||
EXPECT_EQ(symbols.count("atoi"), 0u);
|
||||
} else {
|
||||
EXPECT_EQ(symbols.at("atoi"),
|
||||
reinterpret_cast<void *>(mocktail_bionic_atoi));
|
||||
}
|
||||
EXPECT_EQ(symbols.at("mallinfo"),
|
||||
reinterpret_cast<void *>(mocktail_bionic_mallinfo));
|
||||
EXPECT_EQ(symbols.at("sysinfo"),
|
||||
|
||||
Reference in new issue
Block a user