Linux Media Controller development
 help / color / mirror / Atom feed
From: Sasha Levin <sashal@kernel.org>
To: patches@lists.linux.dev, stable@vger.kernel.org
Cc: Arnd Bergmann <arnd@arndb.de>,
	Hans Verkuil <hverkuil+cisco@kernel.org>,
	Sasha Levin <sashal@kernel.org>,
	mchehab@kernel.org, linux-media@vger.kernel.org,
	linux-kernel@vger.kernel.org
Subject: [PATCH AUTOSEL 6.18-5.10] media: v4l2-tpg: reduce stack usage for kasan builds
Date: Mon, 19 Oct 2026 09:50:45 -0400	[thread overview]
Message-ID: <20261019135441.1420968-354-sashal@kernel.org> (raw)
In-Reply-To: <20261019135441.1420968-1-sashal@kernel.org>

From: Arnd Bergmann <arnd@arndb.de>

[ Upstream commit c49cdaafa443ccf861a72d3191121294742c28c7 ]

tpg_fill_plane_buffer() is a rather complex function. While there is
nothing wrong with it per se, I have run into corner cases with clang-22
on s390 using KASAN that makes it run out of registers and blow the
stack warning limit from excessive spills:

drivers/media/common/v4l2-tpg/v4l2-tpg-core.c:2629:6: error: stack frame size (1560) exceeds limit (1536)
      in 'tpg_fill_plane_buffer' [-Werror,-Wframe-larger-than]
 2629 | void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std,

Forcing the two largest callees out of line completely avoids the problem
and prevents all the register spills, with the stack usage for each function
going down to a few bytes for the local variables.

Arguably this is a problem caused by clang rather than the code, but
a noinline_for_stack annotation is an easy workaround.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---

LLM Generated explanations, may be completely bogus:

I have enough history, diff, and mailing-list evidence to walk through
all nine phases and decide for this 7.3-rc4 tree.

## Phase 1: Commit message forensics

**Step 1.1: Subject line**
- Record: `[media/v4l2-tpg] [reduce] Reduce stack usage of
  tpg_fill_plane_buffer() for clang+KASAN builds so -Wframe-larger-than
  does not fail the build.`

**Step 1.2: Tags**
- Record:
  - `Signed-off-by: Arnd Bergmann <arnd@arndb.de>` (author)
  - `Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org>` (media
    maintainer)
  - No `Fixes:`
  - No `Reported-by:` / `Tested-by:` / `Reviewed-by:` / `Acked-by:` /
    `Link:` / `Cc: stable`
  - Absence of `Fixes:` / `Cc: stable` is expected for this pipeline and
    is not a negative signal
  - Notable: author is Arnd Bergmann (kbuild/clang/stack-usage); applied
    by Hans Verkuil (V4L2 maintainer). No syzbot, no user crash reports.

**Step 1.3: Body**
- Record:
  - **Bug:** `tpg_fill_plane_buffer()` is large; clang-22 on s390 with
    KASAN spills so many temporaries that the compile-time stack-frame
    warning fires as an error.
  - **Symptom:** `error: stack frame size (1560) exceeds limit (1536) in
    'tpg_fill_plane_buffer' [-Werror,-Wframe-larger-than]`
  - **Root cause:** clang register allocator + KASAN instrumentation,
    not incorrect C logic. Author: “nothing wrong with it per se” / “a
    problem caused by clang rather than the code”.
  - **Fix:** `noinline_for_stack` on the two largest callees so they are
    not inlined into the parent; per-function stack then drops to a few
    bytes.
  - **Version info:** clang-22, s390, KASAN. No kernel-version range
    given.

**Step 1.4: Hidden bug fix?**
- Record: Not a disguised UAF/leak/race. It is a **build-failure
  workaround**. Cover letter in the mbox also offers an LLVM bug if
  reviewers want one. Not a hidden runtime fix.

## Phase 2: Diff analysis

