* [PATCH] drm/edid: reduce update_display_info() stack usage
@ 2026-10-13 20:51 Arnd Bergmann
2026-10-19 13:28 ` Jani Nikula
0 siblings, 1 reply; 7+ messages in thread
From: Arnd Bergmann @ 2026-10-13 20:51 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter
Cc: Arnd Bergmann, Mario Limonciello (AMD),
Chenyu Chen, Jani Nikula, Alex Deucher, Harry Wentland,
dri-devel, linux-kernel
From: Arnd Bergmann <arnd@arndb.de>
The drm_parse_cea_ext() calls into nine individual parser functions
based on the data format. If all of those get inlined and KASAN_STACK
is enabled, this can explode the combined stack usage beyond a
reasonable amount:
drivers/gpu/drm/drm_edid.c: In function 'update_display_info':
drivers/gpu/drm/drm_edid.c:7040:1: error: the frame size of 1888 bytes is larger than 1536 bytes [-Werror=frame-larger-than=]
7040 | }
| ^
Mark all of the individual parser functions as noinline_for_stack
to avoid this and keep their stack frames separate. This reduces
the stack usage for update_display_info/drm_parse_cea_ext to
a more manageable 744 bytes, while each parser only adds at most
200 bytes on top.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
drivers/gpu/drm/drm_edid.c | 31 +++++++++++++++++--------------
1 file changed, 17 insertions(+), 14 deletions(-)
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 3148038747b6..913a8bbe8894 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -5341,8 +5341,9 @@ static int edid_hfeeodb_extension_block_count(const struct edid *edid)
* etc). For example, if the bit 0 in bitmap is set, first mode in VDB can
* support YCBCR420 output too.
*/
-static void parse_cta_y420cmdb(struct drm_connector *connector,
- const struct cea_db *db, u64 *y420cmdb_map)
+static noinline_for_stack void
+parse_cta_y420cmdb(struct drm_connector *connector, const struct cea_db *db,
+ u64 *y420cmdb_map)
{
struct drm_display_info *info = &connector->display_info;
int i, map_len = cea_db_payload_len(db) - 1;
@@ -5515,7 +5516,7 @@ static uint8_t hdr_metadata_type(const u8 *edid_ext)
BIT(HDMI_STATIC_METADATA_TYPE1);
}
-static void
+static noinline_for_stack void
drm_parse_hdr_metadata_block(struct drm_connector *connector, const u8 *db)
{
struct hdr_static_metadata *hdr_metadata =
@@ -6070,7 +6071,8 @@ drm_default_rgb_quant_range(const struct drm_display_mode *mode)
EXPORT_SYMBOL(drm_default_rgb_quant_range);
/* CTA-861 Video Data Block (CTA VDB) */
-static void parse_cta_vdb(struct drm_connector *connector, const struct cea_db *db)
+static noinline_for_stack void
+parse_cta_vdb(struct drm_connector *connector, const struct cea_db *db)
{
struct drm_display_info *info = &connector->display_info;
int i, vic_index, len = cea_db_payload_len(db);
@@ -6136,8 +6138,8 @@ static bool cta_vdb_has_vic(const struct drm_connector *connector, u8 vic)
}
/* CTA-861-H YCbCr 4:2:0 Video Data Block (CTA Y420VDB) */
-static void parse_cta_y420vdb(struct drm_connector *connector,
- const struct cea_db *db)
+static noinline_for_stack void
+parse_cta_y420vdb(struct drm_connector *connector, const struct cea_db *db)
{
struct drm_display_info *info = &connector->display_info;
struct drm_hdmi_info *hdmi = &info->hdmi;
@@ -6155,7 +6157,8 @@ static void parse_cta_y420vdb(struct drm_connector *connector,
}
}
-static void drm_parse_vcdb(struct drm_connector *connector, const u8 *db)
+static noinline_for_stack void
+drm_parse_vcdb(struct drm_connector *connector, const u8 *db)
{
struct drm_display_info *info = &connector->display_info;
@@ -6310,8 +6313,8 @@ static void drm_parse_dsc_info(struct drm_hdmi_dsc_cap *hdmi_dsc,
}
/* Sink Capability Data Structure */
-static void drm_parse_hdmi_forum_scds(struct drm_connector *connector,
- const u8 *hf_scds)
+static noinline_for_stack void
+drm_parse_hdmi_forum_scds(struct drm_connector *connector, const u8 *hf_scds)
{
struct drm_display_info *info = &connector->display_info;
struct drm_hdmi_info *hdmi = &info->hdmi;
@@ -6451,7 +6454,7 @@ static void drm_parse_hdmi_deep_color_info(struct drm_connector *connector,
}
/* HDMI Vendor-Specific Data Block (HDMI VSDB, H14b-VSDB) */
-static void
+static noinline_for_stack void
drm_parse_hdmi_vsdb_video(struct drm_connector *connector, const u8 *db)
{
struct drm_display_info *info = &connector->display_info;
@@ -6486,8 +6489,8 @@ drm_parse_hdmi_vsdb_video(struct drm_connector *connector, const u8 *db)
* See EDID extension for head-mounted and specialized monitors, specified at:
* https://docs.microsoft.com/en-us/windows-hardware/drivers/display/specialized-monitors-edid-extension
*/
-static void drm_parse_microsoft_vsdb(struct drm_connector *connector,
- const u8 *db)
+static noinline_for_stack void
+drm_parse_microsoft_vsdb(struct drm_connector *connector, const u8 *db)
{
struct drm_display_info *info = &connector->display_info;
u8 version = db[4];
@@ -6558,8 +6561,8 @@ static void drm_parse_amd_vsdb_v3(struct drm_display_info *info,
info->amd_vsdb.max_frame_rate = max_frame_rate;
}
-static void drm_parse_amd_vsdb(struct drm_connector *connector,
- const struct cea_db *db)
+static noinline_for_stack void
+drm_parse_amd_vsdb(struct drm_connector *connector, const struct cea_db *db)
{
struct drm_display_info *info = &connector->display_info;
const u8 *data = cea_db_data(db);
--
2.53.0
^ permalink raw reply [flat|nested] 7+ messages in thread* Re: [PATCH] drm/edid: reduce update_display_info() stack usage
2026-10-13 20:51 [PATCH] drm/edid: reduce update_display_info() stack usage Arnd Bergmann
@ 2026-10-19 13:28 ` Jani Nikula
2026-10-19 16:15 ` Arnd Bergmann
0 siblings, 1 reply; 7+ messages in thread
From: Jani Nikula @ 2026-10-19 13:28 UTC (permalink / raw)
To: Arnd Bergmann, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter
Cc: Arnd Bergmann, Mario Limonciello (AMD),
Chenyu Chen, Alex Deucher, Harry Wentland, dri-devel,
linux-kernel
On Tue, 13 Oct 2026, Arnd Bergmann <arnd@kernel.org> wrote:
> From: Arnd Bergmann <arnd@arndb.de>
>
> The drm_parse_cea_ext() calls into nine individual parser functions
> based on the data format. If all of those get inlined and KASAN_STACK
> is enabled, this can explode the combined stack usage beyond a
> reasonable amount:
>
> drivers/gpu/drm/drm_edid.c: In function 'update_display_info':
> drivers/gpu/drm/drm_edid.c:7040:1: error: the frame size of 1888 bytes is larger than 1536 bytes [-Werror=frame-larger-than=]
> 7040 | }
> | ^
>
> Mark all of the individual parser functions as noinline_for_stack
> to avoid this and keep their stack frames separate. This reduces
> the stack usage for update_display_info/drm_parse_cea_ext to
> a more manageable 744 bytes, while each parser only adds at most
> 200 bytes on top.
Is there really no way to tell the compiler to not do silly things in a
more generic way?
BR,
Jani.
>
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> ---
> drivers/gpu/drm/drm_edid.c | 31 +++++++++++++++++--------------
> 1 file changed, 17 insertions(+), 14 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
> index 3148038747b6..913a8bbe8894 100644
> --- a/drivers/gpu/drm/drm_edid.c
> +++ b/drivers/gpu/drm/drm_edid.c
> @@ -5341,8 +5341,9 @@ static int edid_hfeeodb_extension_block_count(const struct edid *edid)
> * etc). For example, if the bit 0 in bitmap is set, first mode in VDB can
> * support YCBCR420 output too.
> */
> -static void parse_cta_y420cmdb(struct drm_connector *connector,
> - const struct cea_db *db, u64 *y420cmdb_map)
> +static noinline_for_stack void
> +parse_cta_y420cmdb(struct drm_connector *connector, const struct cea_db *db,
> + u64 *y420cmdb_map)
> {
> struct drm_display_info *info = &connector->display_info;
> int i, map_len = cea_db_payload_len(db) - 1;
> @@ -5515,7 +5516,7 @@ static uint8_t hdr_metadata_type(const u8 *edid_ext)
> BIT(HDMI_STATIC_METADATA_TYPE1);
> }
>
> -static void
> +static noinline_for_stack void
> drm_parse_hdr_metadata_block(struct drm_connector *connector, const u8 *db)
> {
> struct hdr_static_metadata *hdr_metadata =
> @@ -6070,7 +6071,8 @@ drm_default_rgb_quant_range(const struct drm_display_mode *mode)
> EXPORT_SYMBOL(drm_default_rgb_quant_range);
>
> /* CTA-861 Video Data Block (CTA VDB) */
> -static void parse_cta_vdb(struct drm_connector *connector, const struct cea_db *db)
> +static noinline_for_stack void
> +parse_cta_vdb(struct drm_connector *connector, const struct cea_db *db)
> {
> struct drm_display_info *info = &connector->display_info;
> int i, vic_index, len = cea_db_payload_len(db);
> @@ -6136,8 +6138,8 @@ static bool cta_vdb_has_vic(const struct drm_connector *connector, u8 vic)
> }
>
> /* CTA-861-H YCbCr 4:2:0 Video Data Block (CTA Y420VDB) */
> -static void parse_cta_y420vdb(struct drm_connector *connector,
> - const struct cea_db *db)
> +static noinline_for_stack void
> +parse_cta_y420vdb(struct drm_connector *connector, const struct cea_db *db)
> {
> struct drm_display_info *info = &connector->display_info;
> struct drm_hdmi_info *hdmi = &info->hdmi;
> @@ -6155,7 +6157,8 @@ static void parse_cta_y420vdb(struct drm_connector *connector,
> }
> }
>
> -static void drm_parse_vcdb(struct drm_connector *connector, const u8 *db)
> +static noinline_for_stack void
> +drm_parse_vcdb(struct drm_connector *connector, const u8 *db)
> {
> struct drm_display_info *info = &connector->display_info;
>
> @@ -6310,8 +6313,8 @@ static void drm_parse_dsc_info(struct drm_hdmi_dsc_cap *hdmi_dsc,
> }
>
> /* Sink Capability Data Structure */
> -static void drm_parse_hdmi_forum_scds(struct drm_connector *connector,
> - const u8 *hf_scds)
> +static noinline_for_stack void
> +drm_parse_hdmi_forum_scds(struct drm_connector *connector, const u8 *hf_scds)
> {
> struct drm_display_info *info = &connector->display_info;
> struct drm_hdmi_info *hdmi = &info->hdmi;
> @@ -6451,7 +6454,7 @@ static void drm_parse_hdmi_deep_color_info(struct drm_connector *connector,
> }
>
> /* HDMI Vendor-Specific Data Block (HDMI VSDB, H14b-VSDB) */
> -static void
> +static noinline_for_stack void
> drm_parse_hdmi_vsdb_video(struct drm_connector *connector, const u8 *db)
> {
> struct drm_display_info *info = &connector->display_info;
> @@ -6486,8 +6489,8 @@ drm_parse_hdmi_vsdb_video(struct drm_connector *connector, const u8 *db)
> * See EDID extension for head-mounted and specialized monitors, specified at:
> * https://docs.microsoft.com/en-us/windows-hardware/drivers/display/specialized-monitors-edid-extension
> */
> -static void drm_parse_microsoft_vsdb(struct drm_connector *connector,
> - const u8 *db)
> +static noinline_for_stack void
> +drm_parse_microsoft_vsdb(struct drm_connector *connector, const u8 *db)
> {
> struct drm_display_info *info = &connector->display_info;
> u8 version = db[4];
> @@ -6558,8 +6561,8 @@ static void drm_parse_amd_vsdb_v3(struct drm_display_info *info,
> info->amd_vsdb.max_frame_rate = max_frame_rate;
> }
>
> -static void drm_parse_amd_vsdb(struct drm_connector *connector,
> - const struct cea_db *db)
> +static noinline_for_stack void
> +drm_parse_amd_vsdb(struct drm_connector *connector, const struct cea_db *db)
> {
> struct drm_display_info *info = &connector->display_info;
> const u8 *data = cea_db_data(db);
--
Jani Nikula, Intel
^ permalink raw reply [flat|nested] 7+ messages in thread* Re: [PATCH] drm/edid: reduce update_display_info() stack usage
2026-10-19 13:28 ` Jani Nikula
@ 2026-10-19 16:15 ` Arnd Bergmann
2026-10-22 11:37 ` Jani Nikula
0 siblings, 1 reply; 7+ messages in thread
From: Arnd Bergmann @ 2026-10-19 16:15 UTC (permalink / raw)
To: Jani Nikula, Arnd Bergmann, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, Dave Airlie, Simona Vetter
Cc: Mario Limonciello (AMD),
Chenyu Chen, Alex Deucher, Harry Wentland, dri-devel,
linux-kernel
On Mon, Oct 19, 2026, at 15:28, Jani Nikula wrote:
> On Tue, 13 Oct 2026, Arnd Bergmann <arnd@kernel.org> wrote:
>> From: Arnd Bergmann <arnd@arndb.de>
>>
>> The drm_parse_cea_ext() calls into nine individual parser functions
>> based on the data format. If all of those get inlined and KASAN_STACK
>> is enabled, this can explode the combined stack usage beyond a
>> reasonable amount:
>>
>> drivers/gpu/drm/drm_edid.c: In function 'update_display_info':
>> drivers/gpu/drm/drm_edid.c:7040:1: error: the frame size of 1888 bytes is larger than 1536 bytes [-Werror=frame-larger-than=]
>> 7040 | }
>> | ^
>>
>> Mark all of the individual parser functions as noinline_for_stack
>> to avoid this and keep their stack frames separate. This reduces
>> the stack usage for update_display_info/drm_parse_cea_ext to
>> a more manageable 744 bytes, while each parser only adds at most
>> 200 bytes on top.
>
> Is there really no way to tell the compiler to not do silly things in a
> more generic way?
The problem is really the sanitizers here, which turn off the
optimizations that gcc relies on for its normal behavior and
which cause additional register pressure for the inserted function
calls.
Arnd
^ permalink raw reply [flat|nested] 7+ messages in thread* Re: [PATCH] drm/edid: reduce update_display_info() stack usage
2026-10-19 16:15 ` Arnd Bergmann
@ 2026-10-22 11:37 ` Jani Nikula
2026-10-22 16:02 ` Alexander Potapenko
0 siblings, 1 reply; 7+ messages in thread
From: Jani Nikula @ 2026-10-22 11:37 UTC (permalink / raw)
To: Arnd Bergmann, Arnd Bergmann, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, Dave Airlie, Simona Vetter
Cc: Mario Limonciello (AMD),
Chenyu Chen, Alex Deucher, Harry Wentland, dri-devel,
linux-kernel, Andrey Ryabinin, Alexander Potapenko,
Dmitry Vyukov, Vincenzo Frascino, kasan-dev
On Mon, 19 Oct 2026, "Arnd Bergmann" <arnd@arndb.de> wrote:
> On Mon, Oct 19, 2026, at 15:28, Jani Nikula wrote:
>> On Tue, 13 Oct 2026, Arnd Bergmann <arnd@kernel.org> wrote:
>>> From: Arnd Bergmann <arnd@arndb.de>
>>>
>>> The drm_parse_cea_ext() calls into nine individual parser functions
>>> based on the data format. If all of those get inlined and KASAN_STACK
>>> is enabled, this can explode the combined stack usage beyond a
>>> reasonable amount:
>>>
>>> drivers/gpu/drm/drm_edid.c: In function 'update_display_info':
>>> drivers/gpu/drm/drm_edid.c:7040:1: error: the frame size of 1888 bytes is larger than 1536 bytes [-Werror=frame-larger-than=]
>>> 7040 | }
>>> | ^
>>>
>>> Mark all of the individual parser functions as noinline_for_stack
>>> to avoid this and keep their stack frames separate. This reduces
>>> the stack usage for update_display_info/drm_parse_cea_ext to
>>> a more manageable 744 bytes, while each parser only adds at most
>>> 200 bytes on top.
>>
>> Is there really no way to tell the compiler to not do silly things in a
>> more generic way?
>
> The problem is really the sanitizers here, which turn off the
> optimizations that gcc relies on for its normal behavior and
> which cause additional register pressure for the inserted function
> calls.
Cc: a bunch of KASAN folks.
I think it's really silly and ugly to have to sprinkle
noinline_for_stack all over the place in pretty normal code [1]. The
stack usage for each individual function is fairly small.
BR,
Jani.
[1] https://lore.kernel.org/r/20261013205223.2396822-1-arnd@kernel.org
--
Jani Nikula, Intel
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] drm/edid: reduce update_display_info() stack usage
2026-10-22 11:37 ` Jani Nikula
@ 2026-10-22 16:02 ` Alexander Potapenko
2026-10-22 16:14 ` Alexander Potapenko
2026-10-22 18:16 ` Arnd Bergmann
0 siblings, 2 replies; 7+ messages in thread
From: Alexander Potapenko @ 2026-10-22 16:02 UTC (permalink / raw)
To: Jani Nikula
Cc: Arnd Bergmann, Arnd Bergmann, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, Dave Airlie, Simona Vetter,
Mario Limonciello (AMD),
Chenyu Chen, Alex Deucher, Harry Wentland, dri-devel,
linux-kernel, Andrey Ryabinin, Dmitry Vyukov, Vincenzo Frascino,
kasan-dev
On Thu, Oct 22, 2026 at 1:37 PM Jani Nikula <jani.nikula@intel.com> wrote:
>
> On Mon, 19 Oct 2026, "Arnd Bergmann" <arnd@arndb.de> wrote:
> > On Mon, Oct 19, 2026, at 15:28, Jani Nikula wrote:
> >> On Tue, 13 Oct 2026, Arnd Bergmann <arnd@kernel.org> wrote:
> >>> From: Arnd Bergmann <arnd@arndb.de>
> >>>
> >>> The drm_parse_cea_ext() calls into nine individual parser functions
> >>> based on the data format. If all of those get inlined and KASAN_STACK
> >>> is enabled, this can explode the combined stack usage beyond a
> >>> reasonable amount:
> >>>
> >>> drivers/gpu/drm/drm_edid.c: In function 'update_display_info':
> >>> drivers/gpu/drm/drm_edid.c:7040:1: error: the frame size of 1888 bytes is larger than 1536 bytes [-Werror=frame-larger-than=]
> >>> 7040 | }
> >>> | ^
> >>>
> >>> Mark all of the individual parser functions as noinline_for_stack
> >>> to avoid this and keep their stack frames separate. This reduces
> >>> the stack usage for update_display_info/drm_parse_cea_ext to
> >>> a more manageable 744 bytes, while each parser only adds at most
> >>> 200 bytes on top.
> >>
> >> Is there really no way to tell the compiler to not do silly things in a
> >> more generic way?
> >
> > The problem is really the sanitizers here, which turn off the
> > optimizations that gcc relies on for its normal behavior and
> > which cause additional register pressure for the inserted function
> > calls.
>
> Cc: a bunch of KASAN folks.
>
> I think it's really silly and ugly to have to sprinkle
> noinline_for_stack all over the place in pretty normal code [1]. The
> stack usage for each individual function is fairly small.
>
Together with my LLM friend, I did some digging to see whether this
can be handled on the compiler side instead. Summary of what we found
(x86_64 defconfig + KASAN_STACK,
GCC 15.2 and Clang 21, -fstack-usage on every object):
1. The immediate cause here is that GCC's inliner has no idea what the
frame will cost under KASAN. Its stack estimate for a callee only
sums the raw sizes of address-taken locals, so it never includes
the ASan redzones and never sees the register spills that
instrumentation causes. For all nine parsers in drm_parse_cea_ext()
the estimate is literally 0 bytes, which short-circuits the
-fconserve-stack limits, and since each parser has a single caller,
-finline-functions-called-once inlines them regardless of size.
2. A generic knob therefore exists: passing
-fno-inline-functions-called-once under CONFIG_KASAN_STACK with GCC
brings update_display_info() from 704 to 344 bytes here without
touching the source (drm_parse_cea_ext stays a separate 368-byte
frame). Kernel-wide on that config it removes 22 of the 103 frames
above 1024 bytes and introduces 6 new ones, for +1.2% text.
3. The GCC estimate itself is also fixable (make account_stack_vars()
add the redzones it is going to allocate anyway, ~30 lines in
cfgexpand.cc). That reduces total KASAN stack usage by ~7% for
+0.35% text and fixes this particular case on its own (704 -> 368),
so it is probably worth upstreaming. But it is a correctness fix, not a
cure: it doesn't change the number of frames above 1024/2048 at all.
4. The reason is that the big frames under KASAN are overwhelmingly
functions that already have 0.5-1.5KB of genuine locals without
KASAN (97 of the 103 above 1024 bytes); KASAN then multiplies them
by 1.5x (median) to 2.3x (p90) through redzones and spills. No
inlining heuristic can undo that, and this is inherent in how the
stack instrumentation works. So for KASAN_STACK builds we think
FRAME_WARN simply has to be higher than for regular builds. For
what it's worth, Clang does worse on the same config
(149 frames above 1024 vs. 103 for GCC, 1176 bytes for
update_display_info), which is why KASAN_STACK is already off by
default there.
Arnd, one thing I could not do is reproduce the 1888 bytes: with
linux-next's drm_edid.c the worst we get is 704 on x86_64, 752 on
arm64 and 1264 on arm64 with PROFILE_ALL_BRANCHES. Could you share
the .config and GCC version?
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] drm/edid: reduce update_display_info() stack usage
2026-10-22 16:02 ` Alexander Potapenko
@ 2026-10-22 16:14 ` Alexander Potapenko
2026-10-22 18:16 ` Arnd Bergmann
1 sibling, 0 replies; 7+ messages in thread
From: Alexander Potapenko @ 2026-10-22 16:14 UTC (permalink / raw)
To: Jani Nikula
Cc: Arnd Bergmann, Arnd Bergmann, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, Dave Airlie, Simona Vetter,
Mario Limonciello (AMD),
Chenyu Chen, Alex Deucher, Harry Wentland, dri-devel,
linux-kernel, Andrey Ryabinin, Dmitry Vyukov, Vincenzo Frascino,
kasan-dev
> 3. The GCC estimate itself is also fixable (make account_stack_vars()
> add the redzones it is going to allocate anyway, ~30 lines in
> cfgexpand.cc). That reduces total KASAN stack usage by ~7% for
> +0.35% text and fixes this particular case on its own (704 -> 368),
> so it is probably worth upstreaming. But it is a correctness fix, not a
> cure: it doesn't change the number of frames above 1024/2048 at all.
For what it's worth, the patch looks like this:
diff --git a/gcc/cfgexpand.cc b/gcc/cfgexpand.cc
index 0261f861b..56e335cb2 100644
--- a/gcc/cfgexpand.cc
+++ b/gcc/cfgexpand.cc
@@ -1653,12 +1653,17 @@ expand_stack_vars (bool (*pred) (unsigned),
class stack_vars_data *data)
gcc_assert (known_eq (large_alloc, large_size));
}
-/* Take into account all sizes of partitions and reset DECL_RTLs. */
+/* Take into account all sizes of partitions and reset DECL_RTLs.
+ When the stack is sanitized by ASan, account for the red zones that
+ expand_stack_vars will later allocate around each protected variable,
+ so that the inliner's stack size estimate is not wildly optimistic. */
static poly_uint64
account_stack_vars (void)
{
unsigned si, j, i, n = stack_vars_num;
poly_uint64 size = 0;
+ bool asan_vars = false;
+ bool asan_p = asan_sanitize_stack_p ();
for (si = 0; si < n; ++si)
{
@@ -1668,10 +1673,32 @@ account_stack_vars (void)
if (stack_vars[i].representative != i)
continue;
- size += stack_vars[i].size;
+ poly_uint64 vsize = stack_vars[i].size;
+ unsigned HOST_WIDE_INT csize;
+ if (asan_p
+ && vsize.is_constant (&csize)
+ && stack_vars[i].alignb * BITS_PER_UNIT <= MAX_SUPPORTED_STACK_ALIGNMENT)
+ {
+ bool prot = false;
+ for (j = i; j != EOC; j = stack_vars[j].next)
+ if (asan_protect_stack_decl (stack_vars[j].decl))
+ {
+ prot = true;
+ break;
+ }
+ if (prot)
+ {
+ vsize = asan_var_and_redzone_size (csize);
+ asan_vars = true;
+ }
+ }
+ size += vsize;
for (j = i; j != EOC; j = stack_vars[j].next)
set_rtl (stack_vars[j].decl, NULL);
}
+ /* Leading red zone of the ASan protected frame region. */
+ if (asan_vars)
+ size += ASAN_RED_ZONE_SIZE;
return size;
}
^ permalink raw reply [flat|nested] 7+ messages in thread* Re: [PATCH] drm/edid: reduce update_display_info() stack usage
2026-10-22 16:02 ` Alexander Potapenko
2026-10-22 16:14 ` Alexander Potapenko
@ 2026-10-22 18:16 ` Arnd Bergmann
1 sibling, 0 replies; 7+ messages in thread
From: Arnd Bergmann @ 2026-10-22 18:16 UTC (permalink / raw)
To: Alexander Potapenko, Jani Nikula
Cc: Arnd Bergmann, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, Dave Airlie, Simona Vetter,
Mario Limonciello (AMD),
Chenyu Chen, Alex Deucher, Harry Wentland, dri-devel,
linux-kernel, Andrey Ryabinin, Dmitry Vyukov, Vincenzo Frascino,
kasan-dev
[-- Attachment #1: Type: text/plain, Size: 5198 bytes --]
On Thu, Oct 22, 2026, at 18:02, Alexander Potapenko wrote:
> On Thu, Oct 22, 2026 at 1:37 PM Jani Nikula <jani.nikula@intel.com> wrote:
>> On Mon, 19 Oct 2026, "Arnd Bergmann" <arnd@arndb.de> wrote:
>> > On Mon, Oct 19, 2026, at 15:28, Jani Nikula wrote:
>> >>
>> >> Is there really no way to tell the compiler to not do silly things in a
>> >> more generic way?
>> >
>> > The problem is really the sanitizers here, which turn off the
>> > optimizations that gcc relies on for its normal behavior and
>> > which cause additional register pressure for the inserted function
>> > calls.
>>
>> Cc: a bunch of KASAN folks.
>>
>> I think it's really silly and ugly to have to sprinkle
>> noinline_for_stack all over the place in pretty normal code [1]. The
>> stack usage for each individual function is fairly small.
>
> Together with my LLM friend, I did some digging to see whether this
> can be handled on the compiler side instead. Summary of what we found
> (x86_64 defconfig + KASAN_STACK,
> GCC 15.2 and Clang 21, -fstack-usage on every object):
> 1. The immediate cause here is that GCC's inliner has no idea what the
> frame will cost under KASAN. Its stack estimate for a callee only
> sums the raw sizes of address-taken locals, so it never includes
> the ASan redzones and never sees the register spills that
> instrumentation causes. For all nine parsers in drm_parse_cea_ext()
> the estimate is literally 0 bytes, which short-circuits the
> -fconserve-stack limits, and since each parser has a single caller,
> -finline-functions-called-once inlines them regardless of size.
>
> 2. A generic knob therefore exists: passing
> -fno-inline-functions-called-once under CONFIG_KASAN_STACK with GCC
> brings update_display_info() from 704 to 344 bytes here without
> touching the source (drm_parse_cea_ext stays a separate 368-byte
> frame). Kernel-wide on that config it removes 22 of the 103 frames
> above 1024 bytes and introduces 6 new ones, for +1.2% text.
Thanks for taking a look! This bit certainly makes sense, and I
could try to see what effect -fno-inline-functions-called-once has
overall when building a lot of randconfigs with KASAN. My guess
is that it would introduce some other cases that are currently
not causing warnings, but there is a good chance that it will be
an overall win.
> 3. The GCC estimate itself is also fixable (make account_stack_vars()
> add the redzones it is going to allocate anyway, ~30 lines in
> cfgexpand.cc). That reduces total KASAN stack usage by ~7% for
> +0.35% text and fixes this particular case on its own (704 -> 368),
> so it is probably worth upstreaming. But it is a correctness fix, not a
> cure: it doesn't change the number of frames above 1024/2048 at all.
That certainly sounds useful. For my testing, I run with a heuristic
that adds sets of 256 bytes for certain features (KASAN, KASAN_STACK,
KMSAN, 64BIT, clang on ppc64, ...) to the baseline of 1024, in
order to catch as many kernel bugs from excessively large local
variables while not tripping up sanitizers too much. Any reduction
here would help reduce the warnings I see as well as the actual risk
of runtime stack overflow.
On a related note, I wonder if the size of the redzone could be
reduced for KASAN compared to userspace ASAN as the available
thread stack is much smaller. IIRC we already have rather different
calculations for the redzone between clang and gcc, so it
seems likely that we can reduce that a bit.
> 4. The reason is that the big frames under KASAN are overwhelmingly
> functions that already have 0.5-1.5KB of genuine locals without
> KASAN (97 of the 103 above 1024 bytes); KASAN then multiplies them
> by 1.5x (median) to 2.3x (p90) through redzones and spills. No
> inlining heuristic can undo that, and this is inherent in how the
> stack instrumentation works. So for KASAN_STACK builds we think
> FRAME_WARN simply has to be higher than for regular builds. For
> what it's worth, Clang does worse on the same config
> (149 frames above 1024 vs. 103 for GCC, 1176 bytes for
> update_display_info), which is why KASAN_STACK is already off by
> default there.
>
> Arnd, one thing I could not do is reproduce the 1888 bytes: with
> linux-next's drm_edid.c the worst we get is 704 on x86_64, 752 on
> arm64 and 1264 on arm64 with PROFILE_ALL_BRANCHES. Could you share
> the .config and GCC version?
The reproducer I have is for s390, I have attached the .config here.
My guess is that I could find additional reproducers but I applied
my patch locally after the first hit, which stopped me from running
into others, but there is a chance that this is just extremely
rare.
If you are interested, I can also dig out other configurations
that still have frame size warnings upstream, and configs that
trigger them. My randconfig tree still has a few dozen workaround
that never got merged. The nasty ones tend to be those that
run into spilled registers when a santizer adds not just additional
redzones and functions calls but also register pressure.
Arnd
[-- Attachment #2: 0x987E7BA6-config.gz --]
[-- Type: application/gzip, Size: 46821 bytes --]
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-10-22 18:18 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-13 20:51 [PATCH] drm/edid: reduce update_display_info() stack usage Arnd Bergmann
2026-10-19 13:28 ` Jani Nikula
2026-10-19 16:15 ` Arnd Bergmann
2026-10-22 11:37 ` Jani Nikula
2026-10-22 16:02 ` Alexander Potapenko
2026-10-22 16:14 ` Alexander Potapenko
2026-10-22 18:16 ` Arnd Bergmann
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®