llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Hendrik Hübner (HendrikHuebner) <details> <summary>Changes</summary> When an atomic builtin is called with a pointer to an object of size zero, an arithmetic exception gets thrown because there is a modulo operation with the objects size in codegen. This is described here: #<!-- -->90330 I have added a check to SemaChecking.cpp, which throws an error if this is the case. --- Full diff: https://github.com/llvm/llvm-project/pull/91057.diff 3 Files Affected: - (modified) clang/include/clang/Basic/DiagnosticFrontendKinds.td (+3) - (modified) clang/lib/Sema/SemaChecking.cpp (+11-1) - (modified) clang/test/Sema/atomic-ops.c (+32) ``````````diff diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td index e456ec2cac461..74d96a8cbe0dc 100644 --- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td @@ -330,6 +330,9 @@ def warn_atomic_op_misaligned : Warning< "; the expected alignment (%0 bytes) exceeds the actual alignment (%1 bytes)">, InGroup<AtomicAlignment>; +def err_atomic_op_size_zero : Error< + "First argument cannot be a pointer to an object of size zero">; + def warn_atomic_op_oversized : Warning< "large atomic operation may incur " "significant performance penalty" diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index ecd1821651140..f91ab833b4fc7 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -40,6 +40,7 @@ #include "clang/Basic/AddressSpaces.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/Diagnostic.h" +#include "clang/Basic/DiagnosticFrontend.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/LangOptions.h" @@ -8497,7 +8498,9 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange, << 0 << AdjustedNumArgs << static_cast<unsigned>(Args.size()) << /*is non object*/ 0 << ExprRange; return ExprError(); - } else if (Args.size() > AdjustedNumArgs) { + } + + if (Args.size() > AdjustedNumArgs) { Diag(Args[AdjustedNumArgs]->getBeginLoc(), diag::err_typecheck_call_too_many_args) << 0 << AdjustedNumArgs << static_cast<unsigned>(Args.size()) @@ -8544,6 +8547,13 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange, } } + // pointer to object of size zero is not allowed + if (Context.getTypeInfoInChars(AtomTy).Width.isZero()) { + Diag(ExprRange.getBegin(), diag::err_atomic_op_size_zero) + << Ptr->getSourceRange(); + return ExprError(); + } + // For an arithmetic operation, the implied arithmetic must be well-formed. if (Form == Arithmetic) { // GCC does not enforce these rules for GNU atomics, but we do to help catch diff --git a/clang/test/Sema/atomic-ops.c b/clang/test/Sema/atomic-ops.c index 1d36667d6cf40..97da2582312bb 100644 --- a/clang/test/Sema/atomic-ops.c +++ b/clang/test/Sema/atomic-ops.c @@ -639,6 +639,38 @@ void memory_checks(_Atomic(int) *Ap, int *p, int val) { (void)__atomic_compare_exchange_n(p, p, val, 0, memory_order_seq_cst, -1); // expected-warning {{memory order argument to atomic operation is invalid}} } +struct Z { + char z[]; +}; + +void zeroSizeArgError(struct Z *a, struct Z *b, struct Z *c) { + __atomic_exchange(b, b, c, memory_order_relaxed); // expected-error {{First argument cannot be a pointer to an object of size zero}} + __atomic_exchange(b, b, c, memory_order_acq_rel); // expected-error {{First argument cannot be a pointer to an object of size zero}} + __atomic_exchange(b, b, c, memory_order_acquire); // expected-error {{First argument cannot be a pointer to an object of size zero}} + __atomic_exchange(b, b, c, memory_order_consume); // expected-error {{First argument cannot be a pointer to an object of size zero}} + __atomic_exchange(b, b, c, memory_order_release); // expected-error {{First argument cannot be a pointer to an object of size zero}} + __atomic_exchange(b, b, c, memory_order_seq_cst); // expected-error {{First argument cannot be a pointer to an object of size zero}} + __atomic_load(a, b, memory_order_relaxed); // expected-error {{First argument cannot be a pointer to an object of size zero}} + __atomic_load(a, b, memory_order_acq_rel); // expected-error {{First argument cannot be a pointer to an object of size zero}} + __atomic_load(a, b, memory_order_acquire); // expected-error {{First argument cannot be a pointer to an object of size zero}} + __atomic_load(a, b, memory_order_consume); // expected-error {{First argument cannot be a pointer to an object of size zero}} + __atomic_load(a, b, memory_order_release); // expected-error {{First argument cannot be a pointer to an object of size zero}} + __atomic_load(a, b, memory_order_seq_cst); // expected-error {{First argument cannot be a pointer to an object of size zero}} + __atomic_store(a, b, memory_order_relaxed); // expected-error {{First argument cannot be a pointer to an object of size zero}} + __atomic_store(a, b, memory_order_acq_rel); // expected-error {{First argument cannot be a pointer to an object of size zero}} + __atomic_store(a, b, memory_order_acquire); // expected-error {{First argument cannot be a pointer to an object of size zero}} + __atomic_store(a, b, memory_order_consume); // expected-error {{First argument cannot be a pointer to an object of size zero}} + __atomic_store(a, b, memory_order_release); // expected-error {{First argument cannot be a pointer to an object of size zero}} + __atomic_store(a, b, memory_order_seq_cst); // expected-error {{First argument cannot be a pointer to an object of size zero}} + __atomic_compare_exchange(a, b, c, 0, memory_order_relaxed, memory_order_relaxed); // expected-error {{First argument cannot be a pointer to an object of size zero}} + __atomic_compare_exchange(a, b, c, 0, memory_order_acq_rel, memory_order_acq_rel); // expected-error {{First argument cannot be a pointer to an object of size zero}} + __atomic_compare_exchange(a, b, c, 0, memory_order_acquire, memory_order_acquire); // expected-error {{First argument cannot be a pointer to an object of size zero}} + __atomic_compare_exchange(a, b, c, 0, memory_order_consume, memory_order_consume); // expected-error {{First argument cannot be a pointer to an object of size zero}} + __atomic_compare_exchange(a, b, c, 0, memory_order_release, memory_order_release); // expected-error {{First argument cannot be a pointer to an object of size zero}} + __atomic_compare_exchange(a, b, c, 0, memory_order_seq_cst, memory_order_seq_cst); // expected-error {{First argument cannot be a pointer to an object of size zero}} + +} + void nullPointerWarning(void) { volatile _Atomic(int) vai; _Atomic(int) ai; `````````` </details> https://github.com/llvm/llvm-project/pull/91057 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits