DF-4371 / fix.diff
--- a/sys/dev/drm/radeon/r600_dpm.c 2026-06-29 12:51:19.000000000 +0000 +++ b/sys/dev/drm/radeon/r600_dpm.c 2026-09-19 18:44:01.666218647 +0000 @@ -937,6 +937,7 @@ dep_table); if (ret) { kfree(rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries); + rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries = NULL; return ret; } } @@ -948,7 +949,9 @@ dep_table); if (ret) { kfree(rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries); + rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries = NULL; kfree(rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk.entries); + rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk.entries = NULL; return ret; } } @@ -960,8 +963,11 @@ dep_table); if (ret) { kfree(rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries); + rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries = NULL; kfree(rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk.entries); + rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk.entries = NULL; kfree(rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk.entries); + rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk.entries = NULL; return ret; } } @@ -1300,18 +1306,25 @@ { struct radeon_dpm_dynamic_state *dyn_state = &rdev->pm.dpm.dyn_state; - kfree(dyn_state->vddc_dependency_on_sclk.entries); - kfree(dyn_state->vddci_dependency_on_mclk.entries); - kfree(dyn_state->vddc_dependency_on_mclk.entries); - kfree(dyn_state->mvdd_dependency_on_mclk.entries); - kfree(dyn_state->cac_leakage_table.entries); - kfree(dyn_state->phase_shedding_limits_table.entries); - kfree(dyn_state->ppm_table); - kfree(dyn_state->cac_tdp_table); - kfree(dyn_state->vce_clock_voltage_dependency_table.entries); - kfree(dyn_state->uvd_clock_voltage_dependency_table.entries); - kfree(dyn_state->samu_clock_voltage_dependency_table.entries); - kfree(dyn_state->acp_clock_voltage_dependency_table.entries); + /* + * NULL every pointer after kfree(): this function is reachable a + * second time (parse error paths above plus *_dpm_fini() at driver + * unload/reboot); a stale non-NULL pointer here is a double free. + */ +#define RADEON_KFREE_NULL(p) do { kfree(p); (p) = NULL; } while (0) + RADEON_KFREE_NULL(dyn_state->vddc_dependency_on_sclk.entries); + RADEON_KFREE_NULL(dyn_state->vddci_dependency_on_mclk.entries); + RADEON_KFREE_NULL(dyn_state->vddc_dependency_on_mclk.entries); + RADEON_KFREE_NULL(dyn_state->mvdd_dependency_on_mclk.entries); + RADEON_KFREE_NULL(dyn_state->cac_leakage_table.entries); + RADEON_KFREE_NULL(dyn_state->phase_shedding_limits_table.entries); + RADEON_KFREE_NULL(dyn_state->ppm_table); + RADEON_KFREE_NULL(dyn_state->cac_tdp_table); + RADEON_KFREE_NULL(dyn_state->vce_clock_voltage_dependency_table.entries); + RADEON_KFREE_NULL(dyn_state->uvd_clock_voltage_dependency_table.entries); + RADEON_KFREE_NULL(dyn_state->samu_clock_voltage_dependency_table.entries); + RADEON_KFREE_NULL(dyn_state->acp_clock_voltage_dependency_table.entries); +#undef RADEON_KFREE_NULL } enum radeon_pcie_gen r600_get_pcie_gen_support(struct radeon_device *rdev, |