From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0A124C83F10 for ; Thu, 10 Jul 2025 02:47:49 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 5FFEF6B009A; Wed, 9 Jul 2025 22:47:49 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 5B0186B009E; Wed, 9 Jul 2025 22:47:49 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 49F036B009F; Wed, 9 Jul 2025 22:47:49 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0014.hostedemail.com [216.40.44.14]) by kanga.kvack.org (Postfix) with ESMTP id 293EE6B009A for ; Wed, 9 Jul 2025 22:47:49 -0400 (EDT) Received: from smtpin05.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay05.hostedemail.com (Postfix) with ESMTP id 5C89C58B89 for ; Thu, 10 Jul 2025 02:47:48 +0000 (UTC) X-FDA: 83646819816.05.66E1800 Received: from nyc.source.kernel.org (nyc.source.kernel.org [147.75.193.91]) by imf05.hostedemail.com (Postfix) with ESMTP id 9343410000D for ; Thu, 10 Jul 2025 02:47:46 +0000 (UTC) Authentication-Results: imf05.hostedemail.com; dkim=pass header.d=kernel.org header.s=k20201202 header.b=cB5WY3uc; spf=pass (imf05.hostedemail.com: domain of alx@kernel.org designates 147.75.193.91 as permitted sender) smtp.mailfrom=alx@kernel.org; dmarc=pass (policy=quarantine) header.from=kernel.org ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1752115666; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=XVKJ35m3KfImHuLlH4xheYJc+yhuwfDBxxT7Nt0olEo=; b=AtAN0iH/pC3cdf8Yd4B9Nbw5To/y/xe4G6m5Fc18jNnf9aVNOi02Lz3KqXSQiY3W7RV/eP INzLXiYtL7y8nkjAiHYLMJu92erqPe41A/alhjsRfnuq9wVn5GxWRNxBGMNOxNaNTYwEhe 3qJFKb6KLkVppUmOJQHpCl9iZLnIf3s= ARC-Authentication-Results: i=1; imf05.hostedemail.com; dkim=pass header.d=kernel.org header.s=k20201202 header.b=cB5WY3uc; spf=pass (imf05.hostedemail.com: domain of alx@kernel.org designates 147.75.193.91 as permitted sender) smtp.mailfrom=alx@kernel.org; dmarc=pass (policy=quarantine) header.from=kernel.org ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1752115666; a=rsa-sha256; cv=none; b=TR5K7y/QRWM5E0Y9op2NDzB9yghZTStofwIsEBgX5YVMcTI24/2QPgZHF34QIzDSHEUJ+X 7KuufVRVgJayZQCC/J/yH482AE4Pl6bq7753zTlP7ak19yzWl2zRJdyloTwduwDIeqtYwu uanrXvhAibGsDapOexT4JjmnzBzLSoc= Received: from smtp.kernel.org (transwarp.subspace.kernel.org [100.75.92.58]) by nyc.source.kernel.org (Postfix) with ESMTP id 9FDC7A53248; Thu, 10 Jul 2025 02:47:45 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 7932CC4CEEF; Thu, 10 Jul 2025 02:47:36 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1752115665; bh=ftfENfePux5v2ZBwQ+7n6xEYbe0XDM+Q+cV+lEYjFms=; h=Date:From:To:Cc:Subject:References:In-Reply-To:From; b=cB5WY3uc3RCGFuh2go80JWpgxE6gZsDvnNbvC1y7CrZOIszIXUHrxlD1LGn1Ax5Kd HUwU/Uy41SH9FkwaqnsTpbNfeY8WwZiAI0LYuJ3HiL/fm+vF2BJVvNV8Quemo06A/U dZbU7XUKnXe9iKxLlx76LksMrOTTi/m9v/n51WPF34SWiM+X06xlzXPxidv7LcFtov uGXaFzf4KywJduq6dct6WGhOP+eSWPwi6QqvkgRiK9UPqfQqv3exVtkBzaFS0PzG7P zykpNlcqX/GLqQsaACFdD0p/x+daIplqgPNDCa0V4+6plbGiIRuN0Lb0WtLPuRBkX2 ajB1harIqA49Q== Date: Thu, 10 Jul 2025 04:47:33 +0200 From: Alejandro Colomar To: linux-mm@kvack.org, linux-hardening@vger.kernel.org Cc: Alejandro Colomar , Kees Cook , Christopher Bazley , shadow <~hallyn/shadow@lists.sr.ht>, linux-kernel@vger.kernel.org, Andrew Morton , kasan-dev@googlegroups.com, Dmitry Vyukov , Alexander Potapenko , Marco Elver , Christoph Lameter , David Rientjes , Vlastimil Babka , Roman Gushchin , Harry Yoo , Andrew Clayton , Rasmus Villemoes , Michal Hocko , Linus Torvalds , Al Viro , Martin Uecker , Sam James , Andrew Pinski Subject: [RFC v4 0/7] Add and use sprintf_end() instead of less ergonomic APIs Message-ID: X-Mailer: git-send-email 2.50.0 References: MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Disposition: inline In-Reply-To: X-Rspam-User: X-Stat-Signature: xs7e48rz6fteorky86h9y8jb5yq5uh7e X-Rspamd-Server: rspam12 X-Rspamd-Queue-Id: 9343410000D X-HE-Tag: 1752115666-190165 X-HE-Meta: U2FsdGVkX1+jTjmfk1sGyEto/FNF40m+cCeNJ4ToJjl1WjBwoHoMr3NjqUlcneIpuSGXkIedF7eEGyR8M8rrcdG4NZC6IGMTvGktOVymcm7lDljbnYj5dQgpYnaE5sAcmffuIH5u0rPLnmU3b5pLAjDuWvDFn5Bd0gkrw7uTKNKf3aFvHURbQ+DyjIDHCqS28EapPOsSz13i2JGtROlRXY5adGNotbjezIcrqh4K1rryxIWywsg5pBjz8qvGOAgT+qzKjifqn7pjVrczxoyxELLDFnWhYPiuDn95fbOtbF85UyjghvW9hYs6LL1+DtRzXfRjpDxOjjgrKuHwLwhOZuWFGAvF/n4jLJUHzuw5n5DfXAmylUPpGJCtfvi0FHoMTYFbuvWDHBuVt48QP9PVznYPGlW7k5XeU+k2Cxjr7DQDLEhstEEc7vkLpNqenJMVPq5y/WvbJUrDj9fM0AhS88bOFLQ/SdRHU0b9ZI28Qtc0SC8VLer9Ed9+ACt/4bUwBtfISBSwXzkEjnjpA3Fzdyuhbr1kTC3YG/bWVo88qaEgRrnAMsEABVRpUS0FfL35j6gTPVdmDaw5IQI9Wd1OT6uo7MkTAuE1U388q7l+J7mm4eXXyj+OXqQ3tN3JyILLBmm0Q83jMpClMyBwvcLV7Loxgo/4cemrKKBXzyJ9ec5vl+ZC1C/7nPd7ZcmNU+CaBva8Y4CwdDTBIi+fiq35dlrhouWoK3Mcm+OkiJ6Jc0XG9jTurU8D5XNm1cIB3MFRBU5NcZHe4wAt38uR0vpxvGYqXGxo5eLF5j8vvRiot6hiUkKGpHHOESvpO6f6cs4c3pEa53oRAvgh5tHnST8NqBQY+tJzuwtZl+/ywhlsZhxmGM90eetSYYfQv8/urjxJOcvBYUOE2eErg+dGTo6VEL0AlH7TYsOfSIy9aijz2kIe97WWzi5kcXQLcurvupUjJbjYwuuYz2bV8BMTnEA Gtc3Ce+E uwfKhqgwQXYsBxwvKTwY59SEIY8JDuwMWakKN3m1Juk0uoDZvWzaHF/q16hU2aLyHF/GKu8UlLv/MSfNTEdfXzgfxJOPNRNmX5hTh/6D0+zjS0tEBvSzV6qIFnT+k57GkHGxXBwHBBalMx7Oqka/T2kv6HHAvxj2771EoAlLx6ohX9b8Nw00qn3wXwn1RLGb9IBqFi0JLW+5Q/h+ahiMqT4A+Y9ccnDVCMY9dOjXNbUHsfJr4BUiznT6bgRSz9A6RQVSSkM9tI0p7WMiCBA1nwyOcgKEGoH1SmmZg0E9hnF0yIilTH0xou9qlIqEabA7ujqZyTOiym0UM7Cs297jT7RzWTTrLrNjIfOcM0W1dSEP42UirNbzlpz4Veuk5ghD/Vb5pZUdl/LuZ58O48tM6vj8FAZ4wKnDcMR8y4Ghdq6p3CFBCziY28FXJqL1YRqlXLmRBOJ1SlNL+4yyXqjSg3XXa10qmDpCXKdl4RuwvCJ41oUpr359fmvH2ba+1lZkRrBLB6cHJriJtHDB9ZX97tZsnBsVA1GN5IrA4UQVs1h6rrByLEusKxEW5tsv0k//CjtZ3WCNV1p65jeOoID2YYybopV7Q5tZFTt6RRRHluVbckfE0Qq+5sH1oSlW635cBaA9o/HCTCQgNTukYVCwPLq///OkJsrfvaxW0YpMhvxcUi161UOejqQvOWVrNe6ZLLtZ7dEcfXOTHywE4/z6azUPTIa5piBNmlrCkwqdOZb+/Z+jJLO1FdP7MQebyUwXGMxrBpvDGsSRZww/DLX4jTPkHWmVIc819RmyHofcx7dXkTmbZsy6Y3OHmow== X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: List-Subscribe: List-Unsubscribe: Hi, Changes in v4: - Added to global CC everyone who participated in the discussion so far. - Rename seprintf() => sprintf_end(). - Implement SPRINTF_END(). - Drop stprintf(). We don't need it as an intermediate helper. - Link to the draft of a standards proposal (which I'll paste as a reply to this mail again). - Minor fixes or updates to commit messages. - Added Marco Elver's Acked-by: tag in commit 5/7. - In stack_depot_sprint_end(), do sprintf_end(p, end, "") when nr_entries is 0, to guarantee that the string is valid if this is the first s*printf() call in a row. - Document sprintf_end() as 'string end-delimited print formatted'. This spells the letters in seprintf() for their meaning, in case anyone thinks the letters are randomly chosen. :) - Remove comment about vsnprintf(3) not failing in the kernel, after Rasmus commented this is QoI guaranteed by the kernel. Remaining questions: - There are only 3 remaining calls to snprintf(3) under mm/. They are just fine for now, which is why I didn't replace them. If anyone wants to replace them, to get rid of all snprintf(3), we could that. I think for now we can leave them, to minimize the churn. $ grep -rnI snprintf mm/ mm/hugetlb_cgroup.c:674: snprintf(buf, size, "%luGB", hsize / SZ_1G); mm/hugetlb_cgroup.c:676: snprintf(buf, size, "%luMB", hsize / SZ_1M); mm/hugetlb_cgroup.c:678: snprintf(buf, size, "%luKB", hsize / SZ_1K); - There are only 2 remaining calls to the kernel's scnprintf(). This one I would really like to get rid of. Also, those calls are quite suspicious of not being what we want. Please do have a look at them and confirm what's the appropriate behavior in the 2 cases when the string is truncated or not copied at all. That code is very scary for me to try to guess. $ grep -rnI scnprintf mm/ mm/kfence/report.c:75: int len = scnprintf(buf, sizeof(buf), "%ps", (void *)stack_entries[skipnr]); mm/kfence/kfence_test.mod.c:22: { 0x96848186, "scnprintf" }, mm/kmsan/report.c:42: len = scnprintf(buf, sizeof(buf), "%ps", Apart from two calls, I see a string literal with that name. Please let me know if I should do anything about it. I don't know what that is. - I think we should remove one error handling check in "mm/page_owner.c" (marked with an XXX comment), but I'm not 100% sure. Please confirm. Other comments: - This is still not complying to coding style. I'll keep it like that while questions remain open. - I've tested the tests under CONFIG_KFENCE_KUNIT_TEST=y, and this has no regressions at all. - With the current style of the sprintf_end() prototyope, this triggers a diagnostic due to a GCC bug: It would be interesting to ask GCC to fix that bug. (Added relevant GCC maintainers and contributors to CC in this cover letter.) Have a lovely night! Alex Alejandro Colomar (7): vsprintf: Add [v]sprintf_end() stacktrace, stackdepot: Add sprintf_end()-like variants of functions mm: Use sprintf_end() instead of less ergonomic APIs array_size.h: Add ENDOF() mm: Fix benign off-by-one bugs sprintf: Add [V]SPRINTF_END() mm: Use [V]SPRINTF_END() to avoid specifying the array size include/linux/array_size.h | 6 ++++ include/linux/sprintf.h | 6 ++++ include/linux/stackdepot.h | 13 +++++++++ include/linux/stacktrace.h | 3 ++ kernel/stacktrace.c | 28 ++++++++++++++++++ lib/stackdepot.c | 13 +++++++++ lib/vsprintf.c | 59 ++++++++++++++++++++++++++++++++++++++ mm/backing-dev.c | 2 +- mm/cma.c | 4 +-- mm/cma_debug.c | 2 +- mm/hugetlb.c | 3 +- mm/hugetlb_cgroup.c | 2 +- mm/hugetlb_cma.c | 2 +- mm/kasan/report.c | 3 +- mm/kfence/kfence_test.c | 28 +++++++++--------- mm/kmsan/kmsan_test.c | 6 ++-- mm/memblock.c | 4 +-- mm/mempolicy.c | 18 ++++++------ mm/page_owner.c | 32 +++++++++++---------- mm/percpu.c | 2 +- mm/shrinker_debug.c | 2 +- mm/slub.c | 5 ++-- mm/zswap.c | 2 +- 23 files changed, 187 insertions(+), 58 deletions(-) Range-diff against v3: 1: 64334f0b94d6 ! 1: 2c4f793de0b8 vsprintf: Add [v]seprintf(), [v]stprintf() @@ Metadata Author: Alejandro Colomar ## Commit message ## - vsprintf: Add [v]seprintf(), [v]stprintf() + vsprintf: Add [v]sprintf_end() - seprintf() - ========== - - seprintf() is a function similar to stpcpy(3) in the sense that it + sprintf_end() is a function similar to stpcpy(3) in the sense that it returns a pointer that is suitable for chaining to other copy operations. @@ Commit message It also makes error handling much easier, by reporting truncation with a null pointer, which is accepted and transparently passed down by - subsequent seprintf() calls. This results in only needing to report - errors once after a chain of seprintf() calls, unlike snprintf(3), which - requires checking after every call. + subsequent sprintf_end() calls. This results in only needing to report + errors once after a chain of sprintf_end() calls, unlike snprintf(3), + which requires checking after every call. p = buf; e = buf + countof(buf); - p = seprintf(p, e, foo); - p = seprintf(p, e, bar); + p = sprintf_end(p, e, foo); + p = sprintf_end(p, e, bar); if (p == NULL) goto trunc; @@ Commit message size = countof(buf); len += scnprintf(buf + len, size - len, foo); len += scnprintf(buf + len, size - len, bar); - if (len >= size) - goto trunc; + // No ability to check. It seems aparent that it's a more elegant approach to string catenation. - stprintf() - ========== - - stprintf() is a helper that is needed for implementing seprintf() - --although it could be open-coded within vseprintf(), of course--, but - it's also useful by itself. It has the same interface properties as - strscpy(): that is, it copies with truncation, and reports truncation - with -E2BIG. It would be useful to replace some calls to snprintf(3) - and scnprintf() which don't need chaining, and where it's simpler to - pass a size. - - It is better than plain snprintf(3), because it results in simpler error - detection (it doesn't need a check >=countof(buf), but rather <0). + These functions will soon be proposed for standardization as + [v]seprintf() into C2y, and they exist in Plan9 as seprint(2) --but the + Plan9 implementation has important bugs--. + Link: Cc: Kees Cook Cc: Christopher Bazley + Cc: Rasmus Villemoes + Cc: Marco Elver + Cc: Michal Hocko + Cc: Linus Torvalds + Cc: Al Viro Signed-off-by: Alejandro Colomar ## include/linux/sprintf.h ## -@@ include/linux/sprintf.h: __printf(2, 3) int sprintf(char *buf, const char * fmt, ...); - __printf(2, 0) int vsprintf(char *buf, const char *, va_list); - __printf(3, 4) int snprintf(char *buf, size_t size, const char *fmt, ...); +@@ include/linux/sprintf.h: __printf(3, 4) int snprintf(char *buf, size_t size, const char *fmt, ...); __printf(3, 0) int vsnprintf(char *buf, size_t size, const char *fmt, va_list args); -+__printf(3, 4) int stprintf(char *buf, size_t size, const char *fmt, ...); -+__printf(3, 0) int vstprintf(char *buf, size_t size, const char *fmt, va_list args); __printf(3, 4) int scnprintf(char *buf, size_t size, const char *fmt, ...); __printf(3, 0) int vscnprintf(char *buf, size_t size, const char *fmt, va_list args); -+__printf(3, 4) char *seprintf(char *p, const char end[0], const char *fmt, ...); -+__printf(3, 0) char *vseprintf(char *p, const char end[0], const char *fmt, va_list args); ++__printf(3, 4) char *sprintf_end(char *p, const char end[0], const char *fmt, ...); ++__printf(3, 0) char *vsprintf_end(char *p, const char end[0], const char *fmt, va_list args); __printf(2, 3) __malloc char *kasprintf(gfp_t gfp, const char *fmt, ...); __printf(2, 0) __malloc char *kvasprintf(gfp_t gfp, const char *fmt, va_list args); __printf(2, 0) const char *kvasprintf_const(gfp_t gfp, const char *fmt, va_list args); ## lib/vsprintf.c ## -@@ lib/vsprintf.c: int vsnprintf(char *buf, size_t size, const char *fmt_str, va_list args) - } - EXPORT_SYMBOL(vsnprintf); - -+/** -+ * vstprintf - Format a string and place it in a buffer -+ * @buf: The buffer to place the result into -+ * @size: The size of the buffer, including the trailing null space -+ * @fmt: The format string to use -+ * @args: Arguments for the format string -+ * -+ * The return value is the length of the new string. -+ * If the string is truncated, the function returns -E2BIG. -+ * -+ * If you're not already dealing with a va_list consider using stprintf(). -+ * -+ * See the vsnprintf() documentation for format string extensions over C99. -+ */ -+int vstprintf(char *buf, size_t size, const char *fmt, va_list args) -+{ -+ int len; -+ -+ len = vsnprintf(buf, size, fmt, args); -+ -+ // It seems the kernel's vsnprintf() doesn't fail? -+ //if (unlikely(len < 0)) -+ // return -E2BIG; -+ -+ if (unlikely(len >= size)) -+ return -E2BIG; -+ -+ return len; -+} -+EXPORT_SYMBOL(vstprintf); -+ - /** - * vscnprintf - Format a string and place it in a buffer - * @buf: The buffer to place the result into @@ lib/vsprintf.c: int vscnprintf(char *buf, size_t size, const char *fmt, va_list args) } EXPORT_SYMBOL(vscnprintf); +/** -+ * vseprintf - Format a string and place it in a buffer ++ * vsprintf_end - va_list string end-delimited print formatted + * @p: The buffer to place the result into + * @end: A pointer to one past the last character in the buffer + * @fmt: The format string to use @@ lib/vsprintf.c: int vscnprintf(char *buf, size_t size, const char *fmt, va_list + * The return value is a pointer to the trailing '\0'. + * If @p is NULL, the function returns NULL. + * If the string is truncated, the function returns NULL. -+ * -+ * If you're not already dealing with a va_list consider using seprintf(). ++ * If @end <= @p, the function returns NULL. + * + * See the vsnprintf() documentation for format string extensions over C99. + */ -+char *vseprintf(char *p, const char end[0], const char *fmt, va_list args) ++char *vsprintf_end(char *p, const char end[0], const char *fmt, va_list args) +{ + int len; ++ size_t size; + + if (unlikely(p == NULL)) + return NULL; + -+ len = vstprintf(p, end - p, fmt, args); -+ if (unlikely(len < 0)) ++ size = end - p; ++ if (WARN_ON_ONCE(size == 0 || size > INT_MAX)) ++ return NULL; ++ ++ len = vsnprintf(p, size, fmt, args); ++ if (unlikely(len >= size)) + return NULL; + + return p + len; +} -+EXPORT_SYMBOL(vseprintf); ++EXPORT_SYMBOL(vsprintf_end); + /** * snprintf - Format a string and place it in a buffer * @buf: The buffer to place the result into -@@ lib/vsprintf.c: int snprintf(char *buf, size_t size, const char *fmt, ...) - } - EXPORT_SYMBOL(snprintf); - -+/** -+ * stprintf - Format a string and place it in a buffer -+ * @buf: The buffer to place the result into -+ * @size: The size of the buffer, including the trailing null space -+ * @fmt: The format string to use -+ * @...: Arguments for the format string -+ * -+ * The return value is the length of the new string. -+ * If the string is truncated, the function returns -E2BIG. -+ */ -+ -+int stprintf(char *buf, size_t size, const char *fmt, ...) -+{ -+ va_list args; -+ int len; -+ -+ va_start(args, fmt); -+ len = vstprintf(buf, size, fmt, args); -+ va_end(args); -+ -+ return len; -+} -+EXPORT_SYMBOL(stprintf); -+ - /** - * scnprintf - Format a string and place it in a buffer - * @buf: The buffer to place the result into @@ lib/vsprintf.c: int scnprintf(char *buf, size_t size, const char *fmt, ...) } EXPORT_SYMBOL(scnprintf); +/** -+ * seprintf - Format a string and place it in a buffer ++ * sprintf_end - string end-delimited print formatted + * @p: The buffer to place the result into + * @end: A pointer to one past the last character in the buffer + * @fmt: The format string to use @@ lib/vsprintf.c: int scnprintf(char *buf, size_t size, const char *fmt, ...) + * The return value is a pointer to the trailing '\0'. + * If @buf is NULL, the function returns NULL. + * If the string is truncated, the function returns NULL. ++ * If @end <= @p, the function returns NULL. + */ + -+char *seprintf(char *p, const char end[0], const char *fmt, ...) ++char *sprintf_end(char *p, const char end[0], const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); -+ p = vseprintf(p, end, fmt, args); ++ p = vsprintf_end(p, end, fmt, args); + va_end(args); + + return p; +} -+EXPORT_SYMBOL(seprintf); ++EXPORT_SYMBOL(sprintf_end); + /** * vsprintf - Format a string and place it in a buffer 2: 9c140de9842d ! 2: 894d02b08056 stacktrace, stackdepot: Add seprintf()-like variants of functions @@ Metadata Author: Alejandro Colomar ## Commit message ## - stacktrace, stackdepot: Add seprintf()-like variants of functions - - I think there's an anomaly in stack_depot_s*print(). If we have zero - entries, we don't copy anything, which means the string is still not a - string. Normally, this function is called surrounded by other calls to - s*printf(), which guarantee that there's a '\0', but maybe we should - make sure to write a '\0' here? + stacktrace, stackdepot: Add sprintf_end()-like variants of functions Cc: Kees Cook Cc: Christopher Bazley + Cc: Rasmus Villemoes + Cc: Marco Elver + Cc: Michal Hocko + Cc: Linus Torvalds + Cc: Al Viro Signed-off-by: Alejandro Colomar ## include/linux/stackdepot.h ## @@ include/linux/stackdepot.h: void stack_depot_print(depot_stack_handle_t stack); int spaces); +/** -+ * stack_depot_seprint - Print a stack trace from stack depot into a buffer ++ * stack_depot_sprint_end - Print a stack trace from stack depot into a buffer + * + * @handle: Stack depot handle returned from stack_depot_save() + * @p: Pointer to the print buffer @@ include/linux/stackdepot.h: void stack_depot_print(depot_stack_handle_t stack); + * + * Return: Pointer to trailing '\0'; or NULL on truncation + */ -+char *stack_depot_seprint(depot_stack_handle_t handle, char *p, -+ const char end[0], int spaces); ++char *stack_depot_sprint_end(depot_stack_handle_t handle, char *p, ++ const char end[0], int spaces); + /** * stack_depot_put - Drop a reference to a stack trace from stack depot @@ include/linux/stacktrace.h: void stack_trace_print(const unsigned long *trace, u int spaces); int stack_trace_snprint(char *buf, size_t size, const unsigned long *entries, unsigned int nr_entries, int spaces); -+char *stack_trace_seprint(char *p, const char end[0], -+ const unsigned long *entries, unsigned int nr_entries, -+ int spaces); ++char *stack_trace_sprint_end(char *p, const char end[0], ++ const unsigned long *entries, ++ unsigned int nr_entries, int spaces); unsigned int stack_trace_save(unsigned long *store, unsigned int size, unsigned int skipnr); unsigned int stack_trace_save_tsk(struct task_struct *task, @@ kernel/stacktrace.c: int stack_trace_snprint(char *buf, size_t size, const unsig EXPORT_SYMBOL_GPL(stack_trace_snprint); +/** -+ * stack_trace_seprint - Print the entries in the stack trace into a buffer ++ * stack_trace_sprint_end - Print the entries in the stack trace into a buffer + * @p: Pointer to the print buffer + * @end: Pointer to one past the last element in the buffer + * @entries: Pointer to storage array @@ kernel/stacktrace.c: int stack_trace_snprint(char *buf, size_t size, const unsig + * + * Return: Pointer to the trailing '\0'; or NULL on truncation. + */ -+char *stack_trace_seprint(char *p, const char end[0], ++char *stack_trace_sprint_end(char *p, const char end[0], + const unsigned long *entries, unsigned int nr_entries, + int spaces) +{ @@ kernel/stacktrace.c: int stack_trace_snprint(char *buf, size_t size, const unsig + return 0; + + for (i = 0; i < nr_entries; i++) { -+ p = seprintf(p, end, "%*c%pS\n", 1 + spaces, ' ', ++ p = sprintf_end(p, end, "%*c%pS\n", 1 + spaces, ' ', + (void *)entries[i]); + } + + return p; +} -+EXPORT_SYMBOL_GPL(stack_trace_seprint); ++EXPORT_SYMBOL_GPL(stack_trace_sprint_end); + #ifdef CONFIG_ARCH_STACKWALK @@ lib/stackdepot.c: int stack_depot_snprint(depot_stack_handle_t handle, char *buf } EXPORT_SYMBOL_GPL(stack_depot_snprint); -+char *stack_depot_seprint(depot_stack_handle_t handle, char *p, -+ const char end[0], int spaces) ++char *stack_depot_sprint_end(depot_stack_handle_t handle, char *p, ++ const char end[0], int spaces) +{ + unsigned long *entries; + unsigned int nr_entries; + + nr_entries = stack_depot_fetch(handle, &entries); -+ return nr_entries ? stack_trace_seprint(p, end, entries, nr_entries, -+ spaces) : p; ++ return nr_entries ? ++ stack_trace_sprint_end(p, end, entries, nr_entries, spaces) ++ : sprintf_end(p, end, ""); +} -+EXPORT_SYMBOL_GPL(stack_depot_seprint); ++EXPORT_SYMBOL_GPL(stack_depot_sprint_end); + depot_stack_handle_t __must_check stack_depot_set_extra_bits( depot_stack_handle_t handle, unsigned int extra_bits) 3: 033bf00f1fcf ! 3: 690ed4d22f57 mm: Use seprintf() instead of less ergonomic APIs @@ Metadata Author: Alejandro Colomar ## Commit message ## - mm: Use seprintf() instead of less ergonomic APIs + mm: Use sprintf_end() instead of less ergonomic APIs While doing this, I detected some anomalies in the existing code: @@ Commit message This file uses the 'p += snprintf()' anti-pattern. That will overflow the pointer on truncation, which has undefined - behavior. Using seprintf(), this bug is fixed. + behavior. Using sprintf_end(), this bug is fixed. As in the previous file, here there was also dead code in the last scnprintf() call, by incrementing a pointer that is not @@ Commit message a good reason (i.e., we may want to avoid calling print_page_owner_memcg() if we truncated before). Please review if this amount of error handling is the right one, or if we want - to add or remove some. For seprintf(), a single test for null - after the last call is enough to detect truncation. + to add or remove some. For sprintf_end(), a single test for + null after the last call is enough to detect truncation. mm/slub.c: Again, the 'p += snprintf()' anti-pattern. This is UB, and by - using seprintf() we've fixed the bug. + using sprintf_end() we've fixed the bug. - Fixes: f99e12b21b84 (2021-07-30; "kfence: add function to mask address bits") - [alx: that commit introduced dead code] - Fixes: af649773fb25 (2024-07-17; "mm/numa_balancing: teach mpol_to_str about the balancing mode") - [alx: that commit added p+=snprintf() calls, which are UB] - Fixes: 2291990ab36b (2008-04-28; "mempolicy: clean-up mpol-to-str() mempolicy formatting") - [alx: that commit changed p+=sprintf() into p+=snprintf(), which is still UB] - Fixes: 948927ee9e4f (2013-11-13; "mm, mempolicy: make mpol_to_str robust and always succeed") - [alx: that commit changes old code into p+=snprintf(), which is still UB] - [alx: that commit also produced dead code by leaving the last 'p+=...'] - Fixes: d65360f22406 (2022-09-26; "mm/slub: clean up create_unique_id()") - [alx: that commit changed p+=sprintf() into p+=snprintf(), which is still UB] Cc: Kees Cook Cc: Christopher Bazley Cc: Sven Schnelle Cc: Marco Elver Cc: Heiko Carstens Cc: Tvrtko Ursulin - Cc: "Huang, Ying" Cc: Andrew Morton - Cc: Lee Schermerhorn Cc: Linus Torvalds Cc: David Rientjes Cc: Christophe JAILLET Cc: Hyeonggon Yoo <42.hyeyoo@gmail.com> Cc: Chao Yu Cc: Vlastimil Babka + Cc: Rasmus Villemoes + Cc: Michal Hocko + Cc: Al Viro Signed-off-by: Alejandro Colomar ## mm/kfence/kfence_test.c ## @@ mm/kfence/kfence_test.c: static bool report_matches(const struct expect_report * switch (r->type) { case KFENCE_ERROR_OOB: - cur += scnprintf(cur, end - cur, "BUG: KFENCE: out-of-bounds %s", -+ cur = seprintf(cur, end, "BUG: KFENCE: out-of-bounds %s", ++ cur = sprintf_end(cur, end, "BUG: KFENCE: out-of-bounds %s", get_access_type(r)); break; case KFENCE_ERROR_UAF: - cur += scnprintf(cur, end - cur, "BUG: KFENCE: use-after-free %s", -+ cur = seprintf(cur, end, "BUG: KFENCE: use-after-free %s", ++ cur = sprintf_end(cur, end, "BUG: KFENCE: use-after-free %s", get_access_type(r)); break; case KFENCE_ERROR_CORRUPTION: - cur += scnprintf(cur, end - cur, "BUG: KFENCE: memory corruption"); -+ cur = seprintf(cur, end, "BUG: KFENCE: memory corruption"); ++ cur = sprintf_end(cur, end, "BUG: KFENCE: memory corruption"); break; case KFENCE_ERROR_INVALID: - cur += scnprintf(cur, end - cur, "BUG: KFENCE: invalid %s", -+ cur = seprintf(cur, end, "BUG: KFENCE: invalid %s", ++ cur = sprintf_end(cur, end, "BUG: KFENCE: invalid %s", get_access_type(r)); break; case KFENCE_ERROR_INVALID_FREE: - cur += scnprintf(cur, end - cur, "BUG: KFENCE: invalid free"); -+ cur = seprintf(cur, end, "BUG: KFENCE: invalid free"); ++ cur = sprintf_end(cur, end, "BUG: KFENCE: invalid free"); break; } - scnprintf(cur, end - cur, " in %pS", r->fn); -+ seprintf(cur, end, " in %pS", r->fn); ++ sprintf_end(cur, end, " in %pS", r->fn); /* The exact offset won't match, remove it; also strip module name. */ cur = strchr(expect[0], '+'); if (cur) @@ mm/kfence/kfence_test.c: static bool report_matches(const struct expect_report * switch (r->type) { case KFENCE_ERROR_OOB: - cur += scnprintf(cur, end - cur, "Out-of-bounds %s at", get_access_type(r)); -+ cur = seprintf(cur, end, "Out-of-bounds %s at", get_access_type(r)); ++ cur = sprintf_end(cur, end, "Out-of-bounds %s at", get_access_type(r)); addr = arch_kfence_test_address(addr); break; case KFENCE_ERROR_UAF: - cur += scnprintf(cur, end - cur, "Use-after-free %s at", get_access_type(r)); -+ cur = seprintf(cur, end, "Use-after-free %s at", get_access_type(r)); ++ cur = sprintf_end(cur, end, "Use-after-free %s at", get_access_type(r)); addr = arch_kfence_test_address(addr); break; case KFENCE_ERROR_CORRUPTION: - cur += scnprintf(cur, end - cur, "Corrupted memory at"); -+ cur = seprintf(cur, end, "Corrupted memory at"); ++ cur = sprintf_end(cur, end, "Corrupted memory at"); break; case KFENCE_ERROR_INVALID: - cur += scnprintf(cur, end - cur, "Invalid %s at", get_access_type(r)); -+ cur = seprintf(cur, end, "Invalid %s at", get_access_type(r)); ++ cur = sprintf_end(cur, end, "Invalid %s at", get_access_type(r)); addr = arch_kfence_test_address(addr); break; case KFENCE_ERROR_INVALID_FREE: - cur += scnprintf(cur, end - cur, "Invalid free of"); -+ cur = seprintf(cur, end, "Invalid free of"); ++ cur = sprintf_end(cur, end, "Invalid free of"); break; } - cur += scnprintf(cur, end - cur, " 0x%p", (void *)addr); -+ seprintf(cur, end, " 0x%p", (void *)addr); ++ sprintf_end(cur, end, " 0x%p", (void *)addr); spin_lock_irqsave(&observed.lock, flags); if (!report_available()) @@ mm/kmsan/kmsan_test.c: static bool report_matches(const struct expect_report *r) end = &expected_header[sizeof(expected_header) - 1]; - cur += scnprintf(cur, end - cur, "BUG: KMSAN: %s", r->error_type); -+ cur = seprintf(cur, end, "BUG: KMSAN: %s", r->error_type); ++ cur = sprintf_end(cur, end, "BUG: KMSAN: %s", r->error_type); - scnprintf(cur, end - cur, " in %s", r->symbol); -+ seprintf(cur, end, " in %s", r->symbol); ++ sprintf_end(cur, end, " in %s", r->symbol); /* The exact offset won't match, remove it; also strip module name. */ cur = strchr(expected_header, '+'); if (cur) @@ mm/mempolicy.c: void mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol default: WARN_ON_ONCE(1); - snprintf(p, maxlen, "unknown"); -+ seprintf(p, e, "unknown"); ++ sprintf_end(p, e, "unknown"); return; } - p += snprintf(p, maxlen, "%s", policy_modes[mode]); -+ p = seprintf(p, e, "%s", policy_modes[mode]); ++ p = sprintf_end(p, e, "%s", policy_modes[mode]); if (flags & MPOL_MODE_FLAGS) { - p += snprintf(p, buffer + maxlen - p, "="); -+ p = seprintf(p, e, "="); ++ p = sprintf_end(p, e, "="); /* * Static and relative are mutually exclusive. */ if (flags & MPOL_F_STATIC_NODES) - p += snprintf(p, buffer + maxlen - p, "static"); -+ p = seprintf(p, e, "static"); ++ p = sprintf_end(p, e, "static"); else if (flags & MPOL_F_RELATIVE_NODES) - p += snprintf(p, buffer + maxlen - p, "relative"); -+ p = seprintf(p, e, "relative"); ++ p = sprintf_end(p, e, "relative"); if (flags & MPOL_F_NUMA_BALANCING) { if (!is_power_of_2(flags & MPOL_MODE_FLAGS)) - p += snprintf(p, buffer + maxlen - p, "|"); - p += snprintf(p, buffer + maxlen - p, "balancing"); -+ p = seprintf(p, e, "|"); -+ p = seprintf(p, e, "balancing"); ++ p = sprintf_end(p, e, "|"); ++ p = sprintf_end(p, e, "balancing"); } } if (!nodes_empty(nodes)) - p += scnprintf(p, buffer + maxlen - p, ":%*pbl", - nodemask_pr_args(&nodes)); -+ seprintf(p, e, ":%*pbl", nodemask_pr_args(&nodes)); ++ sprintf_end(p, e, ":%*pbl", nodemask_pr_args(&nodes)); } #ifdef CONFIG_SYSFS @@ mm/page_owner.c: static inline int print_page_owner_memcg(char *kbuf, size_t cou if (memcg_data & MEMCG_DATA_OBJEXTS) - ret += scnprintf(kbuf + ret, count - ret, - "Slab cache page\n"); -+ p = seprintf(p, end, "Slab cache page\n"); ++ p = sprintf_end(p, end, "Slab cache page\n"); memcg = page_memcg_check(page); if (!memcg) @@ mm/page_owner.c: static inline int print_page_owner_memcg(char *kbuf, size_t cou online = (memcg->css.flags & CSS_ONLINE); cgroup_name(memcg->css.cgroup, name, sizeof(name)); - ret += scnprintf(kbuf + ret, count - ret, -+ p = seprintf(p, end, ++ p = sprintf_end(p, end, "Charged %sto %smemcg %s\n", PageMemcgKmem(page) ? "(via objcg) " : "", online ? "" : "offline ", @@ mm/page_owner.c: print_page_owner(char __user *buf, size_t count, unsigned long - ret = scnprintf(kbuf, count, + p = kbuf; + e = kbuf + count; -+ p = seprintf(p, e, ++ p = sprintf_end(p, e, "Page allocated via order %u, mask %#x(%pGg), pid %d, tgid %d (%s), ts %llu ns\n", page_owner->order, page_owner->gfp_mask, &page_owner->gfp_mask, page_owner->pid, @@ mm/page_owner.c: print_page_owner(char __user *buf, size_t count, unsigned long pageblock_mt = get_pageblock_migratetype(page); page_mt = gfp_migratetype(page_owner->gfp_mask); - ret += scnprintf(kbuf + ret, count - ret, -+ p = seprintf(p, e, ++ p = sprintf_end(p, e, "PFN 0x%lx type %s Block %lu type %s Flags %pGp\n", pfn, migratetype_names[page_mt], @@ mm/page_owner.c: print_page_owner(char __user *buf, size_t count, unsigned long - ret += stack_depot_snprint(handle, kbuf + ret, count - ret, 0); - if (ret >= count) - goto err; -+ p = stack_depot_seprint(handle, p, e, 0); ++ p = stack_depot_sprint_end(handle, p, e, 0); + if (p == NULL) + goto err; // XXX: Should we remove this error handling? if (page_owner->last_migrate_reason != -1) { - ret += scnprintf(kbuf + ret, count - ret, -+ p = seprintf(p, e, ++ p = sprintf_end(p, e, "Page has been migrated, last migrate reason: %s\n", migrate_reason_names[page_owner->last_migrate_reason]); } @@ mm/page_owner.c: print_page_owner(char __user *buf, size_t count, unsigned long - ret += snprintf(kbuf + ret, count - ret, "\n"); - if (ret >= count) -+ p = seprintf(p, e, "\n"); ++ p = sprintf_end(p, e, "\n"); + if (p == NULL) goto err; @@ mm/slub.c: static char *create_unique_id(struct kmem_cache *s) if (p != name + 1) *p++ = '-'; - p += snprintf(p, ID_STR_LENGTH - (p - name), "%07u", s->size); -+ p = seprintf(p, e, "%07u", s->size); ++ p = sprintf_end(p, e, "%07u", s->size); - if (WARN_ON(p > name + ID_STR_LENGTH - 1)) { + if (WARN_ON(p == NULL)) { 4: d8bd0e1d308b ! 4: e05c5afabb3c array_size.h: Add ENDOF() @@ Metadata ## Commit message ## array_size.h: Add ENDOF() - This macro is useful to calculate the second argument to seprintf(), + This macro is useful to calculate the second argument to sprintf_end(), avoiding off-by-one bugs. Cc: Kees Cook Cc: Christopher Bazley + Cc: Rasmus Villemoes + Cc: Marco Elver + Cc: Michal Hocko + Cc: Linus Torvalds + Cc: Al Viro Signed-off-by: Alejandro Colomar ## include/linux/array_size.h ## 5: 740755c1a888 ! 5: 44a5cfc82acf mm: Fix benign off-by-one bugs @@ Commit message 'end' --that is, at most the terminating null byte will be written at 'end-1'--. - Fixes: bc8fbc5f305a (2021-02-26; "kfence: add test suite") - Fixes: 8ed691b02ade (2022-10-03; "kmsan: add tests for KMSAN") + Acked-by: Marco Elver Cc: Kees Cook Cc: Christopher Bazley Cc: Alexander Potapenko - Cc: Marco Elver Cc: Dmitry Vyukov Cc: Alexander Potapenko Cc: Jann Horn Cc: Andrew Morton Cc: Linus Torvalds + Cc: Rasmus Villemoes + Cc: Marco Elver + Cc: Michal Hocko + Cc: Al Viro Signed-off-by: Alejandro Colomar ## mm/kfence/kfence_test.c ## @@ mm/kfence/kfence_test.c: static bool report_matches(const struct expect_report * + end = ENDOF(expect[0]); switch (r->type) { case KFENCE_ERROR_OOB: - cur = seprintf(cur, end, "BUG: KFENCE: out-of-bounds %s", + cur = sprintf_end(cur, end, "BUG: KFENCE: out-of-bounds %s", @@ mm/kfence/kfence_test.c: static bool report_matches(const struct expect_report *r) /* Access information */ @@ mm/kmsan/kmsan_test.c: static bool report_matches(const struct expect_report *r) - end = &expected_header[sizeof(expected_header) - 1]; + end = ENDOF(expected_header); - cur = seprintf(cur, end, "BUG: KMSAN: %s", r->error_type); + cur = sprintf_end(cur, end, "BUG: KMSAN: %s", r->error_type); 6: 44d05559398c ! 6: 0314948eb225 sprintf: Add [V]STPRINTF() @@ Metadata Author: Alejandro Colomar ## Commit message ## - sprintf: Add [V]STPRINTF() + sprintf: Add [V]SPRINTF_END() - These macros take the array size argument implicitly to avoid programmer - mistakes. This guarantees that the input is an array, unlike the common - call + These macros take the end of the array argument implicitly to avoid + programmer mistakes. This guarantees that the input is an array, unlike snprintf(buf, sizeof(buf), ...); - which is dangerous if the programmer passes a pointer. + which is dangerous if the programmer passes a pointer instead of an + array. These macros are essentially the same as the 2-argument version of - strscpy(), but with a formatted string. + strscpy(), but with a formatted string, and returning a pointer to the + terminating '\0' (or NULL, on error). + Cc: Rasmus Villemoes + Cc: Marco Elver + Cc: Michal Hocko + Cc: Linus Torvalds + Cc: Al Viro Signed-off-by: Alejandro Colomar ## include/linux/sprintf.h ## @@ include/linux/sprintf.h #include +#include + -+#define STPRINTF(a, fmt, ...) stprintf(a, ARRAY_SIZE(a), fmt, ##__VA_ARGS__) -+#define VSTPRINTF(a, fmt, ap) vstprintf(a, ARRAY_SIZE(a), fmt, ap) ++#define SPRINTF_END(a, fmt, ...) sprintf_end(a, ENDOF(a), fmt, ##__VA_ARGS__) ++#define VSPRINTF_END(a, fmt, ap) vsprintf_end(a, ENDOF(a), fmt, ap) int num_to_str(char *buf, int size, unsigned long long num, unsigned int width); 7: d0e95db3c80a ! 7: f99632f42eee mm: Use [V]STPRINTF() to avoid specifying the array size @@ Metadata Author: Alejandro Colomar ## Commit message ## - mm: Use [V]STPRINTF() to avoid specifying the array size + mm: Use [V]SPRINTF_END() to avoid specifying the array size + Cc: Rasmus Villemoes + Cc: Marco Elver + Cc: Michal Hocko + Cc: Linus Torvalds + Cc: Al Viro Signed-off-by: Alejandro Colomar ## mm/backing-dev.c ## @@ mm/backing-dev.c: int bdi_register_va(struct backing_dev_info *bdi, const char * return 0; - vsnprintf(bdi->dev_name, sizeof(bdi->dev_name), fmt, args); -+ VSTPRINTF(bdi->dev_name, fmt, args); ++ VSPRINTF_END(bdi->dev_name, fmt, args); dev = device_create(&bdi_class, NULL, MKDEV(0, 0), bdi, bdi->dev_name); if (IS_ERR(dev)) return PTR_ERR(dev); @@ mm/cma.c: static int __init cma_new_area(const char *name, phys_addr_t size, if (name) - snprintf(cma->name, CMA_MAX_NAME, "%s", name); -+ STPRINTF(cma->name, "%s", name); ++ SPRINTF_END(cma->name, "%s", name); else - snprintf(cma->name, CMA_MAX_NAME, "cma%d\n", cma_area_count); -+ STPRINTF(cma->name, "cma%d\n", cma_area_count); ++ SPRINTF_END(cma->name, "cma%d\n", cma_area_count); cma->available_count = cma->count = size >> PAGE_SHIFT; cma->order_per_bit = order_per_bit; @@ mm/cma_debug.c: static void cma_debugfs_add_one(struct cma *cma, struct dentry * for (r = 0; r < cma->nranges; r++) { cmr = &cma->ranges[r]; - snprintf(rdirname, sizeof(rdirname), "%d", r); -+ STPRINTF(rdirname, "%d", r); ++ SPRINTF_END(rdirname, "%d", r); dir = debugfs_create_dir(rdirname, rangedir); debugfs_create_file("base_pfn", 0444, dir, &cmr->base_pfn, &cma_debugfs_fops); @@ mm/hugetlb.c: void __init hugetlb_add_hstate(unsigned int order) INIT_LIST_HEAD(&h->hugepage_activelist); - snprintf(h->name, HSTATE_NAME_LEN, "hugepages-%lukB", - huge_page_size(h)/SZ_1K); -+ STPRINTF(h->name, "hugepages-%lukB", huge_page_size(h)/SZ_1K); ++ SPRINTF_END(h->name, "hugepages-%lukB", huge_page_size(h)/SZ_1K); parsed_hstate = h; } @@ mm/hugetlb_cgroup.c: hugetlb_cgroup_cfttypes_init(struct hstate *h, struct cftyp *cft = *tmpl; /* rebuild the name */ - snprintf(cft->name, MAX_CFTYPE_NAME, "%s.%s", buf, tmpl->name); -+ STPRINTF(cft->name, "%s.%s", buf, tmpl->name); ++ SPRINTF_END(cft->name, "%s.%s", buf, tmpl->name); /* rebuild the private */ cft->private = MEMFILE_PRIVATE(idx, tmpl->private); /* rebuild the file_offset */ @@ mm/hugetlb_cma.c: void __init hugetlb_cma_reserve(int order) size = round_up(size, PAGE_SIZE << order); - snprintf(name, sizeof(name), "hugetlb%d", nid); -+ STPRINTF(name, "hugetlb%d", nid); ++ SPRINTF_END(name, "hugetlb%d", nid); /* * Note that 'order per bit' is based on smallest size that * may be returned to CMA allocator in the case of @@ mm/kasan/report.c: static void print_memory_metadata(const void *addr) - snprintf(buffer, sizeof(buffer), - (i == 0) ? ">%px: " : " %px: ", row); -+ STPRINTF(buffer, (i == 0) ? ">%px: " : " %px: ", row); ++ SPRINTF_END(buffer, (i == 0) ? ">%px: " : " %px: ", row); /* * We should not pass a shadow pointer to generic @@ mm/memblock.c: static void __init_memblock memblock_dump(struct memblock_type *t #ifdef CONFIG_NUMA if (numa_valid_node(memblock_get_region_node(rgn))) - snprintf(nid_buf, sizeof(nid_buf), " on node %d", -+ STPRINTF(nid_buf, " on node %d", ++ SPRINTF_END(nid_buf, " on node %d", memblock_get_region_node(rgn)); #endif pr_info(" %s[%#x]\t[%pa-%pa], %pa bytes%s flags: %#x\n", @@ mm/memblock.c: int reserve_mem_release_by_name(const char *name) start = phys_to_virt(map->start); end = start + map->size - 1; - snprintf(buf, sizeof(buf), "reserve_mem:%s", name); -+ STPRINTF(buf, "reserve_mem:%s", name); ++ SPRINTF_END(buf, "reserve_mem:%s", name); free_reserved_area(start, end, 0, buf); map->size = 0; @@ mm/percpu.c: int __init pcpu_page_first_chunk(size_t reserved_size, pcpu_fc_cpu_ int nr_g0_units; - snprintf(psize_str, sizeof(psize_str), "%luK", PAGE_SIZE >> 10); -+ STPRINTF(psize_str, "%luK", PAGE_SIZE >> 10); ++ SPRINTF_END(psize_str, "%luK", PAGE_SIZE >> 10); ai = pcpu_build_alloc_info(reserved_size, 0, PAGE_SIZE, NULL); if (IS_ERR(ai)) @@ mm/shrinker_debug.c: int shrinker_debugfs_add(struct shrinker *shrinker) shrinker->debugfs_id = id; - snprintf(buf, sizeof(buf), "%s-%d", shrinker->name, id); -+ STPRINTF(buf, "%s-%d", shrinker->name, id); ++ SPRINTF_END(buf, "%s-%d", shrinker->name, id); /* create debugfs entry */ entry = debugfs_create_dir(buf, shrinker_debugfs_root); @@ mm/zswap.c: static struct zswap_pool *zswap_pool_create(char *type, char *compre /* unique name for each pool specifically required by zsmalloc */ - snprintf(name, 38, "zswap%x", atomic_inc_return(&zswap_pools_count)); -+ STPRINTF(name, "zswap%x", atomic_inc_return(&zswap_pools_count)); ++ SPRINTF_END(name, "zswap%x", atomic_inc_return(&zswap_pools_count)); pool->zpool = zpool_create_pool(type, name, gfp); if (!pool->zpool) { pr_err("%s zpool not available\n", type); -- 2.50.0