**Step 2.1: Inventory**
- Record:
  - File: `drivers/media/common/v4l2-tpg/v4l2-tpg-core.c` — 8
    insertions, 6 deletions (net +2)
  - Functions: `tpg_fill_plane_extras()`, `tpg_fill_plane_pattern()` —
    declaration only
  - Scope: single-file surgical annotation change; no logic, locking, or
    API change

**Step 2.2: Code flow**
- Record:
  - **Before:** both helpers are `static void`, so the compiler may
    inline them into `tpg_fill_plane_buffer()`.
  - **After:** both are `static noinline_for_stack void`; they remain
    callable from the same loop in `tpg_fill_plane_buffer()` (lines
    2707–2710) but cannot be inlined.
  - Path affected: compile-time inlining of the per-line fill helpers.
    Runtime control flow is unchanged.

**Step 2.3: Bug mechanism**
- Record: **Build / compiler-workaround (hardware-workaround
  analogue).** Not UAF, leak, race, NULL deref, or overflow.
  `noinline_for_stack` is `noinline` in `include/linux/compiler_types.h`
  “to prevent stack consumption”.

**Step 2.4: Fix quality**
- Record: Obviously correct and minimal. Regression risk is very low:
  extra calls in a test-pattern generator, not a production hot path.
  Arnd reports stack usage of each function drops. No public API /
  struct / locking change.

## Phase 3: Git history

**Step 3.1: Blame**
- Record: The two functions date to Hans Verkuil’s vivid TPG (2015),
  exported as `drivers/media/common/v4l2-tpg/v4l2-tpg-core.c` in
  `e07d46e7e0da8` (2016). The `noinline_for_stack` lines are this commit
  (`c49cdaafa443c`, 2026-06-18 / applied 2026-07-10). Long-lived code;
  the warning is from clang-22+KASAN inlining, not a new logic bug.

**Step 3.2: Fixes: tag**
- Record: None. Not applicable.

**Step 3.3: File history**
- Record: Recent TPG work is formats/patterns (`5a3757801e58a`,
  `5a531791edb24`), a div-by-zero fix, memleak fix. No prerequisite
  refactor. Standalone, not `N/M`.

**Step 3.4: Author**
- Record: Arnd Bergmann; many similar media stack-usage fixes
  (`c03b7dec3c4dd` rkvdec, `1a03f91c2c241` vivid clang stack,
  `ad4729225d93f` mxl5005s, etc.). This is the established
  `noinline_for_stack` pattern. Hans Verkuil applied it.

**Step 3.5: Dependencies**
- Record: Only `noinline_for_stack`, present in this tree as `#define
  noinline_for_stack noinline`. Applies standalone.

## Phase 4: Mailing list / external

**Step 4.1: Original discussion**
- Record:
  - `b4 dig -c c49cdaafa443c` →
    https://patch.msgid.link/20260618143252.1885475-1-arnd@kernel.org
  - `b4 dig -a`: **v1 only**, 2026-06-18. No later revision.
  - mbox is the patch plus: “If anyone thinks we should track this as an
    llvm bug, I can help come up with a reproducer”. **No replies, no
    NAK, no Cc: stable suggestion.**
  - lore.kernel.org WebFetch returned 403; thread recovered via `b4 dig
    -m`.

**Step 4.2: Recipients (`b4 dig -w`)**
- Record: Mauro Chehab, Nathan Chancellor, Nick Desaulniers, Bill
  Wendling, Justin Stitt, linux-media, LKML, llvm@lists.linux.dev. Right
  maintainers and LLVM list. No review tags in-tree beyond Hans’s SOB on
  apply.

**Step 4.3: Bug report**
- Record: No syzbot/bugzilla. The “report” is Arnd’s own clang-22 s390
  KASAN build. Severity: compile error under `-Werror`, not a runtime
  crash.

**Step 4.4: Series**
- Record: Standalone v1. Not part of a multi-patch series.

