Skip to content

Commit f1ff695

Browse files
authored
Merge pull request #63825 from atrick/diagnose-implicit-raw-bitwise
Warn on implicit pointer conversion from nontrivial inout values.
2 parents f1078cd + a354f26 commit f1ff695

22 files changed

+423
-75
lines changed

include/swift/AST/DiagnosticsSIL.def

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -807,5 +807,14 @@ ERROR(sil_movekillscopyablevalue_move_applied_to_unsupported_move, none,
807807
"'consume' applied to value that the compiler does not support checking",
808808
())
809809

810+
// Implicit inout-to-UnsafeRawPointer conversions
811+
WARNING(nontrivial_to_rawpointer_conversion,none,
812+
"forming %1 to a variable of type %0; this is likely incorrect because %2 may contain "
813+
"an object reference.", (Type, Type, Type))
814+
815+
WARNING(nontrivial_string_to_rawpointer_conversion,none,
816+
"forming %0 to an inout variable of type String exposes the internal representation "
817+
"rather than the string contents.", (Type))
818+
810819
#define UNDEFINE_DIAGNOSTIC_MACROS
811820
#include "DefineDiagnosticMacros.h"

include/swift/AST/KnownProtocols.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ PROTOCOL(CaseIterable)
7474
PROTOCOL(SIMD)
7575
PROTOCOL(SIMDScalar)
7676
PROTOCOL(BinaryInteger)
77+
PROTOCOL(FixedWidthInteger)
7778
PROTOCOL(RangeReplaceableCollection)
7879
PROTOCOL(SerialExecutor)
7980
PROTOCOL(GlobalActor)

include/swift/AST/Types.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -831,6 +831,10 @@ class alignas(1 << TypeAlignInBits) TypeBase
831831
/// type) from `DistributedActor`.
832832
bool isDistributedActor();
833833

834+
/// Determine if the type in question is an Array<T> and, if so, provide the
835+
/// element type of the array.
836+
Type isArrayType();
837+
834838
/// Determines the element type of a known
835839
/// [Autoreleasing]Unsafe[Mutable][Raw]Pointer variant, or returns null if the
836840
/// type is not a pointer.

include/swift/Sema/ConstraintSystem.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4735,10 +4735,6 @@ class ConstraintSystem {
47354735
bool updateState = true,
47364736
bool notifyBindingInference = true);
47374737

4738-
/// Determine if the type in question is an Array<T> and, if so, provide the
4739-
/// element type of the array.
4740-
static Optional<Type> isArrayType(Type type);
4741-
47424738
/// Determine whether the given type is a dictionary and, if so, provide the
47434739
/// key and value types for the dictionary.
47444740
static Optional<std::pair<Type, Type>> isDictionaryType(Type type);

lib/AST/Type.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -823,6 +823,14 @@ CanType CanType::wrapInOptionalTypeImpl(CanType type) {
823823
return type->wrapInOptionalType()->getCanonicalType();
824824
}
825825

