Skip to content

Commit 9439c4f

Browse files
committed
Issue: #397
#397 Partial commit. Added a call to handle NT_CHECKED initializers. If the type of the declaration requires NT_CHECKED, the last item in the initializer list is validated to make sure it is null (nullptr, NULL, 0 or '\0' depending on what's appropriate). Pending: 1. Handle all types (Constant char arrays are not handled yet.) 2. Tests (Add tests for ptr to NT_CHECKED types, NT_CHECKED array, Struct that contains one or both of the previous two cases) 3. Error handling. The current version of the compiler crashes if the NT_CHECKED array is not null terminated.
1 parent d51978f commit 9439c4f

File tree

3 files changed

+88
-41
lines changed

3 files changed

+88
-41
lines changed

include/clang/AST/Expr.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4408,6 +4408,15 @@ class InitListExpr : public Expr {
44084408
/// idiomatic?
44094409
bool isIdiomaticZeroInitializer(const LangOptions &LangOpts) const;
44104410

4411+
/// If the Type of InitListExpr is _NT_CHECKED array or pointer to _NT_CHECKED array
4412+
/// the initializer must end with null terminator. Returns true if null terminator is
4413+
/// not required, or if null terminator is required and it exists.
4414+
/// Returns false if null terminator is missing for _NT_CHECKED array or pointer to _NT_CHECKED
4415+
/// array types
4416+
bool handleNullTerminationCheck(ASTContext &C,
4417+
const InitListExpr *Init,
4418+
QualType VDeclType) const;
4419+
44114420
SourceLocation getLBraceLoc() const { return LBraceLoc; }
44124421
void setLBraceLoc(SourceLocation Loc) { LBraceLoc = Loc; }
44134422
SourceLocation getRBraceLoc() const { return RBraceLoc; }

lib/AST/Expr.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2001,6 +2001,33 @@ bool InitListExpr::isIdiomaticZeroInitializer(const LangOptions &LangOpts) const
20012001
return Lit && Lit->getValue() == 0;
20022002
}
20032003

2004+
bool InitListExpr::handleNullTerminationCheck(ASTContext &C, const InitListExpr *Init, QualType VDeclType) const {
2005+
//Init->dump();
2006+
QualType T = Init->getType();
2007+
// Null termination required only for _NT_CHECKED arrays and for pointers to
2008+
// _NT_CHECKED arrays
2009+
if (!VDeclType->isNtCheckedArrayType()) {
2010+
if (!T->isCheckedPointerNtArrayType()) {
2011+
return true;
2012+
}
2013+
}
2014+
2015+
assert(isSemanticForm() && "Null terminator check must be performed "
2016+
"after all the initialization of all "
2017+
"subobjects are made explicit");
2018+
2019+
const Expr *LastItem = getInit(InitExprs.size() - 1);
2020+
/*if (T->isCheckedPointerArrayType()) {
2021+
2022+
} else if (T->isNtCheckedArrayType()) {
2023+
LastItem->isNu
2024+
2025+
}*/
2026+
Expr::NullPointerConstantKind E = LastItem->isNullPointerConstant(C, Expr::NPC_ValueDependentIsNull);
2027+
return E != NPCK_NotNull;
2028+
//return LastItem == NULL;
2029+
}
2030+
20042031
SourceLocation InitListExpr::getLocStart() const {
20052032
if (InitListExpr *SyntacticForm = getSyntacticForm())
20062033
return SyntacticForm->getLocStart();

lib/Sema/SemaDecl.cpp

Lines changed: 52 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -10925,6 +10925,17 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit,
1092510925
VDecl->setInvalidDecl();
1092610926
}
1092710927