**Step 4.5: Stable list**
- Record: lore.kernel.org/stable WebFetch 403. **UNVERIFIED:** whether
  this was discussed on stable@. Nothing in the mbox nominates it.

## Phase 5: Semantic / call graph

**Step 5.1: Functions**
- Record: `tpg_fill_plane_extras`, `tpg_fill_plane_pattern`
  (annotations). Indirectly `tpg_fill_plane_buffer` (the function named
  in the warning).

**Step 5.2: Callers**
- Record: Both helpers are static and only called from
  `tpg_fill_plane_buffer()`. That function is `EXPORT_SYMBOL_GPL` and
  called from:
  - `tpg_fillbuffer()` (same file)
  - `drivers/media/test-drivers/vivid/vivid-kthread-cap.c`
  - `drivers/media/test-drivers/vimc/vimc-sensor.c`
  - `drivers/media/test-drivers/visl/visl-dec.c`
- Userspace-reachable only if a **virtual V4L2 test driver**
  (vivid/vimc/visl) is loaded. Not IRQ/core.

**Step 5.3: Callees**
- Record: memcpy of pattern lines, rectangle/pillar drawing, pixel-
  format switches. No locks, no alloc in the changed signatures.

**Step 5.4: Reachability**
- Record: Yes from userspace via vivid/vimc/visl, but those Kconfigs say
  “When in doubt, say N.” The failure being fixed is **compile-time**,
  so it hits anyone who *builds* `VIDEO_V4L2_TPG` (selected by those
  drivers; allmodconfig will build it).

**Step 5.5: Similar patterns**
- Record: Same `noinline_for_stack` workaround exists elsewhere in media
  (vivid 2019, rkvdec 2026). This instance is the TPG core helper, not a
  duplicate of those.

## Phase 6: This checkout

**Step 6.1: Local tree and buggy code**
- Record:
  - `git describe HEAD` → `v7.3-rc4-27-gf0100363d8c37`
  - `make kernelversion` → `7.3.0-rc4`
  - Makefile: VERSION=7 PATCHLEVEL=3 SUBLEVEL=0 EXTRAVERSION=-rc4
  - File and functions exist. Pre-patch form was `static void
    tpg_fill_plane_*`. TPG present since 2016 (`e07d46e7e0da8` is an
    ancestor).
  - `git merge-base --is-ancestor c49cdaafa443c HEAD` is true (commit is
    in this development tree). That is **not** treated as “already
    selected for stable”.

**Step 6.2: Backport difficulty**
- Record: Clean apply on this tree. Only the two `static void`
  prototypes change. `noinline_for_stack` exists.

**Step 6.3: Related fixes already here**
- Record: No earlier equivalent TPG stack workaround. `1a03f91c2c241` is
  a similar vivid kthread workaround from 2019, different file/function.

## Phase 7: Subsystem context

**Step 7.1**
- Record: Subsystem `drivers/media/common/v4l2-tpg` (V4L2 test pattern
  generator). **PERIPHERAL** — only vivid/vimc/visl test drivers. Not
  mm/fs/net core.

**Step 7.2**
- Record: Mature (2015–2016), occasional format additions. Not a high-
  churn core path.

## Phase 8: Impact and risk

**Step 8.1: Who is affected**
- Record: Config-specific: `CONFIG_VIDEO_V4L2_TPG` via vivid/vimc/visl,
  plus clang-22, KASAN, `-Werror`, and `CONFIG_FRAME_WARN=1536` (error
  text). Default 64-bit `FRAME_WARN` is **2048** (`lib/Kconfig.debug`);
  1560 < 2048, so **default s390 64-bit allmodconfig would not fail**.
  1536 is the 32-bit Xtensa default, or a non-default int in
  randconfig/custom CI.

**Step 8.2: Trigger**
- Record: Building that file with that toolchain/config. Not a runtime
  trigger. Unprivileged users cannot “hit” it except as a failed kernel
  build.

