[clang] [clang][bytecode] Avoid crash in constexpr wcslen on invalid argument… (PR #177891)
Ayush Kumar Gaur via cfe-commits
cfe-commits at lists.llvm.org
Mon Jan 26 02:57:42 PST 2026
https://github.com/Ayush3941 updated https://github.com/llvm/llvm-project/pull/177891
>From 7679af9795c8a9769e4e2a298ca4ed9db5183ee8 Mon Sep 17 00:00:00 2001
From: Ayush3941 <ayushkgaur1 at gmail.com>
Date: Sun, 25 Jan 2026 22:00:57 -0500
Subject: [PATCH 1/4] [clang][bytecode] Avoid crash in constexpr wcslen on
invalid argument type
---
clang/lib/AST/ByteCode/InterpBuiltin.cpp | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index d668fa118d3b9..e2517730e81ca 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -367,10 +367,18 @@ static bool interp__builtin_strlen(InterpState &S, CodePtr OpPC,
unsigned ElemSize = StrPtr.getFieldDesc()->getElemSize();
if (ID == Builtin::BI__builtin_wcslen || ID == Builtin::BIwcslen) {
- [[maybe_unused]] const ASTContext &AC = S.getASTContext();
- assert(ElemSize == AC.getTypeSizeInChars(AC.getWCharType()).getQuantity());
+ const ASTContext &AC = S.getASTContext();
+ unsigned WCharSize = AC.getTypeSizeInChars(AC.getWCharType()).getQuantity();
+ if (ElemSize != WCharSize) {
+ if (S.diagnosing()) {
+ // a dedicated diagnostic
+ diagnoseNonConstexprBuiltin(S, OpPC, ID);
+ }
+ return false;
+ }
}
+
size_t Len = 0;
for (size_t I = StrPtr.getIndex();; ++I, ++Len) {
const Pointer &ElemPtr = StrPtr.atIndex(I);
>From f54011c559787cb9e34c596739cdd54c86cee826 Mon Sep 17 00:00:00 2001
From: Ayush3941 <ayushkgaur1 at gmail.com>
Date: Mon, 26 Jan 2026 05:28:07 -0500
Subject: [PATCH 2/4] [clang][bytecode] Added Test file to Avoid crash in
constexpr wcslen on invalid argument type
---
clang/lib/AST/ByteCode/InterpBuiltin.cpp | 4 ----
.../AST/ByteCode/interp_builtin_wclen.cpp | 24 +++++++++++++++++++
2 files changed, 24 insertions(+), 4 deletions(-)
create mode 100644 clang/test/AST/ByteCode/interp_builtin_wclen.cpp
diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index e2517730e81ca..69a9381615d52 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -370,10 +370,6 @@ static bool interp__builtin_strlen(InterpState &S, CodePtr OpPC,
const ASTContext &AC = S.getASTContext();
unsigned WCharSize = AC.getTypeSizeInChars(AC.getWCharType()).getQuantity();
if (ElemSize != WCharSize) {
- if (S.diagnosing()) {
- // a dedicated diagnostic
- diagnoseNonConstexprBuiltin(S, OpPC, ID);
- }
return false;
}
}
diff --git a/clang/test/AST/ByteCode/interp_builtin_wclen.cpp b/clang/test/AST/ByteCode/interp_builtin_wclen.cpp
new file mode 100644
index 0000000000000..bc8adbd385094
--- /dev/null
+++ b/clang/test/AST/ByteCode/interp_builtin_wclen.cpp
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -std=c++23 -fexperimental-new-constant-interpreter -verify=expected,both %s
+// RUN: %clang_cc1 -std=c++23 -verify=ref,both %s
+
+namespace WcslenInvalidArg {
+
+ // 1) Narrow string literal passed to wcslen builtin: hard error in C++.
+ static_assert(__builtin_wcslen("x") == 'x');
+ // both-error at -1 {{cannot initialize a parameter of type 'const wchar_t *' with an lvalue of type 'const char[2]'}}
+
+ // 2) Forced cast: should not crash, but not a constant expression.
+ static_assert(__builtin_wcslen((const wchar_t *)"x") == 1);
+ // both-error at -1 {{static assertion expression is not an integral constant expression}}
+ // both-note at -2 {{cast that performs the conversions of a reinterpret_cast}}
+
+ // 3) Forced cast from unsigned char*.
+ const unsigned char u8s[] = "hi";
+ static_assert(__builtin_wcslen((const wchar_t *)u8s) == 2);
+ // both-error at -1 {{static assertion expression is not an integral constant expression}}
+ // both-note at -2 {{cast that performs the conversions of a reinterpret_cast}}
+
+ // 4) Correct wide string usage should constant-fold.
+ static_assert(__builtin_wcslen(L"x") == 1);
+
+} // namespace WcslenInvalidArg
>From 2d16d9af7f079aec7d979f0b89a2e03961480edc Mon Sep 17 00:00:00 2001
From: Ayush3941 <ayushkgaur1 at gmail.com>
Date: Mon, 26 Jan 2026 05:55:07 -0500
Subject: [PATCH 3/4] [clang][bytecode] Added Test file in
clang/test/AST/ByteCode/builtin-functions.cpp to Avoid crash in constexpr
wcslen on invalid argument type
---
clang/test/AST/ByteCode/builtin-functions.cpp | 22 +++++++++++++++++
.../AST/ByteCode/interp_builtin_wclen.cpp | 24 -------------------
2 files changed, 22 insertions(+), 24 deletions(-)
delete mode 100644 clang/test/AST/ByteCode/interp_builtin_wclen.cpp
diff --git a/clang/test/AST/ByteCode/builtin-functions.cpp b/clang/test/AST/ByteCode/builtin-functions.cpp
index 116d6aef8350a..1e0ea4ec60021 100644
--- a/clang/test/AST/ByteCode/builtin-functions.cpp
+++ b/clang/test/AST/ByteCode/builtin-functions.cpp
@@ -1903,3 +1903,25 @@ namespace NonBlockPointerStore {
void foo(void) { a *= __builtin_sadd_overflow(1, 2, 0); }
void foo2(void) { a *= __builtin_addc(1, 2, 0, 0); }
}
+
+namespace WcslenInvalidArg {
+
+ // 1) Narrow string literal passed to wcslen builtin: hard error in C++.
+ static_assert(__builtin_wcslen("x") == 'x');
+ // both-error at -1 {{cannot initialize a parameter of type 'const wchar_t *' with an lvalue of type 'const char[2]'}}
+
+ // 2) Forced cast: should not crash, but not a constant expression.
+ static_assert(__builtin_wcslen((const wchar_t *)"x") == 1);
+ // both-error at -1 {{static assertion expression is not an integral constant expression}}
+ // both-note at -2 {{cast that performs the conversions of a reinterpret_cast}}
+
+ // 3) Forced cast from unsigned char*.
+ const unsigned char u8s[] = "hi";
+ static_assert(__builtin_wcslen((const wchar_t *)u8s) == 2);
+ // both-error at -1 {{static assertion expression is not an integral constant expression}}
+ // both-note at -2 {{cast that performs the conversions of a reinterpret_cast}}
+
+ // 4) Correct wide string usage should constant-fold.
+ static_assert(__builtin_wcslen(L"x") == 1);
+
+} // namespace WcslenInvalidArg
diff --git a/clang/test/AST/ByteCode/interp_builtin_wclen.cpp b/clang/test/AST/ByteCode/interp_builtin_wclen.cpp
deleted file mode 100644
index bc8adbd385094..0000000000000
--- a/clang/test/AST/ByteCode/interp_builtin_wclen.cpp
+++ /dev/null
@@ -1,24 +0,0 @@
-// RUN: %clang_cc1 -std=c++23 -fexperimental-new-constant-interpreter -verify=expected,both %s
-// RUN: %clang_cc1 -std=c++23 -verify=ref,both %s
-
-namespace WcslenInvalidArg {
-
- // 1) Narrow string literal passed to wcslen builtin: hard error in C++.
- static_assert(__builtin_wcslen("x") == 'x');
- // both-error at -1 {{cannot initialize a parameter of type 'const wchar_t *' with an lvalue of type 'const char[2]'}}
-
- // 2) Forced cast: should not crash, but not a constant expression.
- static_assert(__builtin_wcslen((const wchar_t *)"x") == 1);
- // both-error at -1 {{static assertion expression is not an integral constant expression}}
- // both-note at -2 {{cast that performs the conversions of a reinterpret_cast}}
-
- // 3) Forced cast from unsigned char*.
- const unsigned char u8s[] = "hi";
- static_assert(__builtin_wcslen((const wchar_t *)u8s) == 2);
- // both-error at -1 {{static assertion expression is not an integral constant expression}}
- // both-note at -2 {{cast that performs the conversions of a reinterpret_cast}}
-
- // 4) Correct wide string usage should constant-fold.
- static_assert(__builtin_wcslen(L"x") == 1);
-
-} // namespace WcslenInvalidArg
>From a53666493f40d21bd08ab4f03cbfd1eb9a5bbb44 Mon Sep 17 00:00:00 2001
From: Ayush Kumar Gaur <132849148+Ayush3941 at users.noreply.github.com>
Date: Mon, 26 Jan 2026 05:57:33 -0500
Subject: [PATCH 4/4] Update clang/lib/AST/ByteCode/InterpBuiltin.cpp
Co-authored-by: Timm Baeder <tbaeder at redhat.com>
---
clang/lib/AST/ByteCode/InterpBuiltin.cpp | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index 69a9381615d52..100efe0d4bf65 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -369,9 +369,8 @@ static bool interp__builtin_strlen(InterpState &S, CodePtr OpPC,
if (ID == Builtin::BI__builtin_wcslen || ID == Builtin::BIwcslen) {
const ASTContext &AC = S.getASTContext();
unsigned WCharSize = AC.getTypeSizeInChars(AC.getWCharType()).getQuantity();
- if (ElemSize != WCharSize) {
+ if (ElemSize != WCharSize)
return false;
- }
}
More information about the cfe-commits
mailing list