|
48 | 48 | #include <vector> |
49 | 49 |
|
50 | 50 | #include "absl/base/nullability.h" |
| 51 | +#include "absl/base/optimization.h" |
51 | 52 | #include "./centipede/byte_array_mutator.h" |
52 | 53 | #include "./centipede/dispatcher_flag_helper.h" |
53 | 54 | #include "./centipede/execution_metadata.h" |
@@ -99,6 +100,26 @@ static uint64_t TimeInUsec() { |
99 | 100 | return tv.tv_sec * kUsecInSec + tv.tv_usec; |
100 | 101 | } |
101 | 102 |
|
| 103 | +// Atomic flags to make sure that (a) watchdog failure is reported only for |
| 104 | +// the current input, and (b) only one thread is handling watchdog failures. |
| 105 | + |
| 106 | +// True if the watchdog thread is detecting failures, false otherwise. |
| 107 | +static std::atomic<bool> watchdog_thread_busy = false; |
| 108 | +// True if a watchdog failure is found, false otherwise. |
| 109 | +static std::atomic<bool> watchdog_failure_found = false; |
| 110 | + |
| 111 | +static void WaitWatchdogThreadIdle() { |
| 112 | + while (ABSL_PREDICT_FALSE(watchdog_thread_busy.load())) { |
| 113 | + if (ABSL_PREDICT_FALSE(watchdog_failure_found.load())) { |
| 114 | + // A failure is found - wait for the process to terminate. |
| 115 | + sleep(1); // NOLINT |
| 116 | + } else { |
| 117 | + // Busy-wait for the detection. |
| 118 | + sleep(0); // NOLINT |
| 119 | + } |
| 120 | + } |
| 121 | +} |
| 122 | + |
102 | 123 | static void CheckWatchdogLimits() { |
103 | 124 | const uint64_t curr_time = time(nullptr); |
104 | 125 | struct Resource { |
@@ -142,11 +163,7 @@ static void CheckWatchdogLimits() { |
142 | 163 | }; |
143 | 164 | for (const auto &resource : resources) { |
144 | 165 | if (resource.limit != 0 && resource.value > resource.limit) { |
145 | | - // Allow only one invocation to handle a failure: needed because we call |
146 | | - // this function periodically in `WatchdogThread()`, but also call it in |
147 | | - // `RunOneInput()` after all the work is done. |
148 | | - static std::atomic<bool> already_handling_failure = false; |
149 | | - if (!already_handling_failure.exchange(true)) { |
| 166 | + if (!watchdog_failure_found.exchange(true)) { |
150 | 167 | if (resource.ignore_report) { |
151 | 168 | fprintf(stderr, |
152 | 169 | "========= %s exceeded: %" PRIu64 " > %" PRIu64 |
@@ -192,7 +209,9 @@ static void CheckWatchdogLimits() { |
192 | 209 | // No calls to ResetInputTimer() yet: input execution hasn't started. |
193 | 210 | if (state->input_start_time == 0) continue; |
194 | 211 |
|
| 212 | + watchdog_thread_busy = true; |
195 | 213 | CheckWatchdogLimits(); |
| 214 | + watchdog_thread_busy = false; |
196 | 215 | } |
197 | 216 | } |
198 | 217 |
|
@@ -376,6 +395,7 @@ static void RunOneInput(const uint8_t *data, size_t size, |
376 | 395 | if (fuzztest::internal::state->input_start_time.exchange(0) != 0) { |
377 | 396 | PostProcessSancov(target_return_value == -1); |
378 | 397 | } |
| 398 | + WaitWatchdogThreadIdle(); |
379 | 399 | state->stats.post_time_usec = UsecSinceLast(); |
380 | 400 | state->stats.peak_rss_mb = GetPeakRSSMb(); |
381 | 401 | } |
|
0 commit comments