heatd created this revision. Herald added a project: All. heatd requested review of this revision. Herald added subscribers: cfe-commits, MaskRay. Herald added a project: clang.
Add -fcheck-new and -fno-check-new, from GCC, which make the compiler not assume pointers returned from operator new are non-null. Fixes #16931. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D125272 Files: clang/include/clang/Basic/LangOptions.def clang/include/clang/Basic/LangOptions.h clang/include/clang/Driver/Options.td clang/lib/AST/ExprCXX.cpp clang/lib/Driver/ToolChains/Clang.cpp clang/lib/Frontend/CompilerInvocation.cpp clang/lib/Sema/SemaDecl.cpp clang/lib/Sema/SemaExprCXX.cpp clang/test/CodeGenCXX/fcheck-new.cpp clang/test/Driver/clang_f_opts.c
Index: clang/test/Driver/clang_f_opts.c =================================================================== --- clang/test/Driver/clang_f_opts.c +++ clang/test/Driver/clang_f_opts.c @@ -70,7 +70,6 @@ // CHECK-CUDA-SAMPLE-PROFILE: "-cc1" // CHECK-CUDA-SAMPLE-PROFILE-SAME: "-fprofile-sample-use={{.*}}/file.prof" - // RUN: %clang -### -S -fauto-profile=%S/Inputs/file.prof %s 2>&1 | FileCheck -check-prefix=CHECK-AUTO-PROFILE %s // CHECK-AUTO-PROFILE: "-fprofile-sample-use={{.*}}/file.prof" @@ -298,7 +297,6 @@ // RUN: -fno-reorder-blocks -freorder-blocks \ // RUN: -fno-schedule-insns2 -fschedule-insns2 \ // RUN: -fno-stack-check \ -// RUN: -fno-check-new -fcheck-new \ // RUN: -ffriend-injection \ // RUN: -fno-implement-inlines -fimplement-inlines \ // RUN: -fstack-check \ Index: clang/test/CodeGenCXX/fcheck-new.cpp =================================================================== --- /dev/null +++ clang/test/CodeGenCXX/fcheck-new.cpp @@ -0,0 +1,20 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py +// RUN: %clang -fcheck-new -emit-llvm -S %s -o - -O2 | FileCheck %s + +// CHECK-LABEL: @_Z5test0v( +// CHECK-NEXT: [[TMP1:%.*]] = tail call noalias noundef dereferenceable_or_null(4) ptr @_Znwm(i64 noundef 4) #[[ATTR2:[0-9]+]] +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq ptr [[TMP1]], null +// CHECK-NEXT: br i1 [[TMP2]], label [[TMP4:%.*]], label [[TMP3:%.*]] +// CHECK: 3: +// CHECK-NEXT: store i32 48879, ptr [[TMP1]], align 4, !tbaa [[TBAA5:![0-9]+]] +// CHECK-NEXT: br label [[TMP4]] +// CHECK: 4: +// CHECK-NEXT: ret ptr [[TMP1]] +// +int *test0() { + int *ptr = new int; + if (!ptr) + return (int *)0; + *ptr = 0xbeef; + return ptr; +} Index: clang/lib/Sema/SemaExprCXX.cpp =================================================================== --- clang/lib/Sema/SemaExprCXX.cpp +++ clang/lib/Sema/SemaExprCXX.cpp @@ -3104,7 +3104,8 @@ // Global allocation functions should always be visible. Alloc->setVisibleDespiteOwningModule(); - if (HasBadAllocExceptionSpec && getLangOpts().NewInfallible) + if (HasBadAllocExceptionSpec && getLangOpts().NewInfallible && + !getLangOpts().CheckNew) Alloc->addAttr( ReturnsNonNullAttr::CreateImplicit(Context, Alloc->getLocation())); Index: clang/lib/Sema/SemaDecl.cpp =================================================================== --- clang/lib/Sema/SemaDecl.cpp +++ clang/lib/Sema/SemaDecl.cpp @@ -15436,7 +15436,11 @@ // indicates failure by returning a null pointer value. Any other allocation // function never returns a null pointer value and indicates failure only by // throwing an exception [...] - if (!IsNothrow && !FD->hasAttr<ReturnsNonNullAttr>()) + // + // However, -fcheck-new violates this possible assumption, so don't add + // NonNull when that is enabled. + if (!IsNothrow && !FD->hasAttr<ReturnsNonNullAttr>() && + !getLangOpts().CheckNew) FD->addAttr(ReturnsNonNullAttr::CreateImplicit(Context, FD->getLocation())); // C++2a [basic.stc.dynamic.allocation]p2: Index: clang/lib/Frontend/CompilerInvocation.cpp =================================================================== --- clang/lib/Frontend/CompilerInvocation.cpp +++ clang/lib/Frontend/CompilerInvocation.cpp @@ -4113,6 +4113,9 @@ if (const Arg *A = Args.getLastArg(OPT_frandomize_layout_seed_EQ)) Opts.RandstructSeed = A->getValue(0); + if (const Arg *A = Args.getLastArg(OPT_fcheck_new)) + Opts.CheckNew = true; + return Diags.getNumErrors() == NumErrorsBefore; } Index: clang/lib/Driver/ToolChains/Clang.cpp =================================================================== --- clang/lib/Driver/ToolChains/Clang.cpp +++ clang/lib/Driver/ToolChains/Clang.cpp @@ -5981,6 +5981,9 @@ options::OPT_fno_emulated_tls); Args.AddLastArg(CmdArgs, options::OPT_fzero_call_used_regs_EQ); + if (Args.hasFlag(options::OPT_fcheck_new, options::OPT_fno_check_new, false)) + CmdArgs.push_back("-fcheck-new"); + if (Arg *A = Args.getLastArg(options::OPT_fzero_call_used_regs_EQ)) { // FIXME: There's no reason for this to be restricted to X86. The backend // code needs to be changed to include the appropriate function calls Index: clang/lib/AST/ExprCXX.cpp =================================================================== --- clang/lib/AST/ExprCXX.cpp +++ clang/lib/AST/ExprCXX.cpp @@ -275,6 +275,8 @@ } bool CXXNewExpr::shouldNullCheckAllocation() const { + if (getOperatorNew()->getLangOpts().CheckNew) + return true; return !getOperatorNew()->hasAttr<ReturnsNonNullAttr>() && getOperatorNew() ->getType() Index: clang/include/clang/Driver/Options.td =================================================================== --- clang/include/clang/Driver/Options.td +++ clang/include/clang/Driver/Options.td @@ -4579,7 +4579,11 @@ // ignore it for now to avoid breaking builds that use it. def fdiagnostics_show_location_EQ : Joined<["-"], "fdiagnostics-show-location=">, Group<clang_ignored_f_Group>; -defm fcheck_new : BooleanFFlag<"check-new">, Group<clang_ignored_f_Group>; +defm check_new : BoolFOption<"check-new", + LangOpts<"CheckNew">, DefaultFalse, + PosFlag<SetTrue, [], "Check for a null pointer before using storage allocated by new">, + NegFlag<SetFalse>, BothFlags<[CC1Option]>>; + defm caller_saves : BooleanFFlag<"caller-saves">, Group<clang_ignored_gcc_optimization_f_Group>; defm reorder_blocks : BooleanFFlag<"reorder-blocks">, Group<clang_ignored_gcc_optimization_f_Group>; defm branch_count_reg : BooleanFFlag<"branch-count-reg">, Group<clang_ignored_gcc_optimization_f_Group>; Index: clang/include/clang/Basic/LangOptions.h =================================================================== --- clang/include/clang/Basic/LangOptions.h +++ clang/include/clang/Basic/LangOptions.h @@ -452,6 +452,10 @@ /// The seed used by the randomize structure layout feature. std::string RandstructSeed; + // Indicates whether we should keep all nullptr checks for pointers + // received as a result of a standard operator new (-fcheck-new) + bool CheckNew = false; + LangOptions(); /// Set language defaults for the given input language and Index: clang/include/clang/Basic/LangOptions.def =================================================================== --- clang/include/clang/Basic/LangOptions.def +++ clang/include/clang/Basic/LangOptions.def @@ -443,6 +443,8 @@ VALUE_LANGOPT(FuchsiaAPILevel, 32, 0, "Fuchsia API level") +BENIGN_LANGOPT(CheckNew, 1, 0, "Do not eliminate null pointer checks for storage allocated by new") + #undef LANGOPT #undef COMPATIBLE_LANGOPT #undef BENIGN_LANGOPT
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits