https://github.com/marlus updated https://github.com/llvm/llvm-project/pull/204139
>From 055db081f85fe617fa1025e2bf582338e4d747bd Mon Sep 17 00:00:00 2001 From: Marlus Cadanus da Costa <[email protected]> Date: Tue, 16 Jun 2026 08:42:14 -0400 Subject: [PATCH 1/2] [Clang] Fix offsetof sign-extending unsigned array indices >= 128 When evaluating __builtin_offsetof with an unsigned integer array index (e.g. uint8_t, uint16_t) whose value has the high bit set, Clang was calling getSExtValue() on the APSInt index, which sign-extends the value and produces a large bogus offset. Fix this by checking whether the APSInt is unsigned and using getZExtValue() in that case instead. Fixes #199319 --- clang/lib/AST/ExprConstant.cpp | 3 +- clang/test/Sema/offsetof-unsigned-index.c | 25 +++++++++++++++ .../test/SemaCXX/offsetof-unsigned-index.cpp | 31 +++++++++++++++++++ 3 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 clang/test/Sema/offsetof-unsigned-index.c create mode 100644 clang/test/SemaCXX/offsetof-unsigned-index.cpp diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index bc98c0d86bb65..a2a3349b21baf 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -19284,7 +19284,8 @@ bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *OOE) { return Error(OOE); CurrentType = AT->getElementType(); CharUnits ElementSize = Info.Ctx.getTypeSizeInChars(CurrentType); - Result += IdxResult.getSExtValue() * ElementSize; + Result += (IdxResult.isUnsigned() ? (int64_t)IdxResult.getZExtValue() + : IdxResult.getSExtValue()) * ElementSize; break; } diff --git a/clang/test/Sema/offsetof-unsigned-index.c b/clang/test/Sema/offsetof-unsigned-index.c new file mode 100644 index 0000000000000..480e486fbad72 --- /dev/null +++ b/clang/test/Sema/offsetof-unsigned-index.c @@ -0,0 +1,25 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s -triple x86_64-linux-gnu +// RUN: %clang_cc1 -fsyntax-only -verify %s -triple x86_64-linux-gnu -fexperimental-new-constant-interpreter + +// expected-no-diagnostics + +// Test that offsetof correctly zero-extends unsigned array indices >= 128. +// Previously, Clang would sign-extend uint8_t indices >= 128, producing +// a large bogus offset value instead of the correct one. +// https://github.com/llvm/llvm-project/issues/199319 + +#include <stdint.h> +#include <stddef.h> + +struct MyStruct { + void *ptrs[256]; +}; + +_Static_assert(__builtin_offsetof(struct MyStruct, ptrs[(uint8_t)127]) == 127 * sizeof(void *), + "offsetof with uint8_t index 127 should be correct"); + +_Static_assert(__builtin_offsetof(struct MyStruct, ptrs[(uint8_t)128]) == 128 * sizeof(void *), + "offsetof with uint8_t index 128 should be correctly zero-extended, not sign-extended"); + +_Static_assert(__builtin_offsetof(struct MyStruct, ptrs[(uint8_t)255]) == 255 * sizeof(void *), + "offsetof with uint8_t index 255 should be correctly zero-extended, not sign-extended"); diff --git a/clang/test/SemaCXX/offsetof-unsigned-index.cpp b/clang/test/SemaCXX/offsetof-unsigned-index.cpp new file mode 100644 index 0000000000000..50bf50ef0fc35 --- /dev/null +++ b/clang/test/SemaCXX/offsetof-unsigned-index.cpp @@ -0,0 +1,31 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s -triple x86_64-linux-gnu -std=c++11 +// RUN: %clang_cc1 -fsyntax-only -verify %s -triple x86_64-linux-gnu -std=c++11 -fexperimental-new-constant-interpreter + +// expected-no-diagnostics + +// Test that offsetof correctly zero-extends unsigned array indices >= 128. +// Previously, Clang would sign-extend uint8_t/uint16_t indices whose high bit +// was set, producing a large bogus offset value instead of the correct one. +// https://github.com/llvm/llvm-project/issues/199319 + +#include <cstdint> +#include <cstddef> + +struct MyStruct { + void *ptrs[256]; +}; + +// uint8_t index: values >= 128 were incorrectly sign-extended +static_assert(__builtin_offsetof(MyStruct, ptrs[(uint8_t)127]) == 127 * sizeof(void *), + "offsetof with uint8_t index 127 should be correct"); +static_assert(__builtin_offsetof(MyStruct, ptrs[(uint8_t)128]) == 128 * sizeof(void *), + "offsetof with uint8_t index 128 should be correctly zero-extended"); +static_assert(__builtin_offsetof(MyStruct, ptrs[(uint8_t)255]) == 255 * sizeof(void *), + "offsetof with uint8_t index 255 should be correctly zero-extended"); + +// uint16_t index: values >= 32768 were also affected +struct BigStruct { + char data[65536]; +}; +static_assert(__builtin_offsetof(BigStruct, data[(uint16_t)32768]) == 32768, + "offsetof with uint16_t index 32768 should be correctly zero-extended"); >From 71f80764449046ef26d2ad399fcd2853359a2a6a Mon Sep 17 00:00:00 2001 From: Cadanus da Costa <[email protected]> Date: Tue, 16 Jun 2026 14:52:53 -0400 Subject: [PATCH 2/2] Apply clang-format --- clang/lib/AST/ExprConstant.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index a2a3349b21baf..eb76c10076669 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -19285,7 +19285,8 @@ bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *OOE) { CurrentType = AT->getElementType(); CharUnits ElementSize = Info.Ctx.getTypeSizeInChars(CurrentType); Result += (IdxResult.isUnsigned() ? (int64_t)IdxResult.getZExtValue() - : IdxResult.getSExtValue()) * ElementSize; + : IdxResult.getSExtValue()) * + ElementSize; break; } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
