// Global variable to signal LSAN that we are not leaking memory.
uint8_t* allocated_signal_stack = nullptr;
static std::string GetDexFileName(const std::string& jar_name) { // The jar files are located in the data directory within the directory of the fuzzer's binary.
std::string executable_dir = android::base::GetExecutableDirectory();
std::string result =
android::base::StringPrintf("%s/data/%s.jar", executable_dir.c_str(), jar_name.c_str());
void FuzzerInitialize(CompilerCallbacks* callbacks, InstructionSet isa) { // Set logging to error and above to avoid warnings about unexpected checksums.
android::base::SetMinimumLogSeverity(android::base::ERROR);
// Check for heap corruption before running the fuzzer.
Runtime::Current()->GetHeap()->VerifyHeap();
// Runtime::Create acquired the mutator_lock_ that is normally given away when we // Runtime::Start, give it away now with `TransitionFromSuspendedToRunnable` until we figure out // how to start a Runtime.
Thread::Current()->TransitionFromRunnableToSuspended(ThreadState::kNative);
// Query the current stack and add it to the global variable. Otherwise LSAN complains about a // non-existing leak.
stack_t ss; if (sigaltstack(nullptr, &ss) == -1) {
PLOG(FATAL) << "sigaltstack failed";
}
allocated_signal_stack = reinterpret_cast<uint8_t*>(ss.ss_sp);
}
ALWAYS_INLINE std::unique_ptr<StandardDexFile> VerifyDexFile(const uint8_t* data,
size_t size, const std::string& location) { // Do not verify the checksum as we only care about the DEX file contents, // and know that the checksum would probably be erroneous (i.e. random).
constexpr bool kVerifyChecksum = false;
std::unique_ptr<StandardDexFile> dex_file( new StandardDexFile(data,
location, /*location_checksum=*/0, /*oat_dex_file=*/nullptr,
std::make_shared<MemoryDexFileContainer>(data, size)));
for (ClassAccessor accessor : dex_file->GetClasses()) {
h_klass.Assign(
class_linker->FindClass(soa.Self(), *dex_file, accessor.GetClassIdx(), h_loader)); // Ignore classes that couldn't be loaded since we are looking for crashes during // class/method verification. if (h_klass == nullptr || h_klass->IsErroneous()) { // Treat as failure to pass verification
passed_class_verification = false;
soa.Self()->ClearException(); continue;
} if (&h_klass->GetDexFile() != dex_file) { // Skip a duplicate class (as the resolved class is from another dex file). This can happen // e.g. if we have a class named "sun.misc.Unsafe" in fuzz.dex. continue;
}
h_dex_cache.Assign(h_klass->GetDexCache());
// The class loader from the class's dex cache is different from the dex file's class loader // for boot image classes e.g. java.util.AbstractCollection.
h_dex_cache_class_loader.Assign(h_klass->GetDexCache()->GetClassLoader());
DCHECK_EQ(h_klass->IsErroneous(), failure_kind == verifier::FailureKind::kHardFailure); if (failure_kind == verifier::FailureKind::kHardFailure) {
passed_class_verification = false; // ClassLinker::VerifyClass throws, so we clear it before we continue.
CHECK(soa.Self()->IsExceptionPending());
soa.Self()->ClearException();
}
ALWAYS_INLINE void IterationCleanup(jobject class_loader, const StandardDexFile* dex_file) {
ScopedObjectAccess soa(Thread::Current());
Runtime* runtime = Runtime::Current(); // Clear the arena pool to free RAM. The next iteration won't be referencing the pool we just // used.
runtime->ReclaimArenaPoolMemory();
// Delete weak root to the DexCache before removing a DEX file from the cache. This is usually // handled by the GC, but since we are not calling it every iteration, we need to delete them // manually. const ClassLinker::DexCacheData* dex_cache_data =
FuzzerCommonHelper::GetDexCacheData(runtime, dex_file); if (dex_cache_data != nullptr && dex_cache_data->weak_root != nullptr) {
soa.Env()->GetVm()->DeleteWeakGlobalRef(soa.Self(), dex_cache_data->weak_root);
}
// We finished verification and we can move to compilation, using the verification results for (ClassAccessor accessor : dex_file->GetClasses()) {
h_klass.Assign(
class_linker->FindClass(soa.Self(), *dex_file, accessor.GetClassIdx(), h_loader)); // Ignore classes that couldn't be loaded since we are looking for crashes during // compilation. if (h_klass == nullptr || h_klass->IsErroneous()) {
soa.Self()->ClearException(); continue;
} if (&h_klass->GetDexFile() != dex_file) { // Skip a duplicate class (as the resolved class is from another dex file). This can happen // e.g. if we have a class named "sun.misc.Unsafe" in fuzz.dex. continue;
}
ClassReference ref(dex_file, h_klass->GetDexClassDefIndex()); if (callbacks->IsClassRejected(ref)) { continue;
}
h_dex_cache.Assign(h_klass->GetDexCache());
// The class loader from the class's dex cache is different from the dex file's class loader // for boot image classes e.g. java.util.AbstractCollection.
h_dex_cache_class_loader.Assign(h_klass->GetDexCache()->GetClassLoader());
template <typename CompilerOrCompilerOptions, typename CompileFn>
ALWAYS_INLINE int FuzzerTestOneInputCommon( const uint8_t* data,
size_t size,
CompilerOrCompilerOptions* compiler_or_compiler_options,
FuzzerCompilerCallbacks* callbacks, int* skipped_gc_iterations, int max_skip_gc_iterations, bool debug_prints,
std::vector<std::unique_ptr<uint8_t[]>>& data_to_delete,
std::vector<std::unique_ptr<StandardDexFile>>& dex_files_to_delete,
CompileFn compile_fn) { // Note that we ignore the resulting DEX file from `VerifyDexFile` since we want to copy `data` to // manage it ourselves. if (VerifyDexFile(data, size, "fuzz.dex") == nullptr) { // DEX file couldn't be verified, don't save it in the corpus. return -1;
}
// Copy data to keep it alive. Use unique_ptr so that we don't leak.
data_to_delete.emplace_back(new uint8_t[size]);
uint8_t* new_data = data_to_delete.back().get();
memcpy(new_data, data, size);
// TODO(solanes): Is this the best way to get an art method?
ArtMethod* art_method =
class_linker->ResolveMethodId(method.GetIndex(), h_dex_cache, h_dex_cache_class_loader);
if (art_method == nullptr) { // TODO(solanes): Can we guarantee that we will resolve to an ArtMethod? returnfalse;
}
// Use the flags from the ArtMethod, which may be different from the ClassAccessor::Method const uint32_t access_flags = art_method->GetAccessFlags();
if (ArtMethod::IsNative(access_flags)) { // TODO(solanes): Support JNI? returnfalse;
}
if (ArtMethod::IsAbstract(access_flags)) { // Abstract methods don't have code. returnfalse;
}
if (!ArtMethod::IsCompilable(access_flags) ||
ArtMethod::IsIntrinsic(access_flags) ||
!ArtMethod::IsInvokable(access_flags)) { // This method will never be compiled. returnfalse;
}
MethodReference method_ref(dex_file, method.GetIndex()); if (callbacks->IsUncompilableMethod(method_ref)) { returnfalse;
}
if (debug_prints) {
LOG(ERROR) << "Going to compile: " << dex_file->PrettyMethod(method.GetIndex())
<< ". IsUncompilableMethod: " << std::boolalpha
<< callbacks->IsUncompilableMethod(method_ref) << std::noboolalpha
<< " using klass " << h_klass->PrettyClass();
}
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.