826+
Type TypeBase::isArrayType() {
827+
if (auto boundStruct = getAs<BoundGenericStructType>()) {
828+
if (boundStruct->getDecl() == getASTContext().getArrayDecl())
829+
return boundStruct->getGenericArgs()[0];
830+
}
831+
return Type();
832+
}
833+
826834
Type TypeBase::getAnyPointerElementType(PointerTypeKind &PTK) {
827835
auto &C = getASTContext();
828836
if (isUnsafeMutableRawPointer()) {

lib/IRGen/GenMeta.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5983,6 +5983,7 @@ SpecialProtocol irgen::getSpecialProtocolID(ProtocolDecl *P) {
59835983
case KnownProtocolKind::SIMD:
59845984
case KnownProtocolKind::SIMDScalar:
59855985
case KnownProtocolKind::BinaryInteger:
5986+
case KnownProtocolKind::FixedWidthInteger:
59865987
case KnownProtocolKind::ObjectiveCBridgeable:
59875988
case KnownProtocolKind::DestructorSafeContainer:
59885989
case KnownProtocolKind::SwiftNewtypeWrapper:

lib/SILGen/SILGenExpr.cpp

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5707,19 +5707,74 @@ RValue RValueEmitter::visitInOutToPointerExpr(InOutToPointerExpr *E,
57075707
return RValue(SGF, E, ptr);
57085708
}
57095709

5710+
/// Implicit conversion from a nontrivial inout type to a raw pointer are
5711+
/// dangerous. For example:
5712+
///
5713+
/// func bar(_ p: UnsafeRawPointer) { ... }
5714+
/// func foo(object: inout AnyObject) {
5715+
/// bar(&object)
5716+
/// }
5717+
///
5718+
/// These conversions should be done explicitly.
5719+
///
5720+
static void diagnoseImplicitRawConversion(Type sourceTy, Type pointerTy,
5721+
SILLocation loc,
5722+
SILGenFunction &SGF) {
5723+
// Array conversion does not always go down the ArrayConverter
5724+
// path. Recognize the Array source type here both for ArrayToPointer and
5725+
// InoutToPointer cases and diagnose on the element type.
5726+
Type eltTy = sourceTy->isArrayType();
5727+
if (!eltTy)
5728+
eltTy = sourceTy;
5729+
5730+
if (SGF.getLoweredType(eltTy).isTrivial(SGF.F))
5731+
return;
5732+
5733+
auto *SM = SGF.getModule().getSwiftModule();
5734+
if (auto *fixedWidthIntegerDecl = SM->getASTContext().getProtocol(
5735+
KnownProtocolKind::FixedWidthInteger)) {
5736+
if (SM->conformsToProtocol(eltTy, fixedWidthIntegerDecl))
5737+
return;
5738+
}
5739+
5740+
PointerTypeKind kindOfPtr;
5741+
auto pointerElt = pointerTy->getAnyPointerElementType(kindOfPtr);
5742+
assert(!pointerElt.isNull() && "expected an unsafe pointer type");
5743+
5744+
// The element type may contain a reference. Disallow conversion to a "raw"
5745+
// pointer type. Consider Int8/UInt8 to be raw pointers. Trivial element types
5746+
// are filtered out above, so Int8/UInt8 pointers can't match the source
5747+
// type. But the type checker may have allowed these for direct C calls, in
5748+
// which Int8/UInt8 are equivalent to raw pointers..
5749+
if (!(pointerElt->isVoid() || pointerElt->isInt8() || pointerElt->isUInt8()))
5750+
return;
5751+
5752+
if (sourceTy->isString()) {
5753+
SGF.SGM.diagnose(loc, diag::nontrivial_string_to_rawpointer_conversion,
5754+
pointerTy);
5755+
} else {
5756+
SGF.SGM.diagnose(loc, diag::nontrivial_to_rawpointer_conversion, sourceTy,
5757+
pointerTy, eltTy);
5758+
}
5759+
}
5760+
57105761
/// Convert an l-value to a pointer type: unsafe, unsafe-mutable, or
57115762
/// autoreleasing-unsafe-mutable.
57125763
ManagedValue SILGenFunction::emitLValueToPointer(SILLocation loc, LValue &&lv,
57135764
PointerAccessInfo pointerInfo) {
57145765
assert(pointerInfo.AccessKind == lv.getAccessKind());
57155766

5767+
diagnoseImplicitRawConversion(lv.getSubstFormalType(),
5768+
pointerInfo.PointerType, loc, *this);
5769+
57165770
// The incoming lvalue should be at the abstraction level of T in
57175771
// Unsafe*Pointer<T>. Reabstract it if necessary.
57185772
auto opaqueTy = AbstractionPattern::getOpaque();
57195773
auto loweredTy = getLoweredType(opaqueTy, lv.getSubstFormalType());
57205774
if (lv.getTypeOfRValue().getASTType() != loweredTy.getASTType()) {
57215775
lv.addSubstToOrigComponent(opaqueTy, loweredTy);
57225776
}
5777+
57235778
switch (pointerInfo.PointerKind) {
57245779
case PTK_UnsafeMutablePointer:
57255780
case PTK_UnsafePointer:
@@ -5833,6 +5888,9 @@ SILGenFunction::emitArrayToPointer(SILLocation loc, ManagedValue array,
58335888
firstSubMap, secondSubMap, CombineSubstitutionMaps::AtIndex, 1, 0,
58345889
genericSig);
58355890

5891+
diagnoseImplicitRawConversion(accessInfo.ArrayType, accessInfo.PointerType,
5892+
loc, *this);
5893+
58365894
SmallVector<ManagedValue, 2> resultScalars;
58375895
emitApplyOfLibraryIntrinsic(loc, converter, subMap, array, SGFContext())
58385896
.getAll(resultScalars);

lib/Sema/CSApply.cpp

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6465,8 +6465,8 @@ bool ExprRewriter::peepholeCollectionUpcast(Expr *expr, Type toType,
64656465

64666466
// Array literals.
64676467
if (auto arrayLiteral = dyn_cast<ArrayExpr>(expr)) {
6468-
if (Optional<Type> elementType = ConstraintSystem::isArrayType(toType)) {
6469-
peepholeArrayUpcast(arrayLiteral, toType, bridged, *elementType, locator);
6468+
if (Type elementType = toType->isArrayType()) {
6469+
peepholeArrayUpcast(arrayLiteral, toType, bridged, elementType, locator);
64706470
return true;
64716471
}
64726472

@@ -6510,8 +6510,7 @@ Expr *ExprRewriter::buildCollectionUpcastExpr(
65106510
bridged, locator, 0);
65116511

65126512
// For single-parameter collections, form the upcast.
6513-
if (ConstraintSystem::isArrayType(toType) ||
6514-
ConstraintSystem::isSetType(toType)) {
6513+
if (toType->isArrayType() || ConstraintSystem::isSetType(toType)) {
65156514
return cs.cacheType(
65166515
new (ctx) CollectionUpcastConversionExpr(expr, toType, {}, conv));
65176516
}
@@ -6536,12 +6535,11 @@ Expr *ExprRewriter::buildObjCBridgeExpr(Expr *expr, Type toType,
65366535

65376536
// Bridged collection casts always succeed, so we treat them as
65386537
// collection "upcasts".
6539-
if ((ConstraintSystem::isArrayType(fromType) &&
6540-
ConstraintSystem::isArrayType(toType)) ||
6541-
(ConstraintSystem::isDictionaryType(fromType) &&
6542-
ConstraintSystem::isDictionaryType(toType)) ||
6543-
(ConstraintSystem::isSetType(fromType) &&
6544-
ConstraintSystem::isSetType(toType))) {
6538+
if ((fromType->isArrayType() && toType->isArrayType())
6539+
|| (ConstraintSystem::isDictionaryType(fromType)
6540+
&& ConstraintSystem::isDictionaryType(toType))
6541+
|| (ConstraintSystem::isSetType(fromType)
6542+
&& ConstraintSystem::isSetType(toType))) {
65456543
return buildCollectionUpcastExpr(expr, toType, /*bridged=*/true, locator);
65466544
}
65476545

lib/Sema/CSDiagnostics.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1758,8 +1758,8 @@ bool RValueTreatedAsLValueFailure::diagnoseAsError() {
17581758
auto argType = getType(inoutExpr)->getWithoutSpecifierType();
17591759

17601760
PointerTypeKind ptr;
1761-
if (isArrayType(argType) && paramType->getAnyPointerElementType(ptr) &&
1762-
(ptr == PTK_UnsafePointer || ptr == PTK_UnsafeRawPointer)) {
1761+
if (argType->isArrayType() && paramType->getAnyPointerElementType(ptr)
1762+
&& (ptr == PTK_UnsafePointer || ptr == PTK_UnsafeRawPointer)) {
17631763
emitDiagnosticAt(inoutExpr->getLoc(),
17641764
diag::extra_address_of_unsafepointer, paramType)
17651765
.highlight(inoutExpr->getSourceRange())

lib/Sema/CSDiagnostics.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -224,11 +224,6 @@ class FailureDiagnostic {
224224
llvm::function_ref<void(GenericTypeParamType *, Type)> substitution =
225225
[](GenericTypeParamType *, Type) {});
226226

227-
bool isArrayType(Type type) const {
228-
auto &cs = getConstraintSystem();
229-
return bool(cs.isArrayType(type));
230-
}
231-
232227
bool conformsToKnownProtocol(Type type, KnownProtocolKind protocol) const;
233228
};
234229

0 commit comments

Comments
 (0)