**Step 8.3: Failure mode**
- Record: Compile error under `-Werror` (WERROR defaults to
  COMPILE_TEST). Runtime stack on s390 is 16KiB, 64KiB with KASAN
  (`arch/s390/Makefile`); 1560 bytes is not a runtime overflow.
  Severity: **MEDIUM for CI/debug builds with a lowered FRAME_WARN; LOW
  for production stable users.**

**Step 8.4: Risk-benefit**
- Record:
  - Benefit: unblocks clang+KASAN+Werror builds of TPG/vivid; tiny
    annotation.
  - Risk: very low (2 annotations, no behavior change).
  - Ratio: favorable **if** treated as a build fix; modest user benefit
    because the default 64-bit limit is 2048.

## Phase 9: Synthesis

**Step 9.1: Evidence**

FOR:
- Official `stable-kernel-rules.rst` lists **build error** (not
  CONFIG_BROKEN).
- Build-fix exception in the evaluation rubric.
- 8/6-line, obviously correct `noinline_for_stack` — the kernel’s
  standard answer to clang+KASAN frame-size errors.
- Author Arnd Bergmann; applied by Hans Verkuil; LLVM Linux people on
  Cc.
- Helpers and macro exist in this 7.3-rc4 tree; applies cleanly; no
  series deps.
- Similar media workarounds have been used for years.

AGAINST:
- Not a crash, UAF, deadlock, corruption, or security bug.
- Author: clang problem, not a logic bug.
- Only vivid/vimc/visl (test drivers, “When in doubt, say N”).
- Reproduced with FRAME_WARN **1536**; 64-bit default is **2048**, so
  typical s390 KASAN allmodconfig may not fail.
- clang-22 + s390 + KASAN is a narrow toolchain.
- No stable nomination, no user reports, v1 with no review discussion.

UNRESOLVED:
- Whether default `FRAME_WARN=2048` allmodconfig on this tree fails with
  clang-22+KASAN (reported size 1560 suggests no).
- Whether 32-bit clang+KASAN exceeds the 1280 default (not claimed;
  unverified).
- Whether stable@ ever discussed this (lore 403).

**Step 9.2: Stable rules checklist**
1. Obviously correct and tested? **PASS** — two `noinline_for_stack`
   marks; Arnd built it; maintainer applied v1.
2. Real bug that affects users? **PASS** as a **build error** for the
   configs that hit it; **weak** for production runtime users.
3. Important (crash/security/corruption/deadlock)? **PASS only via the
   documented build-error clause**, not via runtime severity. Frame 1560
   vs 1536 is a warning-as-error, not an oops.
4. Small and contained? **PASS** — one file, ~14-line diff, well under
   100 lines.
5. No new features/APIs? **PASS**
6. Can apply to this tree? **PASS** — file, functions, and
   `noinline_for_stack` are all here.

**Step 9.3: Exception category**
- Record: **Build fix** (compilation error/warning under `-Werror`). Not
  a device-ID, quirk, DT, or docs exception.

**Step 9.4: Decision**

This tree is **Linux 7.3-rc4** (mainline). The TPG helpers are present;
the patch is self-contained and matches the code here.

It is not a runtime stability fix. It is the documented class of **build
error** that stable rules allow: clang-22 + KASAN inlines two large
`static` helpers into `tpg_fill_plane_buffer()` until `-Wframe-larger-
than` fails with `-Werror`. The change is two `noinline_for_stack`
annotations, no semantic change, negligible regression risk.

That is enough for this tree: the affected code exists, the workaround
is the usual one, and blocking KASAN/clang builds of `VIDEO_V4L2_TPG` is
a real compile failure even though vivid is a test driver.

## What the commit solves for this tree

