From e1a99c4e2385474a404c404e69acab82db786364 Mon Sep 17 00:00:00 2001 From: Xiang Han Date: Mon, 14 Jul 2025 10:23:43 +0800 Subject: [PATCH] [Union] Fix union initialization bugs causing coredump in nullability check Summary: Fix two bugs related to union initialization that could cause coredump during nullability analysis in safezone: 1. In C, union initialization only initializes the first field, and the InitListExpr contains only one initializer. The previous code incorrectly treated union initialization the same as struct, iterating over all fields and trying to match each field with an initializer. This caused out-of-bounds access when looking for initializers for non-first fields in a union. 2. When initializing a union with an empty initializer list, the default value was not correctly added to the `InitList`. This led to an out-of-bounds access when the nullability check attempted to index into the `InitList` for the union. Both issues could trigger a coredump during nullability checking in safezone. This patch ensures that only the first field is processed for unions and that a default initializer is properly added when the initializer list is empty, preventing invalid memory access. Fix: ICL5JQ --- .../lib/Analysis/BSC/BSCNullabilityCheck.cpp | 16 ++++--- clang/lib/Sema/SemaInit.cpp | 11 ++++- .../safe_initialize_union.cbs | 47 +++++++++++++++++++ 3 files changed, 65 insertions(+), 9 deletions(-) create mode 100644 clang/test/BSC/Positive/SafeZone/safe_initialize_union/safe_initialize_union.cbs diff --git a/clang/lib/Analysis/BSC/BSCNullabilityCheck.cpp b/clang/lib/Analysis/BSC/BSCNullabilityCheck.cpp index dd0e64a5b374..79ffd703b9d5 100644 --- a/clang/lib/Analysis/BSC/BSCNullabilityCheck.cpp +++ b/clang/lib/Analysis/BSC/BSCNullabilityCheck.cpp @@ -115,7 +115,7 @@ public: void VisitDeclStmt(DeclStmt *S); void HandleVarDeclInit(DeclStmt *DS, VarDecl *VD); void HandlePointerInit(DeclStmt *DS, VarDecl *VD); - void HandleStructInit(DeclStmt *DS, VarDecl *VD); + void HandleStructUnionInit(DeclStmt *DS, VarDecl *VD); void HandleFieldInit(DeclStmt *DS, VarDecl *VD, FieldDecl *FD, Expr *FieldInit, std::string FullFieldPath); void VisitBinaryOperator(BinaryOperator *BO); @@ -128,7 +128,7 @@ public: void SetCFGBlocksByExpr(Expr *PtrE, const CFGBlock *NonNullBlock, const CFGBlock *NullableBlock); void PassConditionStatusToSuccBlocks(Stmt *Cond); - void HandleNestedStructInit(DeclStmt *DS, VarDecl *TopVD, RecordDecl *RD, + void HandleNestedStructUnionInit(DeclStmt *DS, VarDecl *TopVD, RecordDecl *RD, InitListExpr *InitList, std::string FieldPrefix); }; } // namespace @@ -310,7 +310,7 @@ void TransferFunctions::HandleVarDeclInit(DeclStmt *DS, VarDecl *VD) { if (VQT->isPointerType()) HandlePointerInit(DS, VD); else if (VQT->isRecordType()) - HandleStructInit(DS, VD); + HandleStructUnionInit(DS, VD); } // Init a pointer variable @@ -331,7 +331,7 @@ void TransferFunctions::HandlePointerInit(DeclStmt *DS, VarDecl *VD) { } // Init a struct variable with pointer fields. -void TransferFunctions::HandleStructInit(DeclStmt *DS, VarDecl *VD) { +void TransferFunctions::HandleStructUnionInit(DeclStmt *DS, VarDecl *VD) { if (auto RecTy = dyn_cast(VD->getType().getCanonicalType())) { if (RecordDecl *RD = RecTy->getDecl()) { if (Expr *Init = VD->getInit()) { @@ -351,14 +351,14 @@ void TransferFunctions::HandleStructInit(DeclStmt *DS, VarDecl *VD) { break; } if (auto InitListE = dyn_cast(Init)) { - HandleNestedStructInit(DS, VD, RD, InitListE, ""); + HandleNestedStructUnionInit(DS, VD, RD, InitListE, ""); } } } } } -void TransferFunctions::HandleNestedStructInit(DeclStmt *DS, VarDecl *TopVD, +void TransferFunctions::HandleNestedStructUnionInit(DeclStmt *DS, VarDecl *TopVD, RecordDecl *RD, InitListExpr *InitList, std::string FieldPrefix) { @@ -390,11 +390,13 @@ void TransferFunctions::HandleNestedStructInit(DeclStmt *DS, VarDecl *TopVD, dyn_cast(FD->getType().getCanonicalType())) { if (RecordDecl *nestedRD = nestedRecTy->getDecl()) { if (auto nestedInitList = dyn_cast(fieldInit)) { - HandleNestedStructInit(DS, TopVD, nestedRD, nestedInitList, + HandleNestedStructUnionInit(DS, TopVD, nestedRD, nestedInitList, fullFieldPath); } } } + if (RD->isUnion()) + break; } } diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index c605201445ff..1c51eaede728 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -781,8 +781,15 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity, if (const RecordType *RType = ILE->getType()->getAs()) { const RecordDecl *RDecl = RType->getDecl(); if (RDecl->isUnion() && ILE->getInitializedFieldInUnion()) - FillInEmptyInitForField(0, ILE->getInitializedFieldInUnion(), - Entity, ILE, RequiresSecondPass, FillWithNoInit); +#if ENABLE_BSC + { + ILE->resizeInits(SemaRef.Context, 1); +#endif + FillInEmptyInitForField(0, ILE->getInitializedFieldInUnion(), Entity, ILE, + RequiresSecondPass, FillWithNoInit); +#if ENABLE_BSC + } +#endif else if (RDecl->isUnion() && isa(RDecl) && cast(RDecl)->hasInClassInitializer()) { for (auto *Field : RDecl->fields()) { diff --git a/clang/test/BSC/Positive/SafeZone/safe_initialize_union/safe_initialize_union.cbs b/clang/test/BSC/Positive/SafeZone/safe_initialize_union/safe_initialize_union.cbs new file mode 100644 index 000000000000..4f02d25517f7 --- /dev/null +++ b/clang/test/BSC/Positive/SafeZone/safe_initialize_union/safe_initialize_union.cbs @@ -0,0 +1,47 @@ +// RUN: %clang %s -o %t.output +// RUN: %t.output +// expected-no-diagnostics + +union Union1 { + int x; +}; + +union Union2 { + int x; + char y; +}; + +union Union3 { + int x; + int y; +}; + +union Union4 { + char x; + int y; +}; + +int main() +{ + safe + { + union Union1 u11 = {}; + union Union1 u12 = {1}; + + union Union2 u21 = {}; + union Union2 u22 = {1}; + + union Union3 u31 = {}; + union Union3 u32 = {1}; + + union Union4 u41 = {}; + union Union4 u42 = {1}; + union Union4 u43 = {'1'}; + + unsafe{ + if(u11.x==0 && u12.x==1 && u21.x==0 && u22.x==1 && u31.x==0 && u32.x==1 && u41.x==0 && u42.x==1 && u43.x=='1') + return 0; + return 1; + } + } +} \ No newline at end of file -- Gitee