From f25f4265a8c27fd6d40db03eabdc97f75f091fd3 Mon Sep 17 00:00:00 2001 From: ziruichen Date: Tue, 16 Dec 2025 19:43:26 +0800 Subject: [PATCH 1/2] [borrow] fix coredump when performing c style cast from non borrow qualified to borrow qualified type in call expr. --- clang/lib/Sema/BSC/SemaDeclBSC.cpp | 16 ++++++++++++++ .../borrow_qual_Cstyle_Cast_in_call_expr.cbs | 21 +++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 clang/test/BSC/Positive/Ownership/borrow_check_rules/borrow_qual_Cstyle_Cast_in_call_expr/borrow_qual_Cstyle_Cast_in_call_expr.cbs diff --git a/clang/lib/Sema/BSC/SemaDeclBSC.cpp b/clang/lib/Sema/BSC/SemaDeclBSC.cpp index c9991e601175..26d6978fb197 100644 --- a/clang/lib/Sema/BSC/SemaDeclBSC.cpp +++ b/clang/lib/Sema/BSC/SemaDeclBSC.cpp @@ -530,6 +530,22 @@ public: FPOptionsOverride()); replacedNodesMap.Insert(E, UO); } + } else if (CStyleCastExpr *CSCE = dyn_cast(E)) { + // Handle cast from non-borrow to borrow qualified type. + if (CSCE->getType().isBorrowQualified()) { + Expr *SubExpr = CSCE->getSubExpr()->IgnoreParenImpCasts(); + if (DeclRefExpr *DRE = dyn_cast(SubExpr)) { + if (!DRE->getType().isBorrowQualified()) { + E = ReplaceWithTemporaryVariable(CSCE); + CastKind Kind = + E->getType()->getAsCXXRecordDecl() ? CK_NoOp : CK_LValueToRValue; + E = ImplicitCastExpr::Create(getSema().Context, E->getType(), Kind, E, + nullptr, VK_PRValue, + FPOptionsOverride()); + replacedNodesMap.Insert(E, CSCE); + } + } + } } CE->setArg(i, E); } diff --git a/clang/test/BSC/Positive/Ownership/borrow_check_rules/borrow_qual_Cstyle_Cast_in_call_expr/borrow_qual_Cstyle_Cast_in_call_expr.cbs b/clang/test/BSC/Positive/Ownership/borrow_check_rules/borrow_qual_Cstyle_Cast_in_call_expr/borrow_qual_Cstyle_Cast_in_call_expr.cbs new file mode 100644 index 000000000000..11d9904a33ef --- /dev/null +++ b/clang/test/BSC/Positive/Ownership/borrow_check_rules/borrow_qual_Cstyle_Cast_in_call_expr/borrow_qual_Cstyle_Cast_in_call_expr.cbs @@ -0,0 +1,21 @@ +// RUN: %clang %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +int *borrow foo(int *borrow a, int *borrow b){ + return a; +} + +void test(int *p, int *q) { + int *borrow m = foo((int *borrow)p, (int *borrow)q); +} + +int main(){ + int * a = malloc(sizeof(int)); + int * b = malloc(sizeof(int)); + test(a,b); + return 0; +} \ No newline at end of file -- Gitee From 9740c803ff3889e1eb53d870f42ffbb9e04c005c Mon Sep 17 00:00:00 2001 From: ziruichen Date: Tue, 16 Dec 2025 20:31:42 +0800 Subject: [PATCH 2/2] [borrow] fix coredump when init an borrow qualified array. also reconstrcuted ReplaceWithTemporaryVariable to avoid code duplication --- clang/lib/Analysis/BSC/BSCBorrowChecker.cpp | 38 ++++++- clang/lib/Sema/BSC/SemaDeclBSC.cpp | 100 ++++-------------- .../cstyle_cast_in_callexpr.cbs | 8 ++ .../borrow_array_int/borrow_array_int.cbs | 16 +++ 4 files changed, 80 insertions(+), 82 deletions(-) create mode 100644 clang/test/BSC/Negative/Ownership/Borrow/borrow_check_rules/cstyle_cast_in_callexpr/cstyle_cast_in_callexpr.cbs create mode 100644 clang/test/BSC/Positive/Ownership/borrow_check_rules/borrow_array_int/borrow_array_int.cbs diff --git a/clang/lib/Analysis/BSC/BSCBorrowChecker.cpp b/clang/lib/Analysis/BSC/BSCBorrowChecker.cpp index 6988056cee8f..95bf6993442e 100644 --- a/clang/lib/Analysis/BSC/BSCBorrowChecker.cpp +++ b/clang/lib/Analysis/BSC/BSCBorrowChecker.cpp @@ -486,8 +486,8 @@ void ActionExtract::VisitDeclStmt(DeclStmt *DS) { // the DeclStmt. for (Decl *D : DS->decls()) { if (VarDecl *VD = dyn_cast(D)) { - if (VD->getType()->isStructureType() && IsTrackedType(VD->getType()) && - isa(VD->getInit())) { + if ((VD->getType()->isStructureType() || VD->getType()->isArrayType()) && + IsTrackedType(VD->getType()) && isa(VD->getInit())) { BuildOnGet = false; Dest = std::make_unique(VD->getName().str(), VD->getType(), VD->getLocation()); @@ -514,14 +514,15 @@ void ActionExtract::VisitDeclStmt(DeclStmt *DS) { } void ActionExtract::VisitInitListExpr(InitListExpr *ILE) { - if (IsTrackedType(ILE->getType())) { + if (const RecordType *RT = + dyn_cast(ILE->getType().getCanonicalType()); + RT && IsTrackedType(ILE->getType())) { + // Handle struct/union initialization with tracked fields Kind = Action::Noop; RegionName RN = RNL; RegionName CurRN; std::unique_ptr Base = std::make_unique(*Dest); unsigned Index = 0; - const RecordType *RT = - dyn_cast(ILE->getType().getCanonicalType()); for (FieldDecl *Field : RT->getDecl()->fields()) { Kind = Action::Assign; std::unique_ptr FieldName = std::make_unique(*Base); @@ -540,6 +541,33 @@ void ActionExtract::VisitInitListExpr(InitListExpr *ILE) { BuildAction(); ++Index; } + } else if (ILE->getType()->isArrayType() && IsTrackedType(ILE->getType())) { + // Handle array initialization with borrow-qualified elements + Kind = Action::Noop; + RegionName RN = RNL; + RegionName CurRN; + std::unique_ptr Base = std::make_unique(*Dest); + const ArrayType *AT = ILE->getType()->getAsArrayTypeUnsafe(); + QualType ElementType = AT->getElementType(); + unsigned Index = 0; + for (Expr *Init : ILE->inits()) { + Kind = Action::Assign; + std::unique_ptr ArrayElem = std::make_unique(*Base); + ArrayElem = std::make_unique( + std::move(ArrayElem), "[" + std::to_string(Index) + "]", + ElementType, ILE->getBeginLoc()); + Dest = std::move(ArrayElem); + if (IsTrackedType(ElementType)) + CurRN = RN; + RNL = CurRN; + op = RHS; + Visit(Init); + if (RNL.isInvalid() || RNR.isInvalid() || Sources.empty()) + Kind = Action::Init; + if (Dest) + BuildAction(); + ++Index; + } } else { for (Expr *Init : ILE->inits()) { Visit(Init); diff --git a/clang/lib/Sema/BSC/SemaDeclBSC.cpp b/clang/lib/Sema/BSC/SemaDeclBSC.cpp index 26d6978fb197..304d02b91e4e 100644 --- a/clang/lib/Sema/BSC/SemaDeclBSC.cpp +++ b/clang/lib/Sema/BSC/SemaDeclBSC.cpp @@ -291,6 +291,16 @@ class BorrowCheckerPrologue : public TreeTransform { E->getType(), VK_LValue); } + // Replace with temporary variable and wrap in ImplicitCastExpr. + Expr *ReplaceWithTemporaryVariableAndWrap(Expr *E) { + DeclRefExpr *DRE = ReplaceWithTemporaryVariable(E); + CastKind Kind = + DRE->getType()->getAsCXXRecordDecl() ? CK_NoOp : CK_LValueToRValue; + return ImplicitCastExpr::Create(getSema().Context, DRE->getType(), Kind, + DRE, nullptr, VK_PRValue, + FPOptionsOverride()); + } + CompoundStmt *GetOrWrapWithCompoundStmt(Stmt *S) { if (isa(S)) return dyn_cast(S); @@ -428,23 +438,13 @@ public: ExprResult Res = getDerived().TransformExpr(RS->getRetValue()); Expr *E = Res.get(); if (CallExpr *CE = dyn_cast_or_null(E)) { - DeclRefExpr *DRE = ReplaceWithTemporaryVariable(CE); - CastKind Kind = - DRE->getType()->getAsCXXRecordDecl() ? CK_NoOp : CK_LValueToRValue; - ImplicitCastExpr *ICE = - ImplicitCastExpr::Create(getSema().Context, DRE->getType(), Kind, DRE, - nullptr, VK_PRValue, FPOptionsOverride()); + Expr *ICE = ReplaceWithTemporaryVariableAndWrap(CE); replacedNodesMap.Insert(ICE, CE); RS->setRetValue(ICE); return RS; } if (UnaryOperator *UO = dyn_cast(E)) { - DeclRefExpr *DRE = ReplaceWithTemporaryVariable(UO); - CastKind Kind = - DRE->getType()->getAsCXXRecordDecl() ? CK_NoOp : CK_LValueToRValue; - ImplicitCastExpr *ICE = - ImplicitCastExpr::Create(getSema().Context, DRE->getType(), Kind, DRE, - nullptr, VK_PRValue, FPOptionsOverride()); + Expr *ICE = ReplaceWithTemporaryVariableAndWrap(UO); replacedNodesMap.Insert(ICE, UO); RS->setRetValue(ICE); return RS; @@ -477,12 +477,7 @@ public: ExprResult ResLHS = getDerived().TransformExpr(BO->getLHS()); Expr *ELHS = ResLHS.get(); if (CallExpr *CE = dyn_cast(ELHS)) { - DeclRefExpr *DRE = ReplaceWithTemporaryVariable(CE); - CastKind Kind = - DRE->getType()->getAsCXXRecordDecl() ? CK_NoOp : CK_LValueToRValue; - ELHS = - ImplicitCastExpr::Create(getSema().Context, DRE->getType(), Kind, DRE, - nullptr, VK_PRValue, FPOptionsOverride()); + ELHS = ReplaceWithTemporaryVariableAndWrap(CE); replacedNodesMap.Insert(ELHS, CE); } BO->setLHS(ELHS); @@ -491,12 +486,7 @@ public: Expr *ERHS = ResRHS.get(); if (BO->getOpcode() < BO_Assign) { if (CallExpr *CE = dyn_cast(ERHS)) { - DeclRefExpr *DRE = ReplaceWithTemporaryVariable(CE); - CastKind Kind = - DRE->getType()->getAsCXXRecordDecl() ? CK_NoOp : CK_LValueToRValue; - ERHS = ImplicitCastExpr::Create(getSema().Context, DRE->getType(), Kind, - DRE, nullptr, VK_PRValue, - FPOptionsOverride()); + ERHS = ReplaceWithTemporaryVariableAndWrap(CE); replacedNodesMap.Insert(ERHS, CE); } } @@ -513,21 +503,12 @@ public: Expr *E = Res.get(); if (CallExpr *NestedCall = dyn_cast(E)) { - E = ReplaceWithTemporaryVariable(NestedCall); - CastKind Kind = - E->getType()->getAsCXXRecordDecl() ? CK_NoOp : CK_LValueToRValue; - E = ImplicitCastExpr::Create(getSema().Context, E->getType(), Kind, E, - nullptr, VK_PRValue, FPOptionsOverride()); + E = ReplaceWithTemporaryVariableAndWrap(NestedCall); replacedNodesMap.Insert(E, NestedCall); } else if (UnaryOperator *UO = dyn_cast(E)) { if (UO->getOpcode() >= UO_AddrMut && UO->getOpcode() <= UO_AddrConstDeref) { - E = ReplaceWithTemporaryVariable(UO); - CastKind Kind = - E->getType()->getAsCXXRecordDecl() ? CK_NoOp : CK_LValueToRValue; - E = ImplicitCastExpr::Create(getSema().Context, E->getType(), Kind, E, - nullptr, VK_PRValue, - FPOptionsOverride()); + E = ReplaceWithTemporaryVariableAndWrap(UO); replacedNodesMap.Insert(E, UO); } } else if (CStyleCastExpr *CSCE = dyn_cast(E)) { @@ -536,12 +517,7 @@ public: Expr *SubExpr = CSCE->getSubExpr()->IgnoreParenImpCasts(); if (DeclRefExpr *DRE = dyn_cast(SubExpr)) { if (!DRE->getType().isBorrowQualified()) { - E = ReplaceWithTemporaryVariable(CSCE); - CastKind Kind = - E->getType()->getAsCXXRecordDecl() ? CK_NoOp : CK_LValueToRValue; - E = ImplicitCastExpr::Create(getSema().Context, E->getType(), Kind, E, - nullptr, VK_PRValue, - FPOptionsOverride()); + E = ReplaceWithTemporaryVariableAndWrap(CSCE); replacedNodesMap.Insert(E, CSCE); } } @@ -603,13 +579,7 @@ public: } else if (UnaryOperator *UO = dyn_cast(E)) { if (UO->getOpcode() >= UO_AddrMut && UO->getOpcode() <= UO_AddrConstDeref) { - E = ReplaceWithTemporaryVariable(UO); - CastKind Kind = - E->getType()->getAsCXXRecordDecl() ? CK_NoOp : CK_LValueToRValue; - ImplicitCastExpr *ICE = ImplicitCastExpr::Create( - getSema().Context, E->getType(), Kind, E, nullptr, VK_PRValue, - FPOptionsOverride()); - E = ICE; + E = ReplaceWithTemporaryVariableAndWrap(UO); replacedNodesMap.Insert(E, UO); } } @@ -622,11 +592,7 @@ public: ExprResult Res = getDerived().TransformExpr(ME->getBase()); Expr *E = Res.get(); if (CallExpr *CE = dyn_cast(E)) { - E = ReplaceWithTemporaryVariable(CE); - CastKind Kind = - E->getType()->getAsCXXRecordDecl() ? CK_NoOp : CK_LValueToRValue; - E = ImplicitCastExpr::Create(getSema().Context, E->getType(), Kind, E, - nullptr, VK_PRValue, FPOptionsOverride()); + E = ReplaceWithTemporaryVariableAndWrap(CE); replacedNodesMap.Insert(E, CE); } ME->setBase(E); @@ -637,20 +603,10 @@ public: ExprResult Res = getDerived().TransformExpr(PE->getSubExpr()); Expr *E = Res.get(); if (CallExpr *CE = dyn_cast(E)) { - DeclRefExpr *DRE = ReplaceWithTemporaryVariable(E); - CastKind Kind = - DRE->getType()->getAsCXXRecordDecl() ? CK_NoOp : CK_LValueToRValue; - E = ImplicitCastExpr::Create(getSema().Context, DRE->getType(), Kind, - DRE, nullptr, VK_PRValue, - FPOptionsOverride()); + E = ReplaceWithTemporaryVariableAndWrap(E); replacedNodesMap.Insert(E, CE); } else if (BinaryOperator *BO = dyn_cast(E)) { - DeclRefExpr *DRE = ReplaceWithTemporaryVariable(E); - CastKind Kind = - DRE->getType()->getAsCXXRecordDecl() ? CK_NoOp : CK_LValueToRValue; - E = ImplicitCastExpr::Create(getSema().Context, DRE->getType(), Kind, - DRE, nullptr, VK_PRValue, - FPOptionsOverride()); + E = ReplaceWithTemporaryVariableAndWrap(E); replacedNodesMap.Insert(E, BO); } PE->setSubExpr(E); @@ -669,20 +625,10 @@ public: Expr *E = Res.get(); if (UO->getOpcode() == UO_Deref) { if (CallExpr *CE = dyn_cast(E)) { - DeclRefExpr *DRE = ReplaceWithTemporaryVariable(E); - CastKind Kind = - DRE->getType()->getAsCXXRecordDecl() ? CK_NoOp : CK_LValueToRValue; - E = ImplicitCastExpr::Create(getSema().Context, DRE->getType(), Kind, - DRE, nullptr, VK_PRValue, - FPOptionsOverride()); + E = ReplaceWithTemporaryVariableAndWrap(E); replacedNodesMap.Insert(E, CE); } else if (BinaryOperator *BO = dyn_cast(E)) { - DeclRefExpr *DRE = ReplaceWithTemporaryVariable(E); - CastKind Kind = - DRE->getType()->getAsCXXRecordDecl() ? CK_NoOp : CK_LValueToRValue; - E = ImplicitCastExpr::Create(getSema().Context, DRE->getType(), Kind, - DRE, nullptr, VK_PRValue, - FPOptionsOverride()); + E = ReplaceWithTemporaryVariableAndWrap(E); replacedNodesMap.Insert(E, BO); } } diff --git a/clang/test/BSC/Negative/Ownership/Borrow/borrow_check_rules/cstyle_cast_in_callexpr/cstyle_cast_in_callexpr.cbs b/clang/test/BSC/Negative/Ownership/Borrow/borrow_check_rules/cstyle_cast_in_callexpr/cstyle_cast_in_callexpr.cbs new file mode 100644 index 000000000000..4b1aeb273c70 --- /dev/null +++ b/clang/test/BSC/Negative/Ownership/Borrow/borrow_check_rules/cstyle_cast_in_callexpr/cstyle_cast_in_callexpr.cbs @@ -0,0 +1,8 @@ +// RUN: %clang_cc1 -verify %s + +int *borrow foo(int *borrow p, int *borrow q); + +void test(int *p) { + int *borrow m = foo((int *borrow)p, (int *borrow)p); // expected-error {{cannot borrow `*p` as mutable more than once at a time}} // expected-note {{first mut borrow occurs here}} + *m = 2; +} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Ownership/borrow_check_rules/borrow_array_int/borrow_array_int.cbs b/clang/test/BSC/Positive/Ownership/borrow_check_rules/borrow_array_int/borrow_array_int.cbs new file mode 100644 index 000000000000..fef908dfeba7 --- /dev/null +++ b/clang/test/BSC/Positive/Ownership/borrow_check_rules/borrow_array_int/borrow_array_int.cbs @@ -0,0 +1,16 @@ +// RUN: %clang %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +void test(int *borrow p) { + int *borrow arr[2] = {p}; +} + +int main(){ + int * borrow a = (int* borrow)malloc(sizeof(int)); + test(a); + return 0; +} -- Gitee