10928+
if (InitListExpr *E = dyn_cast<InitListExpr>(Init)) {
10929+
/// $TODO$ Remove dump calls.
10930+
/// $TODO$ Handle constant string types (char array)
10931+
//Init->dump();
10932+
//RealDecl->is
10933+
if (!E->handleNullTerminationCheck(RealDecl->getASTContext(), E, VDecl->getType())) {
10934+
RealDecl->setInvalidDecl();
10935+
return;
10936+
}
10937+
}
10938+
1092810939
// If adding the initializer will turn this declaration into a definition,
1092910940
// and we already have a definition for this variable, diagnose or otherwise
1093010941
// handle the situation.
@@ -11394,47 +11405,47 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) {
1139411405
else if (B && !B->isInvalid() && !B->isUnknown() && !Ty->isArrayType())
1139511406
Diag(Var->getLocation(), diag::err_initializer_expected_with_bounds)
1139611407
<< Var;
11397-
11398-
// An unchecked pointer in a checked scope with a bounds expression must be initialized
11399-
if (Ty->isUncheckedPointerType() && InCheckedScope && Var->hasBoundsExpr())
11400-
Diag(Var->getLocation(), diag::err_initializer_expected_for_unchecked_pointer_in_checked_scope_with_bounds_expr)
11401-
<< Var;
11402-
11403-
// An integer with a bounds expression must be initialized
11404-
if (Ty->isIntegerType() && Var->hasBoundsExpr())
11405-
Diag(Var->getLocation(), diag::err_initializer_expected_for_integer_with_bounds_expr)
11406-
<< Var;
11407-
11408-
// struct/union and array with checked pointer members must have initializers
11409-
// array with checked ptr element
11410-
if (Ty->isArrayType()) {
11411-
// if this is an array type, check the element type of the array, potentially with type qualifiers missing
11412-
if (Type::HasCheckedValue == Ty->getPointeeOrArrayElementType()->containsCheckedValue(InCheckedScope))
11413-
Diag(Var->getLocation(), diag::err_initializer_expected_for_array)
11414-
<< Var;
11415-
}
11416-
// RecordType(struct/union) with checked pointer member
11417-
if (Ty->isRecordType()) {
11418-
const RecordType *RT = Ty->getAs<RecordType>();
11419-
switch (RT->containsCheckedValue(InCheckedScope)) {
11420-
default:
11421-
break;
11422-
case Type::HasCheckedValue: {
11423-
Diag(Var->getLocation(), diag::err_initializer_expected_for_record_with_checked_value)
11424-
<< RT->getDecl()->getTagKind() << Var;
11425-
break;
11426-
}
11427-
case Type::HasIntWithBounds: {
11428-
Diag(Var->getLocation(), diag::err_initializer_expected_for_record_with_integer_member_with_bounds_expr)
11429-
<< RT->getDecl()->getTagKind() << Var;
11430-
break;
11431-
}
11432-
case Type::HasUncheckedPointer: {
11433-
Diag(Var->getLocation(), diag::err_initializer_expected_for_record_with_unchecked_pointer_in_checked_scope)
11434-
<< RT->getDecl()->getTagKind() << Var;
11435-
break;
11436-
}
11437-
}
11408+
11409+
// An unchecked pointer in a checked scope with a bounds expression must be initialized
11410+
if (Ty->isUncheckedPointerType() && InCheckedScope && Var->hasBoundsExpr())
11411+
Diag(Var->getLocation(), diag::err_initializer_expected_for_unchecked_pointer_in_checked_scope_with_bounds_expr)
11412+
<< Var;
11413+
11414+
// An integer with a bounds expression must be initialized
11415+
if (Ty->isIntegerType() && Var->hasBoundsExpr())
11416+
Diag(Var->getLocation(), diag::err_initializer_expected_for_integer_with_bounds_expr)
11417+
<< Var;
11418+
11419+
// struct/union and array with checked pointer members must have initializers
11420+
// array with checked ptr element
11421+
if (Ty->isArrayType()) {
11422+
// if this is an array type, check the element type of the array, potentially with type qualifiers missing
11423+
if (Type::HasCheckedValue == Ty->getPointeeOrArrayElementType()->containsCheckedValue(InCheckedScope))
11424+
Diag(Var->getLocation(), diag::err_initializer_expected_for_array)
11425+
<< Var;
11426+
}
11427+
// RecordType(struct/union) with checked pointer member
11428+
if (Ty->isRecordType()) {
11429+
const RecordType *RT = Ty->getAs<RecordType>();
11430+
switch (RT->containsCheckedValue(InCheckedScope)) {
11431+
default:
11432+
break;
11433+
case Type::HasCheckedValue: {
11434+
Diag(Var->getLocation(), diag::err_initializer_expected_for_record_with_checked_value)
11435+
<< RT->getDecl()->getTagKind() << Var;
11436+
break;
11437+
}
11438+
case Type::HasIntWithBounds: {
11439+
Diag(Var->getLocation(), diag::err_initializer_expected_for_record_with_integer_member_with_bounds_expr)
11440+
<< RT->getDecl()->getTagKind() << Var;
11441+
break;
11442+
}
11443+
case Type::HasUncheckedPointer: {
11444+
Diag(Var->getLocation(), diag::err_initializer_expected_for_record_with_unchecked_pointer_in_checked_scope)
11445+
<< RT->getDecl()->getTagKind() << Var;
11446+
break;
11447+
}
11448+
}
1143811449
}
1143911450
}
1144011451

0 commit comments

Comments
 (0)