From 059f6c97b46e988bc1ff3b68ddb3add255321896 Mon Sep 17 00:00:00 2001 From: Ao Li Date: Wed, 27 Mar 2024 22:41:51 -0400 Subject: [PATCH] Make sure SFuzz stops gracefully when failure occurs. --- core/build.gradle.kts | 1 + .../cmu/pasta/sfuzz/core/GlobalContext.kt | 47 ++++++++++-- .../main/kotlin/cmu/pasta/sfuzz/core/Main.kt | 14 +--- .../cmu/pasta/sfuzz/core/RuntimeDelegate.kt | 16 ++-- .../cmu/pasta/sfuzz/core/ThreadContext.kt | 4 +- .../cmu/pasta/sfuzz/core/concurrency/Sync.kt | 6 +- examples/build.gradle.kts | 75 ++++++------------- 7 files changed, 84 insertions(+), 79 deletions(-) diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 7fc2be03..c2e28a62 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -4,6 +4,7 @@ plugins { kotlin("jvm") kotlin("plugin.serialization") version "1.9.22" id("com.github.johnrengelman.shadow") version "8.1.1" + id("maven-publish") } repositories { diff --git a/core/src/main/kotlin/cmu/pasta/sfuzz/core/GlobalContext.kt b/core/src/main/kotlin/cmu/pasta/sfuzz/core/GlobalContext.kt index 440c4056..7b35582a 100644 --- a/core/src/main/kotlin/cmu/pasta/sfuzz/core/GlobalContext.kt +++ b/core/src/main/kotlin/cmu/pasta/sfuzz/core/GlobalContext.kt @@ -63,7 +63,21 @@ object GlobalContext { val t = Thread.currentThread() val context = registeredThreads[t.id]!! context.state = ThreadState.Completed - scheduleNextOperation(true) + while (registeredThreads.any { it.value.state != ThreadState.Completed }) { + try { + scheduleNextOperation(true) + } catch (e: TargetTerminateException) { + // If deadlock detected let's try to unblock one thread and continue. + if (e.status == -1) { + for (thread in registeredThreads.values) { + if (thread.state == ThreadState.Paused) { + thread.state = ThreadState.Enabled + break + } + } + } + } + } } fun start() { @@ -172,7 +186,9 @@ object GlobalContext { } fun threadCompleted(t: Thread) { - monitorEnter(t) + if (!errorFound) { + monitorEnter(t) + } objectNotifyAll(t) registeredThreads[t.id]?.state = ThreadState.Completed // We do not want to send notify all because @@ -191,9 +207,24 @@ object GlobalContext { Thread.yield() } lockUnlockDone(t) - unlockImpl(t, t.id, false, false, true) - syncManager.synchronizationPoints.remove(System.identityHashCode(t)) - scheduleNextOperation(false) + if (!errorFound) { + unlockImpl(t, t.id, false, false, true) + syncManager.synchronizationPoints.remove(System.identityHashCode(t)) + } + try { + scheduleNextOperation(false) + } catch (e: TargetTerminateException) { + // If deadlock detected let's try to unblock one thread and continue. + if (e.status == -1) { + for (thread in registeredThreads.values) { + if (thread.state == ThreadState.Paused) { + thread.state = ThreadState.Running + thread.unblock() + break + } + } + } + } } } @@ -375,7 +406,7 @@ object GlobalContext { // synchronized(lock) { // lock.unlock(); // } - while (!lockManager.lock(lock, t, true, false)) { + while (!lockManager.lock(lock, t, true, false) && !errorFound) { registeredThreads[t]?.state = ThreadState.Paused // We want to block current thread because we do @@ -384,6 +415,10 @@ object GlobalContext { // threads hold the same lock. scheduleNextOperation(true) } + + if (errorFound) { + throw TargetTerminateException(-2) + } } fun monitorEnter(lock: Any) { diff --git a/core/src/main/kotlin/cmu/pasta/sfuzz/core/Main.kt b/core/src/main/kotlin/cmu/pasta/sfuzz/core/Main.kt index 360b89c9..dd3e56ec 100644 --- a/core/src/main/kotlin/cmu/pasta/sfuzz/core/Main.kt +++ b/core/src/main/kotlin/cmu/pasta/sfuzz/core/Main.kt @@ -3,7 +3,6 @@ package cmu.pasta.sfuzz.core import cmu.pasta.sfuzz.core.runtime.AnalysisResult import cmu.pasta.sfuzz.runtime.Delegate import cmu.pasta.sfuzz.runtime.Runtime -import cmu.pasta.sfuzz.runtime.TargetTerminateException import java.lang.reflect.InvocationTargetException import java.nio.file.Paths import kotlin.io.path.ExperimentalPathApi @@ -39,19 +38,8 @@ fun run(config: Configuration) { } Runtime.onMainExit() } catch (e: InvocationTargetException) { - val cause = e.cause - if (cause is TargetTerminateException) { - Runtime.onMainExit() - if (cause.status != 0) { - println("target terminated: ${cause.status}") - println("iter: $i") - } - } else { - println("target terminated: ${cause}") - println("iter: $i") - } GlobalContext.errorFound = true - // GlobalContext.checkErrorAndExit() + Runtime.onMainExit() } Runtime.DELEGATE = Delegate() GlobalContext.done(AnalysisResult.COMPLETE) diff --git a/core/src/main/kotlin/cmu/pasta/sfuzz/core/RuntimeDelegate.kt b/core/src/main/kotlin/cmu/pasta/sfuzz/core/RuntimeDelegate.kt index 5061c5c3..a21c995e 100644 --- a/core/src/main/kotlin/cmu/pasta/sfuzz/core/RuntimeDelegate.kt +++ b/core/src/main/kotlin/cmu/pasta/sfuzz/core/RuntimeDelegate.kt @@ -98,9 +98,12 @@ class RuntimeDelegate : Delegate() { skipFunctionEntered.set(1 + skipFunctionEntered.get()) return } - GlobalContext.lockLock(l) - entered.set(false) - skipFunctionEntered.set(skipFunctionEntered.get() + 1) + try { + GlobalContext.lockLock(l) + } finally { + entered.set(false) + skipFunctionEntered.set(skipFunctionEntered.get() + 1) + } } override fun onLockLockDone(l: ReentrantLock?) { @@ -132,8 +135,11 @@ class RuntimeDelegate : Delegate() { override fun onMonitorEnter(o: Any) { if (checkEntered()) return - GlobalContext.monitorEnter(o) - entered.set(false) + try { + GlobalContext.monitorEnter(o) + } finally { + entered.set(false) + } } override fun onMonitorExit(o: Any) { diff --git a/core/src/main/kotlin/cmu/pasta/sfuzz/core/ThreadContext.kt b/core/src/main/kotlin/cmu/pasta/sfuzz/core/ThreadContext.kt index fe1fe0ef..c6fcfbaa 100644 --- a/core/src/main/kotlin/cmu/pasta/sfuzz/core/ThreadContext.kt +++ b/core/src/main/kotlin/cmu/pasta/sfuzz/core/ThreadContext.kt @@ -32,7 +32,9 @@ class ThreadContext(val thread: Thread, val index: Int) { } fun unblock() { - sync.unblock() + if (sync.isBlocked) { + sync.unblock() + } } fun checkInterrupt() { diff --git a/core/src/main/kotlin/cmu/pasta/sfuzz/core/concurrency/Sync.kt b/core/src/main/kotlin/cmu/pasta/sfuzz/core/concurrency/Sync.kt index eec6ce7a..1f9d6d76 100644 --- a/core/src/main/kotlin/cmu/pasta/sfuzz/core/concurrency/Sync.kt +++ b/core/src/main/kotlin/cmu/pasta/sfuzz/core/concurrency/Sync.kt @@ -4,6 +4,7 @@ package cmu.pasta.sfuzz.core.concurrency // for signals. class Sync(val goal: Int) : Any() { private var count = 0 + var isBlocked = false @Synchronized fun block() { @@ -11,6 +12,7 @@ class Sync(val goal: Int) : Any() { count = 0 return } + isBlocked = true // We don't need synchronized here because // it is already inside a synchronized method while (count < goal) { @@ -21,6 +23,7 @@ class Sync(val goal: Int) : Any() { // to unblock this operation. } } + isBlocked = false // At this point no concurrency. count = 0 } @@ -28,9 +31,6 @@ class Sync(val goal: Int) : Any() { @Synchronized fun unblock() { count += 1 - if (count > goal) { - println("??") - } assert(count <= goal) if (count == goal) { (this as Object).notify() diff --git a/examples/build.gradle.kts b/examples/build.gradle.kts index 9a107050..fcf56479 100644 --- a/examples/build.gradle.kts +++ b/examples/build.gradle.kts @@ -16,44 +16,13 @@ tasks.test { useJUnitPlatform() } -tasks.register("runExample") { - var jdk = project(":jdk") - classpath = sourceSets["main"].runtimeClasspath - mainClass.set("example.Main") - executable("${jdk.layout.buildDirectory.get().asFile}/java-inst/bin/java") -} - -tasks.compileJava { - options.compilerArgs.addAll(listOf("--add-exports", "java.base/jdk.internal.misc=ALL-UNNAMED")) -} - -tasks.register("run") { - val agentPath: String by rootProject.extra - val jdk = project(":jdk") - val instrumentation = project(":instrumentation") - classpath = sourceSets["main"].runtimeClasspath - executable("${jdk.layout.buildDirectory.get().asFile}/java-inst/bin/java") - mainClass.set("cmu.pasta.sfuzz.core.MainKt") - args = listOf("example.Main", "-o", "${layout.buildDirectory.get().asFile}/report", "--scheduler", "fifo") - jvmArgs("-agentpath:$agentPath") - jvmArgs("-javaagent:${instrumentation.layout.buildDirectory.get().asFile}/libs/${instrumentation.name}-${instrumentation.version}-all.jar") - doFirst { - // Printing the full command - println("Executing command: ${executable} ${jvmArgs!!.joinToString(" ")} -cp ${classpath.asPath} ${mainClass.get()} ${args!!.joinToString(" ")}") - } -} - -tasks.register("replay") { +tasks.withType { val agentPath: String by rootProject.extra val jdk = project(":jdk") - val cp = properties["classpath"] as String - val main = properties["mainClass"] as String - val mainName = main.split(".").last() val instrumentation = project(":instrumentation") - classpath = sourceSets["main"].runtimeClasspath + files(cp) + classpath = sourceSets["main"].runtimeClasspath executable("${jdk.layout.buildDirectory.get().asFile}/java-inst/bin/java") - mainClass.set("cmu.pasta.sfuzz.core.MainKt") - args = listOf(main, "main", "--path", "//Users/aoli/repos/sfuzz-benchmark/schedules/$mainName.csv", "--scheduler", "replay", "--logger", "csv") + mainClass = "cmu.pasta.sfuzz.core.MainKt" jvmArgs("-agentpath:$agentPath") jvmArgs("-javaagent:${instrumentation.layout.buildDirectory.get().asFile}/libs/${instrumentation.name}-${instrumentation.version}-all.jar") jvmArgs("-ea") @@ -63,23 +32,27 @@ tasks.register("replay") { } } -tasks.register("runBench") { - val agentPath: String by rootProject.extra - val jdk = project(":jdk") - val cp = properties["classpath"] as String - val main = properties["mainClass"] as String - val instrumentation = project(":instrumentation") - classpath = sourceSets["main"].runtimeClasspath + files(cp) - executable("${jdk.layout.buildDirectory.get().asFile}/java-inst/bin/java") - mainClass.set("cmu.pasta.sfuzz.core.MainKt") - args = listOf(main, "main", "-o", "${layout.buildDirectory.get().asFile}/report", "--scheduler", "random", "--logger", "csv", "--iter", "1000") - jvmArgs("-agentpath:$agentPath") - jvmArgs("-javaagent:${instrumentation.layout.buildDirectory.get().asFile}/libs/${instrumentation.name}-${instrumentation.version}-all.jar") - jvmArgs("-ea") - doFirst { - // Printing the full command - println("Executing command: ${executable} ${jvmArgs!!.joinToString(" ")} -cp ${classpath.asPath} ${mainClass.get()} ${args!!.joinToString(" ")}") - } + +tasks.compileJava { + options.compilerArgs.addAll(listOf("--add-exports", "java.base/jdk.internal.misc=ALL-UNNAMED")) +} + +tasks.register("runExample") { + args = listOf("example.Main", "-o", "${layout.buildDirectory.get().asFile}/report", "--scheduler", "fifo") +} + +tasks.register("replay") { + val cp = properties["classpath"] as String? ?: "" + val main = properties["mainClass"] as String? ?: "" + classpath = classpath + files(cp) + args = listOf("cmu.pasta.sfuzz.benchmark.sctbench.cs.$main", "main", "--path", "//Users/aoli/repos/sfuzz-benchmark/schedules/$main.csv", "--scheduler", "replay", "--logger", "csv") +} + +tasks.register("runSCT") { + val cp = properties["classpath"] as String? ?: "" + val main = properties["mainClass"] as String? ?: "" + classpath = classpath + files(cp) + args = listOf("cmu.pasta.sfuzz.benchmark.sctbench.cs.$main", "main", "-o", "${layout.buildDirectory.get().asFile}/report", "--scheduler", "random", "--logger", "csv", "--iter", "1000") } tasks.register("runArithmeticProgBad") {