Skip to content

Commit 79456b4

Browse files
committed
capture execution/program input values synchronously in the event listeners
1 parent df24915 commit 79456b4

File tree

1 file changed

+101
-113
lines changed

1 file changed

+101
-113
lines changed

Sources/Fuzzilli/Modules/PostgreSQLSync.swift

Lines changed: 101 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -139,145 +139,137 @@ public class PostgreSQLSync: Module {
139139
// If not found (e.g., corpus import), use empty strings
140140
let programId = program.id.uuidString
141141
let (stdout, stderr, fuzzout) = self.executionCache[programId] ?? ("", "", "")
142-
143-
// Clean up the cache entry immediately after use
144142
self.executionCache.removeValue(forKey: programId)
145-
146-
Task {
147-
guard let fuzzerId = self.cachedFuzzerId else {
148-
self.logger.error("Fuzzer ID not set - registration may have failed")
149-
return
150-
}
151-
152-
let programInput = try self.prepareProgramInput(program: program, fuzzerId: fuzzerId, programId: programId)
153-
await self.storage.addProgramToBatch(programInput)
154-
155-
if let execution = execution {
156-
let outcomeId = DatabaseUtils.mapExecutionOutcome(outcome: execution.outcome)
157143

158-
// Determine if new edges were found
159-
// Check if aspects is a CovEdgeSet to distinguish between:
160-
// - New coverage edges (CovEdgeSet with count > 0)
161-
// - Feedback/optimization delta only (basic ProgramAspects)
162-
let isNewEdge: Bool
163-
if let covEdgeSet = aspects as? CovEdgeSet {
164-
isNewEdge = covEdgeSet.count > 0
165-
} else {
166-
isNewEdge = false
167-
}
144+
guard let fuzzerId = self.cachedFuzzerId else {
145+
self.logger.error("Fuzzer ID not set - registration may have failed")
146+
return
147+
}
168148

169-
var coverageTotal: Double? = nil
170-
var edgesFound: Int? = nil
171-
var totalEdges: Int? = nil
172-
var turbofanOptimizationBits: Int64? = nil
173-
var feedbackNexusCount: Int? = nil
174-
175-
if let evaluator = self.covEvaluator {
176-
let totalEdgesCount = evaluator.getTotalEdgesCount()
177-
totalEdges = Int(totalEdgesCount)
178-
179-
let foundEdgesCount = evaluator.getFoundEdgesCount()
180-
181-
if totalEdgesCount > 0 {
182-
coverageTotal = (Double(foundEdgesCount) / Double(totalEdgesCount)) * 100
183-
}
184-
185-
if let covEdgeSet = aspects as? CovEdgeSet {
186-
edgesFound = Int(covEdgeSet.count)
187-
} else {
188-
edgesFound = 0
189-
}
190-
191-
turbofanOptimizationBits = Int64(evaluator.getTurbofanOptimizationBits())
192-
feedbackNexusCount = Int(evaluator.getFeedbackNexusCount())
193-
}
194-
195-
let executionInput = PostgresSQLStorage.ExecutionInput(
196-
programHash: programInput.programHash,
197-
executionOutcomeId: outcomeId,
198-
coverageTotal: coverageTotal,
199-
edgesFound: edgesFound,
200-
totalEdges: totalEdges,
201-
isNewEdge: isNewEdge,
202-
stdout: stdout,
203-
stderr: stderr,
204-
fuzzout: fuzzout,
205-
turbofanOptimizationBits: turbofanOptimizationBits,
206-
feedbackNexusCount: feedbackNexusCount,
207-
createdAt: Date()
208-
)
209-
await self.storage.addExecutionToBatch(executionInput)
210-
211-
// TODO Aleksi: This is a bit too verbose, maybe only log every x times
212-
//if self.enableLogging {
213-
// let edgeInfo = isNewEdge ? " with new edges" : " (feedback/optimization delta only)"
214-
// self.logger.verbose("Added interesting program and execution to batch\(edgeInfo)")
215-
//}
216-
}
149+
let programInput: PostgresSQLStorage.ProgramInput
150+
do {
151+
programInput = try self.prepareProgramInput(program: program, fuzzerId: fuzzerId, programId: programId)
152+
} catch {
153+
self.logger.error("Failed to prepare program input: \(error)")
154+
return
217155
}
218-
}
219-
220-
fuzzer.registerEventListener(for: fuzzer.events.CrashFound) { ev in
221-
let program = ev.program
222-
let behaviour = ev.behaviour // .deterministic or .flaky
223-
let isUnique = ev.isUnique
224-
225-
// Retrieve cached execution outputs using program ID
226-
// For crashes, stderr will contain the crash stacktrace and signal info
227-
let programId = program.id.uuidString
228-
let (stdout, stderr, fuzzout) = self.executionCache[programId] ?? ("", "", "")
229-
230-
// Clean up the cache entry immediately after use
231-
self.executionCache.removeValue(forKey: programId)
232-
233-
Task {
234-
guard let fuzzerId = self.cachedFuzzerId else {
235-
self.logger.error("Fuzzer ID not set - registration may have failed")
236-
return
156+
157+
var executionInput: PostgresSQLStorage.ExecutionInput? = nil
158+
if let execution = execution {
159+
// Determine if new edges were found
160+
// Check if aspects is a CovEdgeSet to distinguish between:
161+
// - New coverage edges (CovEdgeSet with count > 0)
162+
// - Feedback/optimization delta only (basic ProgramAspects)
163+
let isNewEdge: Bool
164+
if let covEdgeSet = aspects as? CovEdgeSet {
165+
isNewEdge = covEdgeSet.count > 0
166+
} else {
167+
isNewEdge = false
237168
}
238169

239-
let programInput = try self.prepareProgramInput(program: program, fuzzerId: fuzzerId, programId: programId)
240-
await self.storage.addProgramToBatch(programInput)
241-
242-
// Get coverage metrics if available (crashes may still have coverage)
243170
var coverageTotal: Double? = nil
244171
var edgesFound: Int? = nil
245172
var totalEdges: Int? = nil
246173
var turbofanOptimizationBits: Int64? = nil
247174
var feedbackNexusCount: Int? = nil
248-
175+
249176
if let evaluator = self.covEvaluator {
250177
let totalEdgesCount = evaluator.getTotalEdgesCount()
251178
totalEdges = Int(totalEdgesCount)
252-
253179
let foundEdgesCount = evaluator.getFoundEdgesCount()
254-
255180
if totalEdgesCount > 0 {
256181
coverageTotal = (Double(foundEdgesCount) / Double(totalEdgesCount)) * 100
257182
}
258-
259-
// For crashes, we don't have new edge information in the same way
260-
edgesFound = Int(foundEdgesCount)
261-
183+
if let covEdgeSet = aspects as? CovEdgeSet {
184+
edgesFound = Int(covEdgeSet.count)
185+
} else {
186+
edgesFound = 0
187+
}
262188
turbofanOptimizationBits = Int64(evaluator.getTurbofanOptimizationBits())
263189
feedbackNexusCount = Int(evaluator.getFeedbackNexusCount())
264190
}
265-
266-
// Create execution record with outcome_id = 1 (Crashed)
267-
let executionInput = PostgresSQLStorage.ExecutionInput(
191+
192+
executionInput = PostgresSQLStorage.ExecutionInput(
268193
programHash: programInput.programHash,
269-
executionOutcomeId: 1, // Crashed
194+
executionOutcomeId: DatabaseUtils.mapExecutionOutcome(outcome: execution.outcome),
270195
coverageTotal: coverageTotal,
271196
edgesFound: edgesFound,
272197
totalEdges: totalEdges,
273-
isNewEdge: false, // Crashes don't contribute new edges
198+
isNewEdge: isNewEdge,
274199
stdout: stdout,
275-
stderr: stderr, // Contains crash stacktrace and signal info
200+
stderr: stderr,
276201
fuzzout: fuzzout,
277202
turbofanOptimizationBits: turbofanOptimizationBits,
278203
feedbackNexusCount: feedbackNexusCount,
279204
createdAt: Date()
280205
)
206+
}
207+
Task {
208+
await self.storage.addProgramToBatch(programInput)
209+
if let executionInput = executionInput {
210+
await self.storage.addExecutionToBatch(executionInput)
211+
}
212+
}
213+
}
214+
215+
fuzzer.registerEventListener(for: fuzzer.events.CrashFound) { ev in
216+
let program = ev.program
217+
let behaviour = ev.behaviour // .deterministic or .flaky
218+
let isUnique = ev.isUnique
219+
220+
// Retrieve cached execution outputs using program ID
221+
// For crashes, stderr will contain the crash stacktrace and signal info
222+
let programId = program.id.uuidString
223+
let (stdout, stderr, fuzzout) = self.executionCache[programId] ?? ("", "", "")
224+
self.executionCache.removeValue(forKey: programId)
225+
226+
guard let fuzzerId = self.cachedFuzzerId else {
227+
self.logger.error("Fuzzer ID not set - registration may have failed")
228+
return
229+
}
230+
231+
let programInput: PostgresSQLStorage.ProgramInput
232+
do {
233+
programInput = try self.prepareProgramInput(program: program, fuzzerId: fuzzerId, programId: programId)
234+
} catch {
235+
self.logger.error("Failed to prepare program input: \(error)")
236+
return
237+
}
238+
239+
// Get coverage metrics if available (crashes may still have coverage)
240+
var coverageTotal: Double? = nil
241+
var totalEdges: Int? = nil
242+
var turbofanOptimizationBits: Int64? = nil
243+
var feedbackNexusCount: Int? = nil
244+
245+
if let evaluator = self.covEvaluator {
246+
let totalEdgesCount = evaluator.getTotalEdgesCount()
247+
totalEdges = Int(totalEdgesCount)
248+
let foundEdgesCount = evaluator.getFoundEdgesCount()
249+
if totalEdgesCount > 0 {
250+
coverageTotal = (Double(foundEdgesCount) / Double(totalEdgesCount)) * 100
251+
}
252+
turbofanOptimizationBits = Int64(evaluator.getTurbofanOptimizationBits())
253+
feedbackNexusCount = Int(evaluator.getFeedbackNexusCount())
254+
}
255+
256+
let executionInput = PostgresSQLStorage.ExecutionInput(
257+
programHash: programInput.programHash,
258+
executionOutcomeId: 1, // Crashed
259+
coverageTotal: coverageTotal,
260+
edgesFound: nil, // Crashes don't contribute new edges
261+
totalEdges: totalEdges,
262+
isNewEdge: false, // Crashes don't contribute new edges
263+
stdout: stdout,
264+
stderr: stderr, // Contains crash stacktrace and signal info
265+
fuzzout: fuzzout,
266+
turbofanOptimizationBits: turbofanOptimizationBits,
267+
feedbackNexusCount: feedbackNexusCount,
268+
createdAt: Date()
269+
)
270+
// TODO Aleksi: Store the crash on disk as well
271+
Task {
272+
await self.storage.addProgramToBatch(programInput)
281273
await self.storage.addExecutionToBatch(executionInput)
282274

283275
if self.enableLogging {
@@ -289,7 +281,7 @@ public class PostgreSQLSync: Module {
289281
}
290282

291283
// Periodic Flush
292-
fuzzer.timers.scheduleTask(every: 15 * Minutes) {
284+
fuzzer.timers.scheduleTask(every: 2 * Minutes) {
293285
Task {
294286
do {
295287
try await self.storage.flushBatches()
@@ -463,8 +455,4 @@ public class PostgreSQLSync: Module {
463455
parentHash: parentHash
464456
)
465457
}
466-
467-
private func prepareExecutionInput() {
468-
469-
}
470458
}

0 commit comments

Comments
 (0)