`tpg_fill_plane_buffer()` grows a 1560-byte frame when clang-22+KASAN
inlines `tpg_fill_plane_extras()` and `tpg_fill_plane_pattern()`. With
`CONFIG_FRAME_WARN=1536` and `CONFIG_WERROR`, the build dies. Forcing
those callees out of line removes the spill storm. Stable users who
build this kernel with clang+KASAN+Werror (CI, debug kernels) need that
to compile; production runtime behavior is unchanged.

## Risk vs benefit

Benefit is restoring those builds; risk is two extra calls in a test-
pattern path. The FRAME_WARN=1536 vs default 2048 gap means default
64-bit configs may already pass, but the official build-error rule still
covers the failure Arnd hit, and the patch is too small to justify
withholding it.

## Verification
- [Phase 1] Parsed message/tags: Arnd + Hans SOB only; no
  Fixes/Reported-by/Link/Cc:stable
- [Phase 2] `git show c49cdaafa443c --stat`: 1 file, +8/-6; only two
  function signatures
- [Phase 2] Read `v4l2-tpg-core.c` ~2350–2712: loop still calls both
  helpers; no logic change
- [Phase 2] `noinline_for_stack` is `#define noinline` in
  `include/linux/compiler_types.h:264`
- [Phase 3] `git blame` on the annotations: `c49cdaafa443c`; older
  `static void` from 2015 vivid TPG
- [Phase 3] Origin `e07d46e7e0da8` (2016) is an ancestor of HEAD
- [Phase 3] No Fixes: tag to follow
- [Phase 3] `git log --oneline -20 --
  drivers/media/common/v4l2-tpg/v4l2-tpg-core.c`: no prerequisite series
- [Phase 4] `b4 dig -c c49cdaafa443c`: lore msgid
  `20260618143252.1885475-1-arnd@kernel.org`
- [Phase 4] `b4 dig -a`: v1 only
- [Phase 4] `b4 dig -w`: media + LLVM maintainers Cc’d
- [Phase 4] `b4 dig -m /tmp/tpg-thread.mbox`: patch + LLVM-bug offer; no
  replies
- [Phase 4] WebFetch lore/stable: 403 — UNVERIFIED stable-list history
- [Phase 5] `git grep tpg_fill_plane_buffer`: vivid, vimc, visl only
- [Phase 5] No semcode MCP; used grep/read
- [Phase 6] `git describe HEAD` / `make kernelversion`: v7.3-rc4 /
  7.3.0-rc4
- [Phase 6] `git merge-base --is-ancestor c49cdaafa443c HEAD`: yes
  (original commit in this tree; not used as circular “already
  selected”)
- [Phase 6] Parent blobs still have `static void
  tpg_fill_plane_extras/pattern`
- [Phase 7] Kconfig: `VIDEO_V4L2_TPG` tristate selected by
  vivid/vimc/visl test drivers
- [Phase 8] `lib/Kconfig.debug`: FRAME_WARN default 2048 if 64BIT, 1536
  only if !64BIT && XTENSA; s390 `STACK_SIZE` 16K/64K with KASAN
- [Phase 8] `init/Kconfig`: WERROR default COMPILE_TEST
- UNVERIFIED: allmodconfig with default FRAME_WARN=2048 on clang-22 s390
  KASAN (1560 suggests it would pass)
- UNVERIFIED: 32-bit clang KASAN frame size vs 1280 default

**YES**

 drivers/media/common/v4l2-tpg/v4l2-tpg-core.c | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c
index 931e5dc453b90..e1d5c220f7381 100644
--- a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c
+++ b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c
@@ -2346,9 +2346,11 @@ static void tpg_fill_params_extras(const struct tpg_data *tpg,
 			(params->is_60hz ? V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM);
 }
 
