diff --git a/tools/fuzzing/ipc/IPCFuzzController.cpp b/tools/fuzzing/ipc/IPCFuzzController.cpp index 0cbc2e784705..68a5ef6b4a34 100644 --- a/tools/fuzzing/ipc/IPCFuzzController.cpp +++ b/tools/fuzzing/ipc/IPCFuzzController.cpp @@ -127,6 +127,13 @@ void IPCFuzzController::OnActorConnected(IProtocol* protocol) { MOZ_FUZZING_NYX_DEBUG( "DEBUG: IPCFuzzController::OnActorConnected() Mutex locked\n"); actorIds[*portName].emplace_back(protocol->Id(), protocol->GetProtocolId()); + + // Fix the port we will be using for at least the next 5 messages + useLastPortName = true; + lastActorPortName = *portName; + + // Use this actor for the next 5 messages + useLastActor = 5; } else { MOZ_FUZZING_NYX_PRINT("WARNING: No port name on actor?!\n"); } @@ -356,17 +363,25 @@ bool IPCFuzzController::MakeTargetDecision( return false; } - *name = portInstances[portInstanceIndex % portInstances.size()]; + if (useLastActor) { + useLastActor--; + *name = lastActorPortName; - auto seqNos = portSeqNos[*name]; + MOZ_FUZZING_NYX_PRINT("DEBUG: MakeTargetDecision: Pinned to last actor.\n"); - // Hand out the correct sequence numbers - *seqno = seqNos.first - 1; - *fseqno = seqNos.second + 1; - - if (update) { - portSeqNos.insert_or_assign(*name, - std::pair(*seqno, *fseqno)); + // Once we stop pinning to the last actor, we need to decide if we + // want to keep the pinning on the port itself. We use one of the + // unused upper bits of portIndex for this purpose. + if (!useLastActor && (portIndex & (1 << 7))) { + MOZ_FUZZING_NYX_PRINT( + "DEBUG: MakeTargetDecision: Released pinning on last port.\n"); + useLastPortName = false; + } + } else if (useLastPortName) { + *name = lastActorPortName; + MOZ_FUZZING_NYX_PRINT("DEBUG: MakeTargetDecision: Pinned to last port.\n"); + } else { + *name = portInstances[portInstanceIndex % portInstances.size()]; } // We should always have at least one actor per port @@ -384,7 +399,23 @@ bool IPCFuzzController::MakeTargetDecision( return false; } - actorIndex %= actors.size(); + auto seqNos = portSeqNos[*name]; + + // Hand out the correct sequence numbers + *seqno = seqNos.first - 1; + *fseqno = seqNos.second + 1; + + if (update) { + portSeqNos.insert_or_assign(*name, + std::pair(*seqno, *fseqno)); + } + + if (useLastActor) { + actorIndex = actors.size() - 1; + } else { + actorIndex %= actors.size(); + } + ActorIdPair ids = actors[actorIndex]; *actorId = ids.first; @@ -603,6 +634,9 @@ NS_IMETHODIMP IPCFuzzController::IPCFuzzLoop::Run() { uint32_t expected_messages = 0; + IPCFuzzController::instance().useLastActor = 0; + IPCFuzzController::instance().useLastPortName = false; + for (int i = 0; i < 16; ++i) { if (!buffer.initLengthUninitialized(maxMsgSize)) { MOZ_REALLY_CRASH(__LINE__); diff --git a/tools/fuzzing/ipc/IPCFuzzController.h b/tools/fuzzing/ipc/IPCFuzzController.h index 8b7ac08527b2..faf89d9f81a8 100644 --- a/tools/fuzzing/ipc/IPCFuzzController.h +++ b/tools/fuzzing/ipc/IPCFuzzController.h @@ -124,6 +124,16 @@ class IPCFuzzController { std::unordered_map> actorIds; + // If set, `lastActorPortName` is valid and fuzzing is pinned to this port. + Atomic useLastPortName; + + // Last port where a new actor appeared. Only valid with `useLastPortName`. + mojo::core::ports::PortName lastActorPortName; + + // Counter to indicate how long fuzzing should stay pinned to the last + // actor that appeared on `lastActorPortName`. + Atomic useLastActor; + // This is the deterministic ordering of toplevel actors for fuzzing. // In this matrix, each row (toplevel index) corresponds to one toplevel // actor *type* while each entry in that row is an instance of that type,