From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 24CDB37AA97 for ; Thu, 23 Apr 2026 10:07:44 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776938864; cv=none; b=bvFk/UaYdUMh83VPVkCM22aEOVFIVUCSn+dGC3owcnb8IQZd+x2noM8OeCMImmk+dCsKz//lbUVvK50va680aeAXQmUOOpII2AopY3AN9EtJzwz7ny9IXYmIUsm4NnVnGcfz7ltnQu+ffXy5/cQLeX56SoEOrtFI8B6EXydNR8E= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776938864; c=relaxed/simple; bh=XLthABTvu6wZbcVZCsOBaQZVrcObStJws8bV4+2Va+Y=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=VdN1WFnioYRrTrjiSdOafHYocVlui48GsAJNEsVk7k8+z0OmtkuY3VCT/JU0ZOPAuUXspQSapObk1W6CkkvbwTpkr9EkSPbhw9boW6OTY/Cb5ZY2JZqsfyvdZMZRlLnBXUTQDUu9PR8HWL+kSLSJ//IgWj5FOTRfUU4k5OMMrto= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=R2mj7TVu; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="R2mj7TVu" Received: by smtp.kernel.org (Postfix) with ESMTPSA id AA6C2C2BCB5; Thu, 23 Apr 2026 10:07:43 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1776938864; bh=XLthABTvu6wZbcVZCsOBaQZVrcObStJws8bV4+2Va+Y=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=R2mj7TVurnX+CLOBGT23kIGf8DPba6GTlmXXLP3RbJeUSQoO3Tc6JNRPe52VK3GRE PK68JVgHzwM88dlrkdW2eiHi7rgmlho/kS3kOalJibcmwiKS9u7pkuoIXg0oEw7jOj g5LdCSlpAtgiJFO+kzbdnHiyU8/jztEidIjD488XajfPuT49Ahcf5kweUkdYquCzD0 HB9l6EkdjxmMe9ZGsD2/pd1XMEwokv12LwlDZQvazViMoHvIrQaur/LThNrTb44mW0 7jdSoHrZGFuqP+e+tDC6c732SFm0PhHFWaE50yPF8K9d2NlVbC3IHSW1fzugGQjGa9 D4rWIxMf0HRDg== From: Maxime Ripard Date: Thu, 23 Apr 2026 12:06:47 +0200 Subject: [PATCH v2 09/28] drm/atomic: Only call atomic_destroy_state on a !NULL pointer Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit Message-Id: <20260423-drm-state-readout-v2-9-6cde1a9910ed@kernel.org> References: <20260423-drm-state-readout-v2-0-6cde1a9910ed@kernel.org> In-Reply-To: <20260423-drm-state-readout-v2-0-6cde1a9910ed@kernel.org> To: Maarten Lankhorst , Thomas Zimmermann , David Airlie , Simona Vetter , Andrzej Hajda , Neil Armstrong , Robert Foss , Laurent Pinchart , Jonas Karlman , Jernej Skrabec , Jyri Sarha , Tomi Valkeinen Cc: Devarsh Thakkar , dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, Maxime Ripard , Laurent Pinchart X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=3793; i=mripard@kernel.org; h=from:subject:message-id; bh=XLthABTvu6wZbcVZCsOBaQZVrcObStJws8bV4+2Va+Y=; b=owGbwMvMwCmsHn9OcpHtvjLG02pJDJkv33tdWMN989WPR+IzI9ZHSRrGpEpJ7mgptV1a2fO3d JfjzNq9HVNZGIQ5GWTFFFmeyISdXt6+uMrBfuUPmDmsTCBDGLg4BWAiZVaMdRoc7wNLeAz+rDmS xZLf3X4/XSSc9b/0XvVdzIINE1PXcFwomMbM9eeT/M7ZpYqnrN7IM1YxTdN86WXwopn3W5z300v fzl+P7BG85sotPt1VJPF29//lmZuvaFmvrP/4N37lqVOfW3wA X-Developer-Key: i=mripard@kernel.org; a=openpgp; fpr=BE5675C37E818C8B5764241C254BCFC56BF6CE8D The drm_atomic_state structure is freed through the drm_atomic_state_put() function, that eventually calls drm_atomic_state_default_clear() by default when there's no active users of that state. It then iterates over all objects with a state, and will call the atomic_destroy_state callback on the state pointer. The state pointer is mostly used these days to point to which of the old or new state needs to be freed, depending on whether the state was committed or not. So it all makes sense. However, with the hardware state readout support approaching, we might have a state, with multiple objects in it, but no state to free because we want them to persist. In such a case, the state pointer is going to be NULL, and thus we'll end up with NULL pointer dereference. Test if the state pointer is non-NULL before calling atomic_destroy_state on it. Reviewed-by: Laurent Pinchart Reviewed-by: Thomas Zimmermann Signed-off-by: Maxime Ripard --- drivers/gpu/drm/drm_atomic.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index c714a6e6e9ae..6449a4fd4ae0 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -274,12 +274,14 @@ void drm_atomic_state_default_clear(struct drm_atomic_state *state) struct drm_connector *connector = state->connectors[i].ptr; if (!connector) continue; - connector->funcs->atomic_destroy_state(connector, - state->connectors[i].state_to_destroy); + if (state->connectors[i].state_to_destroy) + connector->funcs->atomic_destroy_state(connector, + state->connectors[i].state_to_destroy); + state->connectors[i].ptr = NULL; state->connectors[i].state_to_destroy = NULL; state->connectors[i].old_state = NULL; state->connectors[i].new_state = NULL; drm_connector_put(connector); @@ -289,12 +291,13 @@ void drm_atomic_state_default_clear(struct drm_atomic_state *state) struct drm_crtc *crtc = state->crtcs[i].ptr; if (!crtc) continue; - crtc->funcs->atomic_destroy_state(crtc, - state->crtcs[i].state_to_destroy); + if (state->crtcs[i].state_to_destroy) + crtc->funcs->atomic_destroy_state(crtc, + state->crtcs[i].state_to_destroy); state->crtcs[i].ptr = NULL; state->crtcs[i].state_to_destroy = NULL; state->crtcs[i].old_state = NULL; state->crtcs[i].new_state = NULL; @@ -309,12 +312,14 @@ void drm_atomic_state_default_clear(struct drm_atomic_state *state) struct drm_plane *plane = state->planes[i].ptr; if (!plane) continue; - plane->funcs->atomic_destroy_state(plane, - state->planes[i].state_to_destroy); + if (state->planes[i].state_to_destroy) + plane->funcs->atomic_destroy_state(plane, + state->planes[i].state_to_destroy); + state->planes[i].ptr = NULL; state->planes[i].state_to_destroy = NULL; state->planes[i].old_state = NULL; state->planes[i].new_state = NULL; } @@ -337,12 +342,14 @@ void drm_atomic_state_default_clear(struct drm_atomic_state *state) struct drm_private_obj *obj = state->private_objs[i].ptr; if (!obj) continue; - obj->funcs->atomic_destroy_state(obj, - state->private_objs[i].state_to_destroy); + if (state->private_objs[i].state_to_destroy) + obj->funcs->atomic_destroy_state(obj, + state->private_objs[i].state_to_destroy); + state->private_objs[i].ptr = NULL; state->private_objs[i].state_to_destroy = NULL; state->private_objs[i].old_state = NULL; state->private_objs[i].new_state = NULL; } -- 2.53.0