-static void tpg_fill_plane_extras(const struct tpg_data *tpg,
-				  const struct tpg_draw_params *params,
-				  unsigned p, unsigned h, u8 *vbuf)
+/* noinline to work around clang KASAN issues */
+static noinline_for_stack void
+tpg_fill_plane_extras(const struct tpg_data *tpg,
+		      const struct tpg_draw_params *params,
+		      unsigned p, unsigned h, u8 *vbuf)
 {
 	unsigned twopixsize = params->twopixsize;
 	unsigned img_width = params->img_width;
@@ -2483,9 +2485,9 @@ static void tpg_fill_plane_extras(const struct tpg_data *tpg,
 	}
 }
 
-static void tpg_fill_plane_pattern(const struct tpg_data *tpg,
-				   const struct tpg_draw_params *params,
-				   unsigned p, unsigned h, u8 *vbuf)
+static noinline_for_stack void
+tpg_fill_plane_pattern(const struct tpg_data *tpg, const struct tpg_draw_params *params,
+		       unsigned p, unsigned h, u8 *vbuf)
 {
 	unsigned twopixsize = params->twopixsize;
 	unsigned img_width = params->img_width;
-- 
2.53.0


  parent reply	other threads:[~2026-10-19 14:03 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <20261019135441.1420968-1-sashal@kernel.org>
2026-10-19 13:46 ` [PATCH AUTOSEL 6.18-5.10] media: em28xx: use vb2_video_unregister_device Sasha Levin
2026-10-19 13:46 ` [PATCH AUTOSEL 6.18-5.10] media: em28xx: requeue buffers if start_streaming fails Sasha Levin
2026-10-19 13:47 ` [PATCH AUTOSEL 6.18-5.10] media: cec: tegra_cec: don't break off msg on NACK Sasha Levin
2026-10-19 13:47 ` [PATCH AUTOSEL 6.18-5.10] media: dvb-core: fix feed leak on failed DMX_ADD_PID Sasha Levin
2026-10-19 13:47 ` [PATCH AUTOSEL 6.18-5.10] media: go7007: s2250: propagate control I/O failures Sasha Levin
2026-10-19 13:47 ` [PATCH AUTOSEL 6.18-5.10] media: ivtv: stop VBI start-code scan before short tail Sasha Levin
2026-10-19 13:49 ` [PATCH AUTOSEL 6.18-5.10] media: go7007: avoid undefined shifts in MPEG-4 headers Sasha Levin
2026-10-19 13:49 ` [PATCH AUTOSEL 6.18-5.10] media: cx88: fix memory leak in cx8802_register_driver() error path Sasha Levin
2026-10-19 13:49 ` [PATCH AUTOSEL 6.18-5.10] media: cec: tegra: add missing MODULE_DEVICE_TABLE() Sasha Levin
2026-10-19 13:50 ` [PATCH AUTOSEL 6.18-5.10] media: cec: stm32: return an error when log-address wait times out Sasha Levin
2026-10-19 13:50 ` Sasha Levin [this message]
2026-10-19 13:51 ` [PATCH AUTOSEL 6.18-5.10] media: cx18: stop VBI start-code scan before short tail Sasha Levin
2026-10-19 13:51 ` [PATCH AUTOSEL 6.18-5.15] media: i2c: ov8865: Program the sensor on stream start Sasha Levin
2026-10-19 13:52 ` [PATCH AUTOSEL 6.18-5.10] media: cec/core: drop cec_post_state_event call Sasha Levin
2026-10-19 13:52 ` [PATCH AUTOSEL 6.18-5.10] media: em28xx: dev_info->pr_info since dev has been freed Sasha Levin
2026-10-19 13:53 ` [PATCH AUTOSEL 6.18-5.15] media: i2c: ov8865: Drop the runtime PM usage count on stream failure Sasha Levin

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261019135441.1420968-354-sashal@kernel.org \
    --to=sashal@kernel.org \
    --cc=arnd@arndb.de \
    --cc=hverkuil+cisco@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-media@vger.kernel.org \
    --cc=mchehab@kernel.org \
    --cc=patches@lists.linux.dev \
    --cc=stable@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox