llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Marlus Cadanus da Costa (marlus) <details> <summary>Changes</summary> 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 --- Full diff: https://github.com/llvm/llvm-project/pull/204139.diff 3 Files Affected: - (modified) clang/lib/AST/ExprConstant.cpp (+2-1) - (added) clang/test/Sema/offsetof-unsigned-index.c (+25) - (added) clang/test/SemaCXX/offsetof-unsigned-index.cpp (+31) ``````````diff 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"); `````````` </details> https://github.com/llvm/llvm-project/pull/204139 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
