diff --git a/src/native/pwntools/PwntoolsDecoder.ts b/src/native/pwntools/PwntoolsDecoder.ts index 3a28edbfa..d8cad3d2e 100644 --- a/src/native/pwntools/PwntoolsDecoder.ts +++ b/src/native/pwntools/PwntoolsDecoder.ts @@ -518,6 +518,13 @@ export class PwntoolsDecoder< [ pending.process.launch.ownership?.runId ?? "owned-decoder", ...(pending.root === undefined ? [] : [pending.root.path]), + // The retained group may still be live; name it as OwnedCommand does. + ...(pending.process.launch.ownership === undefined + ? [] + : [ + `pid:${pending.process.launch.ownership.leaderPid}`, + `process-group:${pending.process.launch.ownership.processGroupId}`, + ]), ], { reason: stopped.reason, diff --git a/tests/process-global/pwntoolsStageRetirement.test.ts b/tests/process-global/pwntoolsStageRetirement.test.ts index bcdaf858f..6ec062535 100644 --- a/tests/process-global/pwntoolsStageRetirement.test.ts +++ b/tests/process-global/pwntoolsStageRetirement.test.ts @@ -261,6 +261,14 @@ it.runIf(supportedHost).each([ if (result.ok) throw new Error("Expected unresolved process ownership"); const projected = projectAnalysisError(result.error); expect(projected.code).toBe("cleanup_incomplete"); + expect(projected).toMatchObject({ + details: { + resources: expect.arrayContaining([ + expect.stringMatching(/^pid:\d+$/u), + expect.stringMatching(/^process-group:\d+$/u), + ]), + }, + }); if (stage === "debugger") expect(projected).toMatchObject({ details: {