// Try to create the overflow table ourselves.
FdTableOverflow* local_overflow = atomic_load(&overflow); if (__predict_false(!local_overflow)) { struct rlimit rlim = { .rlim_max = 32768 };
getrlimit(RLIMIT_NOFILE, &rlim);
rlim_t max = rlim.rlim_max;
if (max == RLIM_INFINITY) { // This isn't actually possible (the kernel has a hard limit), but just // in case...
max = 32768;
}
if (idx > max) { // This can happen if an fd is created and then the rlimit is lowered. // In this case, just return nullptr and ignore the fd. return nullptr;
}
if (atomic_compare_exchange_strong(&overflow, &local_overflow, new_overflow)) {
local_overflow = new_overflow;
} else { // Someone beat us to it. Deallocate and use theirs.
munmap(allocation, aligned_size);
}
}
uint64_t result = static_cast<uint64_t>(type) << 56;
uint64_t mask = (static_cast<uint64_t>(1) << 56) - 1;
result |= tag & mask; return result;
}
constchar* android_fdsan_get_tag_type(uint64_t tag) {
uint64_t type = tag >> 56; switch (type) { case ANDROID_FDSAN_OWNER_TYPE_FILE: return"FILE*"; case ANDROID_FDSAN_OWNER_TYPE_DIR: return"DIR*"; case ANDROID_FDSAN_OWNER_TYPE_UNIQUE_FD: return"unique_fd"; case ANDROID_FDSAN_OWNER_TYPE_FILEINPUTSTREAM: return"FileInputStream"; case ANDROID_FDSAN_OWNER_TYPE_FILEOUTPUTSTREAM: return"FileOutputStream"; case ANDROID_FDSAN_OWNER_TYPE_RANDOMACCESSFILE: return"RandomAccessFile"; case ANDROID_FDSAN_OWNER_TYPE_PARCELFILEDESCRIPTOR: return"ParcelFileDescriptor"; case ANDROID_FDSAN_OWNER_TYPE_SQLITE: return"sqlite"; case ANDROID_FDSAN_OWNER_TYPE_ART_FDFILE: return"ART FdFile"; case ANDROID_FDSAN_OWNER_TYPE_DATAGRAMSOCKETIMPL: return"DatagramSocketImpl"; case ANDROID_FDSAN_OWNER_TYPE_SOCKETIMPL: return"SocketImpl"; case ANDROID_FDSAN_OWNER_TYPE_ZIPARCHIVE: return"ZipArchive"; case ANDROID_FDSAN_OWNER_TYPE_NATIVE_HANDLE: return"native_handle_t"; case ANDROID_FDSAN_OWNER_TYPE_PARCEL: return"Parcel";
case ANDROID_FDSAN_OWNER_TYPE_GENERIC_00: default: return"native object of unknown type";
case ANDROID_FDSAN_OWNER_TYPE_GENERIC_FF: // If bits 48 to 56 are set, this is a sign-extended generic native pointer
uint64_t high_bits = tag >> 48; if (high_bits == (1 << 16) - 1) { return"native object of unknown type";
}
return"Java object of unknown type";
}
}
uint64_t android_fdsan_get_tag_value(uint64_t tag) { // Lop off the most significant byte and sign extend. returnstatic_cast<uint64_t>(static_cast<int64_t>(tag << 8) >> 8);
}
int android_fdsan_close_with_tag(int fd, uint64_t expected_tag) { if (__get_thread()->is_vforked()) { return __close(fd);
}
uint64_t tag = expected_tag; if (!atomic_compare_exchange_strong(&fde->close_tag, &tag, 0)) { constchar* expected_type = android_fdsan_get_tag_type(expected_tag);
uint64_t expected_owner = android_fdsan_get_tag_value(expected_tag); constchar* actual_type = android_fdsan_get_tag_type(tag);
uint64_t actual_owner = android_fdsan_get_tag_value(tag); if (expected_tag && tag) {
fdsan_error( "attempted to close file descriptor %d, " "expected to be owned by %s 0x%" PRIx64 ", actually owned by %s 0x%" PRIx64,
fd, expected_type, expected_owner, actual_type, actual_owner);
} elseif (expected_tag && !tag) {
fdsan_error( "attempted to close file descriptor %d, " "expected to be owned by %s 0x%" PRIx64 ", actually unowned",
fd, expected_type, expected_owner);
} elseif (!expected_tag && tag) {
fdsan_error( "attempted to close file descriptor %d, " "expected to be unowned, actually owned by %s 0x%" PRIx64,
fd, actual_type, actual_owner);
} elseif (!expected_tag && !tag) { // This should never happen: our CAS failed, but expected == actual?
async_safe_fatal("fdsan atomic_compare_exchange_strong failed unexpectedly while closing");
}
}
int rc = __close(fd); // If we were expecting to close with a tag, abort on EBADF. if (expected_tag && rc == -1 && errno == EBADF) {
fdsan_error("double-close of file descriptor %d detected", fd);
} return rc;
}
FdEntry* fde = GetFdEntry(fd); if (!fde) { return;
}
uint64_t tag = expected_tag; if (!atomic_compare_exchange_strong(&fde->close_tag, &tag, new_tag)) { if (expected_tag && tag) {
fdsan_error( "failed to exchange ownership of file descriptor: fd %d is " "owned by %s 0x%" PRIx64 ", was expected to be owned by %s 0x%" PRIx64,
fd, android_fdsan_get_tag_type(tag), android_fdsan_get_tag_value(tag),
android_fdsan_get_tag_type(expected_tag), android_fdsan_get_tag_value(expected_tag));
} elseif (expected_tag && !tag) {
fdsan_error( "failed to exchange ownership of file descriptor: fd %d is " "unowned, was expected to be owned by %s 0x%" PRIx64,
fd, android_fdsan_get_tag_type(expected_tag), android_fdsan_get_tag_value(expected_tag));
} elseif (!expected_tag && tag) {
fdsan_error( "failed to exchange ownership of file descriptor: fd %d is " "owned by %s 0x%" PRIx64 ", was expected to be unowned",
fd, android_fdsan_get_tag_type(tag), android_fdsan_get_tag_value(tag));
} elseif (!expected_tag && !tag) { // This should never happen: our CAS failed, but expected == actual?
async_safe_fatal( "fdsan atomic_compare_exchange_strong failed unexpectedly while exchanging owner tag");
}
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.