Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion clang/include/clang/Basic/DiagnosticIDs.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ enum {
DIAG_SIZE_AST = 300,
DIAG_SIZE_COMMENT = 100,
DIAG_SIZE_CROSSTU = 100,
DIAG_SIZE_SEMA = 5000,
DIAG_SIZE_SEMA = 5100,
DIAG_SIZE_ANALYSIS = 100,
DIAG_SIZE_REFACTORING = 1000,
DIAG_SIZE_INSTALLAPI = 100,
Expand Down
38 changes: 36 additions & 2 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -13611,6 +13611,9 @@ def err_bounds_safety_terminated_by_from_indexable_pointee_mismatch : Error<
def err_bounds_safety_incompatible_string_literal_to_terminated_by : Error<
"'__terminated_by' pointer converted from a string literal must be "
"NUL-terminated">;
def warn_unsafe_incompatible_string_literal_to_terminated_by : Warning<
err_bounds_safety_incompatible_string_literal_to_terminated_by.Summary>,
InGroup<UnsafeBufferUsage>, DefaultIgnore;

def note_fixit_null_terminated_to_indexable: Note<"consider using '%select{__null_terminated_to_indexable|__unsafe_null_terminated_to_indexable}0()' to perform this conversion. Note this conversion requires a linear scan of memory to find the null terminator and the resulting upper bound %select{excludes|includes}0 the null terminator">;
def note_fixit_unsafe_null_terminated_from_indexable : Note<"consider using '__unsafe_null_terminated_from_indexable()' to perform this conversion. Note this performs a linear scan of memory to find the null terminator">;
Expand All @@ -13634,6 +13637,9 @@ def err_bounds_safety_incompatible_terminated_by_terminators : Error<
"%diff{casting $ to incompatible type $|"
"casting type to incompatible type}0,1|"
"}2">;
def warn_unsafe_incompatible_terminated_by_terminators : Warning<
err_bounds_safety_incompatible_terminated_by_terminators.Summary>,
InGroup<UnsafeBufferUsage>, DefaultIgnore;
def err_bounds_safety_incompatible_terminated_by_to_non_terminated_by : Error<
"%select{"
"%diff{assigning to $ from incompatible type $|"
Expand All @@ -13652,6 +13658,9 @@ def err_bounds_safety_incompatible_terminated_by_to_non_terminated_by : Error<
"casting type to incompatible type}0,1|"
"}2 requires a linear search for the terminator; use "
"'%select{__terminated_by_to_indexable|__null_terminated_to_indexable}3()' to perform this conversion explicitly">;
def warn_unsafe_incompatible_terminated_by_to_non_terminated_by : Warning<
err_bounds_safety_incompatible_terminated_by_to_non_terminated_by.Summary>,
InGroup<UnsafeBufferUsage>, DefaultIgnore;
def warn_bounds_safety_incompatible_non_terminated_by_to_terminated_by : Warning<
"%select{"
"%diff{assigning to $ from incompatible type $|"
Expand All @@ -13673,6 +13682,9 @@ def warn_bounds_safety_incompatible_non_terminated_by_to_terminated_by : Warning
"; use '__unsafe_null_terminated_from_indexable()' or '__unsafe_forge_null_terminated()' to perform this conversion|"
"}3">, InGroup<BoundsSafetyStrictTerminatedByCast>, DefaultError;
def err_bounds_safety_incompatible_non_terminated_by_to_terminated_by : Error<warn_bounds_safety_incompatible_non_terminated_by_to_terminated_by.Summary>;
def warn_unsafe_incompatible_non_terminated_by_to_terminated_by : Warning<
warn_bounds_safety_incompatible_non_terminated_by_to_terminated_by.Summary>,
InGroup<UnsafeBufferUsage>, DefaultIgnore;
def err_bounds_safety_incompatible_terminated_by_to_non_terminated_by_mismatch : Error<
"%select{"
"%diff{assigning to $ from incompatible type $|"
Expand All @@ -13689,7 +13701,10 @@ def err_bounds_safety_incompatible_terminated_by_to_non_terminated_by_mismatch :
"sending type to parameter of incompatible type}0,1|"
"%diff{casting $ to incompatible type $|"
"casting type to incompatible type}0,1|"
"}2 that discards '__terminated_by' attribute is not allowed">;
"}2 that discards '__terminated_by' attribute%select{ is not allowed|}3">;
def warn_unsafe_incompatible_terminated_by_to_non_terminated_by_mismatch : Warning<
err_bounds_safety_incompatible_terminated_by_to_non_terminated_by_mismatch.Summary>,
InGroup<UnsafeBufferUsage>, DefaultIgnore;
def warn_bounds_safety_incompatible_non_terminated_by_to_terminated_by_mismatch : Warning<
"%select{"
"%diff{assigning to $ from incompatible type $|"
Expand All @@ -13706,22 +13721,41 @@ def warn_bounds_safety_incompatible_non_terminated_by_to_terminated_by_mismatch
"sending type to parameter of incompatible type}0,1|"
"%diff{casting $ to incompatible type $|"
"casting type to incompatible type}0,1|"
"}2 that adds '__terminated_by' attribute is not allowed">, InGroup<BoundsSafetyStrictTerminatedByCast>, DefaultError;
"}2 that adds '__terminated_by' attribute%select{ is not allowed|}3">,
InGroup<BoundsSafetyStrictTerminatedByCast>, DefaultError;
def err_bounds_safety_incompatible_non_terminated_by_to_terminated_by_mismatch : Error<warn_bounds_safety_incompatible_non_terminated_by_to_terminated_by_mismatch.Summary>;
def warn_unsafe_incompatible_non_terminated_by_to_terminated_by_mismatch : Warning<
warn_bounds_safety_incompatible_non_terminated_by_to_terminated_by_mismatch.Summary>,
InGroup<UnsafeBufferUsage>, DefaultIgnore;

def err_bounds_safety_terminated_by_uninitialized : Error<
"array '%0' with '__terminated_by' attribute must be initialized">;
def warn_unsafe_terminated_by_uninitialized : Warning<
err_bounds_safety_terminated_by_uninitialized.Summary>,
InGroup<UnsafeBufferUsage>, DefaultIgnore;
def err_bounds_safety_terminated_by_incomplete_array_empty_init : Error<
"incomplete array '%0' with '__terminated_by' attribute must be initialized "
"with at least one element">;
def warn_unsafe_terminated_by_incomplete_array_empty_init : Warning<
err_bounds_safety_terminated_by_incomplete_array_empty_init.Summary>,
InGroup<UnsafeBufferUsage>, DefaultIgnore;
def err_bounds_safety_terminated_by_terminator_in_array_must_be_const : Error<
"terminator in array '%0' must be a compile-time constant">;
def warn_unsafe_terminated_by_terminator_in_array_must_be_const : Warning<
err_bounds_safety_terminated_by_terminator_in_array_must_be_const.Summary>,
InGroup<UnsafeBufferUsage>, DefaultIgnore;
def err_bounds_safety_terminated_by_wrong_initializer_kind : Error<
"array '%0' with '__terminated_by' attribute must be initialized with a "
"string literal or an initializer list">;
def warn_unsafe_terminated_by_wrong_initializer_kind : Warning<
err_bounds_safety_terminated_by_wrong_initializer_kind.Summary>,
InGroup<UnsafeBufferUsage>, DefaultIgnore;
def err_bounds_safety_terminated_by_terminator_mismatch : Error<
"array '%0' with '__terminated_by' attribute is initialized with an "
"incorrect terminator (expected: %quoted1; got %quoted2)">;
def warn_unsafe_terminated_by_terminator_mismatch : Warning<
err_bounds_safety_terminated_by_terminator_mismatch.Summary>,
InGroup<UnsafeBufferUsage>, DefaultIgnore;

def err_bounds_safety_irrecoverable_attr : Error<
"bounds attribute '%select{__bidi_indexable|__indexable|__single|__unsafe_indexable}0' cannot be applied to attributed type %1 in this context%select{| due to the surrounding 'typeof' specifier}2">;
Expand Down
99 changes: 65 additions & 34 deletions clang/lib/Sema/SemaCast.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -239,9 +239,9 @@ namespace {
/// int *__bidi_indexable p1;
/// int *__indexable p2 = (int *__indexable)p1;
/// \endcode
if (Self.getLangOpts().BoundsSafety ||
Self.isCXXSafeBuffersBoundsSafetyInteropEnabledAt(
SrcExpr.get()->getBeginLoc())) {
bool isCXXSafeBuffersBoundsSafetyInterop =
Self.isCXXSafeBuffersBoundsSafetyInteropEnabledAt(OpRange.getBegin());
if (Self.getLangOpts().BoundsSafety || isCXXSafeBuffersBoundsSafetyInterop) {
unsigned DiagKind = 0;
bool isInvalid = false;
// The type error may be nested, so any pointer can result in VT errors
Expand All @@ -254,36 +254,51 @@ namespace {
break;
case AssignConvertType::
IncompatibleStringLiteralToValueTerminatedPointer:
DiagKind =
diag::err_bounds_safety_incompatible_string_literal_to_terminated_by;
isInvalid = true;
if (isCXXSafeBuffersBoundsSafetyInterop)
DiagKind =
diag::warn_unsafe_incompatible_string_literal_to_terminated_by;
else {
DiagKind = diag::
err_bounds_safety_incompatible_string_literal_to_terminated_by;
isInvalid = true;
}
break;
case AssignConvertType::IncompatibleValueTerminatedTerminators:
DiagKind = diag::err_bounds_safety_incompatible_terminated_by_terminators;
isInvalid = true;
if (isCXXSafeBuffersBoundsSafetyInterop)
DiagKind = diag::warn_unsafe_incompatible_terminated_by_terminators;
else {
DiagKind =
diag::err_bounds_safety_incompatible_terminated_by_terminators;
isInvalid = true;
}
break;
case AssignConvertType::
IncompatibleValueTerminatedToNonValueTerminatedPointer: {
const auto *SrcPointerType = SrcType->getAs<ValueTerminatedType>();
IsSrcNullTerm =
SrcPointerType->getTerminatorValue(Self.Context).isZero();
DiagKind = diag::
err_bounds_safety_incompatible_terminated_by_to_non_terminated_by;
isInvalid = true;
if (isCXXSafeBuffersBoundsSafetyInterop)
DiagKind = diag::
warn_unsafe_incompatible_terminated_by_to_non_terminated_by;
else {
DiagKind = diag::
err_bounds_safety_incompatible_terminated_by_to_non_terminated_by;
isInvalid = true;
}
break;
}
case AssignConvertType::
IncompatibleNonValueTerminatedToValueTerminatedPointer: {
const auto *DstPointerType = DestType->getAs<ValueTerminatedType>();
IsDstNullTerm =
DstPointerType->getTerminatorValue(Self.Context).isZero();
if (Self.getLangOpts().BoundsSafetyRelaxedSystemHeaders ||
Self.isCXXSafeBuffersBoundsSafetyInteropEnabledAt(
OpRange.getBegin())) {
if (isCXXSafeBuffersBoundsSafetyInterop)
DiagKind = diag::
warn_unsafe_incompatible_non_terminated_by_to_terminated_by;
else if (Self.getLangOpts().BoundsSafetyRelaxedSystemHeaders)
DiagKind = diag::
warn_bounds_safety_incompatible_non_terminated_by_to_terminated_by;
isInvalid = false;
} else {
else {
DiagKind = diag::
err_bounds_safety_incompatible_non_terminated_by_to_terminated_by;
isInvalid = true;
Expand All @@ -292,58 +307,74 @@ namespace {
}
case AssignConvertType::
IncompatibleNestedValueTerminatedToNonValueTerminatedPointer:
DiagKind = diag::
err_bounds_safety_incompatible_terminated_by_to_non_terminated_by_mismatch;
isInvalid = true;
if (isCXXSafeBuffersBoundsSafetyInterop)
DiagKind = diag::
warn_unsafe_incompatible_terminated_by_to_non_terminated_by_mismatch;
else {
DiagKind = diag::
err_bounds_safety_incompatible_terminated_by_to_non_terminated_by_mismatch;
isInvalid = true;
}
break;
case AssignConvertType::
IncompatibleNestedNonValueTerminatedToValueTerminatedPointer:
if (Self.getLangOpts().BoundsSafetyRelaxedSystemHeaders) {
if (isCXXSafeBuffersBoundsSafetyInterop)
DiagKind = diag::
warn_unsafe_incompatible_non_terminated_by_to_terminated_by_mismatch;
else if (Self.getLangOpts().BoundsSafetyRelaxedSystemHeaders)
DiagKind = diag::
warn_bounds_safety_incompatible_non_terminated_by_to_terminated_by_mismatch;
isInvalid = false;
} else {
else {
DiagKind = diag::
err_bounds_safety_incompatible_non_terminated_by_to_terminated_by_mismatch;
isInvalid = true;
}
break;
}
if (DiagKind) {
if (DiagKind ==
diag::
err_bounds_safety_incompatible_terminated_by_to_non_terminated_by) {
if (ConvertTy ==
AssignConvertType::
IncompatibleValueTerminatedToNonValueTerminatedPointer) {
auto FDiag = Self.Diag(OpRange.getBegin(), DiagKind)
<< SrcType << DestType << AssignmentAction::Casting
<< (IsSrcNullTerm ? /*null_terminated*/ 1
: /*terminated_by*/ 0);
} else if (
DiagKind ==
diag::
err_bounds_safety_incompatible_non_terminated_by_to_terminated_by ||
DiagKind ==
diag::
warn_bounds_safety_incompatible_non_terminated_by_to_terminated_by) {
ConvertTy ==
AssignConvertType::
IncompatibleNonValueTerminatedToValueTerminatedPointer) {
auto FDiag = Self.Diag(OpRange.getBegin(), DiagKind)
<< SrcType << DestType << AssignmentAction::Casting
<< (!Self.isCXXSafeBuffersBoundsSafetyInteropEnabledAt(
OpRange.getBegin())
? (IsDstNullTerm ? /*null_terminated*/ 1
: /*terminated_by*/ 0)
: 2 /* cut message irrelevant to that mode*/);
} else if (
ConvertTy ==
AssignConvertType::
IncompatibleNestedValueTerminatedToNonValueTerminatedPointer ||
ConvertTy ==
AssignConvertType::
IncompatibleNestedNonValueTerminatedToValueTerminatedPointer) {
Self.Diag(OpRange.getBegin(), DiagKind)
<< SrcType << DestType << AssignmentAction::Casting
<< isCXXSafeBuffersBoundsSafetyInterop;
} else {
Self.Diag(OpRange.getBegin(), DiagKind)
<< SrcType << DestType << AssignmentAction::Casting;
}

Self.TryFixAssigningNullTerminatedToBidiIndexableExpr(SrcExpr.get(),
if (Self.getLangOpts().BoundsSafety) {
Self.TryFixAssigningNullTerminatedToBidiIndexableExpr(SrcExpr.get(),
DestType);

Self.TryFixAssigningImplicitBidiIndexableToNullTerminatedPtr(
Self.TryFixAssigningImplicitBidiIndexableToNullTerminatedPtr(
SrcExpr.get(), DestType);

Self.TryFixAssigningBidiIndexableExprToNullTerminated(SrcExpr.get(),
Self.TryFixAssigningBidiIndexableExprToNullTerminated(SrcExpr.get(),
DestType);
}

if (isInvalid) {
SrcExpr = ExprError();
Expand Down
Loading