Skip to content

Commit 4988127

Browse files
authored
Merge pull request swiftlang#35525 from mikeash/swift_asprintf-static-checking
[Runtime] Mark swift_asprintf with __attribute__((__format__))
2 parents 35dad11 + 216e555 commit 4988127

File tree

6 files changed

+65
-50
lines changed

6 files changed

+65
-50
lines changed

include/swift/Demangling/TypeDecoder.h

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -331,10 +331,11 @@ getObjCClassOrProtocolName(NodePointer node) {
331331
#endif
332332

333333
#define MAKE_NODE_TYPE_ERROR(Node, Fmt, ...) \
334-
TypeLookupError("TypeDecoder.h:%d: Node kind %u \"%.*s\" - " Fmt, __LINE__, \
335-
Node->getKind(), \
336-
Node->hasText() ? (int)Node->getText().size() : 0, \
337-
Node->hasText() ? Node->getText().data() : "", __VA_ARGS__)
334+
TYPE_LOOKUP_ERROR_FMT("TypeDecoder.h:%u: Node kind %u \"%.*s\" - " Fmt, \
335+
__LINE__, (unsigned)Node->getKind(), \
336+
Node->hasText() ? (int)Node->getText().size() : 0, \
337+
Node->hasText() ? Node->getText().data() : "", \
338+
__VA_ARGS__)
338339

339340
#define MAKE_NODE_TYPE_ERROR0(Node, Str) MAKE_NODE_TYPE_ERROR(Node, "%s", Str)
340341

@@ -406,7 +407,7 @@ class TypeDecoder {
406407
case NodeKind::BoundGenericOtherNominalType: {
407408
if (Node->getNumChildren() < 2)
408409
return MAKE_NODE_TYPE_ERROR(Node,
409-
"fewer children (%u) than required (2)",
410+
"fewer children (%zu) than required (2)",
410411
Node->getNumChildren());
411412

412413
llvm::SmallVector<BuiltType, 8> args;
@@ -469,13 +470,13 @@ class TypeDecoder {
469470
// so that the parent type becomes 'S' and not 'P'.
470471
if (Node->getNumChildren() < 2)
471472
return MAKE_NODE_TYPE_ERROR(Node,
472-
"fewer children (%u) than required (2)",
473+
"fewer children (%zu) than required (2)",
473474
Node->getNumChildren());
474475

475476
const auto &genericArgs = Node->getChild(1);
476477
if (genericArgs->getNumChildren() != 1)
477478
return MAKE_NODE_TYPE_ERROR(genericArgs,
478-
"expected 1 generic argument, saw %u",
479+
"expected 1 generic argument, saw %zu",
479480
genericArgs->getNumChildren());
480481

481482
return decodeMangledType(genericArgs->getChild(0));
@@ -550,7 +551,7 @@ class TypeDecoder {
550551
if (Node->getKind() == NodeKind::ProtocolListWithClass) {
551552
if (Node->getNumChildren() < 2)
552553
return MAKE_NODE_TYPE_ERROR(Node,
553-
"fewer children (%u) than required (2)",
554+
"fewer children (%zu) than required (2)",
554555
Node->getNumChildren());
555556

556557
auto superclassNode = Node->getChild(1);
@@ -579,7 +580,7 @@ class TypeDecoder {
579580
}
580581
case NodeKind::DynamicSelf: {
581582
if (Node->getNumChildren() != 1)
582-
return MAKE_NODE_TYPE_ERROR(Node, "expected 1 child, saw %u",
583+
return MAKE_NODE_TYPE_ERROR(Node, "expected 1 child, saw %zu",
583584
Node->getNumChildren());
584585

585586
auto selfType = decodeMangledType(Node->getChild(0));
@@ -607,7 +608,7 @@ class TypeDecoder {
607608
case NodeKind::FunctionType: {
608609
if (Node->getNumChildren() < 2)
609610
return MAKE_NODE_TYPE_ERROR(Node,
610-
"fewer children (%u) than required (2)",
611+
"fewer children (%zu) than required (2)",
611612
Node->getNumChildren());
612613

613614
FunctionTypeFlags flags;
@@ -655,7 +656,7 @@ class TypeDecoder {
655656

656657
if (Node->getNumChildren() < firstChildIdx + 2)
657658
return MAKE_NODE_TYPE_ERROR(Node,
658-
"fewer children (%u) than required (%u)",
659+
"fewer children (%zu) than required (%u)",
659660
Node->getNumChildren(), firstChildIdx + 2);
660661

661662
bool hasParamFlags = false;
@@ -828,7 +829,7 @@ class TypeDecoder {
828829
if (Node->getChild(0)->getKind() == NodeKind::TupleElementName) {
829830
if (Node->getNumChildren() < 2)
830831
return MAKE_NODE_TYPE_ERROR(Node,
831-
"fewer children (%u) than required (2)",
832+
"fewer children (%zu) than required (2)",
832833
Node->getNumChildren());
833834

834835
return decodeMangledType(Node->getChild(1));
@@ -838,15 +839,15 @@ class TypeDecoder {
838839
case NodeKind::DependentGenericType: {
839840
if (Node->getNumChildren() < 2)
840841
return MAKE_NODE_TYPE_ERROR(Node,
841-
"fewer children (%u) than required (2)",
842+
"fewer children (%zu) than required (2)",
842843
Node->getNumChildren());
843844

844845
return decodeMangledType(Node->getChild(1));
845846
}
846847
case NodeKind::DependentMemberType: {
847848
if (Node->getNumChildren() < 2)
848849
return MAKE_NODE_TYPE_ERROR(Node,
849-
"fewer children (%u) than required (2)",
850+
"fewer children (%zu) than required (2)",
850851
Node->getNumChildren());
851852

852853
auto base = decodeMangledType(Node->getChild(0));
@@ -866,7 +867,7 @@ class TypeDecoder {
866867
case NodeKind::DependentAssociatedTypeRef: {
867868
if (Node->getNumChildren() < 2)
868869
return MAKE_NODE_TYPE_ERROR(Node,
869-
"fewer children (%u) than required (2)",
870+
"fewer children (%zu) than required (2)",
870871
Node->getNumChildren());
871872

872873
return decodeMangledType(Node->getChild(1));
@@ -935,7 +936,7 @@ class TypeDecoder {
935936
case NodeKind::SugaredDictionary: {
936937
if (Node->getNumChildren() < 2)
937938
return MAKE_NODE_TYPE_ERROR(Node,
938-
"fewer children (%u) than required (2)",
939+
"fewer children (%zu) than required (2)",
939940
Node->getNumChildren());
940941

941942
auto key = decodeMangledType(Node->getChild(0));
@@ -961,7 +962,7 @@ class TypeDecoder {
961962
case NodeKind::OpaqueType: {
962963
if (Node->getNumChildren() < 3)
963964
return MAKE_NODE_TYPE_ERROR(Node,
964-
"fewer children (%u) than required (3)",
965+
"fewer children (%zu) than required (3)",
965966
Node->getNumChildren());
966967
auto descriptor = Node->getChild(0);
967968
auto ordinalNode = Node->getChild(1);
@@ -1079,7 +1080,7 @@ class TypeDecoder {
10791080
} else {
10801081
if (node->getNumChildren() < 2)
10811082
return MAKE_NODE_TYPE_ERROR(
1082-
node, "Number of node children (%u) less than required (2)",
1083+
node, "Number of node children (%zu) less than required (2)",
10831084
node->getNumChildren());
10841085

10851086
auto parentContext = node->getChild(0);
@@ -1097,7 +1098,7 @@ class TypeDecoder {
10971098
// Decode the type being extended.
10981099
if (parentContext->getNumChildren() < 2)
10991100
return MAKE_NODE_TYPE_ERROR(parentContext,
1100-
"Number of parentContext children (%u) "
1101+
"Number of parentContext children (%zu) "
11011102
"less than required (2)",
11021103
node->getNumChildren());
11031104
parentContext = parentContext->getChild(1);

include/swift/Demangling/TypeLookupError.h

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -125,18 +125,6 @@ class TypeLookupError {
125125
};
126126
}
127127

128-
/// Construct a TypeLookupError that creates a string using asprintf. The passed-in
129-
/// format string and arguments are passed directly to swift_asprintf when
130-
/// the string is requested. The arguments are captured and the string is only
131-
/// formatted when needed.
132-
template <typename... Args>
133-
TypeLookupError(const char *fmt, Args... args)
134-
: TypeLookupError([=] {
135-
char *str;
136-
swift_asprintf(&str, fmt, args...);
137-
return str;
138-
}) {}
139-
140128
/// Construct a TypeLookupError that wraps a function returning a string. The
141129
/// passed-in function can return either a `std::string` or `char *`. If it
142130
/// returns `char *` then the string will be destroyed with `free()`.
@@ -201,6 +189,27 @@ template <typename T> class TypeLookupErrorOr {
201189
bool isError() { return getError() != nullptr; }
202190
};
203191

192+
/// Construct a TypeLookupError that creates a string using asprintf. The
193+
/// passed-in format string and arguments are passed directly to swift_asprintf
194+
/// when the string is requested. The arguments are captured and the string is
195+
/// only formatted when needed.
196+
///
197+
/// The crazy sizeof(swift_asprintf(... construct gives us compile-time type
198+
/// checking of the format string and arguments, while still letting us use the
199+
/// variadic template to safely capture the arguments in the lambda.
200+
#define TYPE_LOOKUP_ERROR_FMT(...) \
201+
(sizeof(swift_asprintf(NULL, __VA_ARGS__)), TypeLookupErrorImpl(__VA_ARGS__))
202+
203+
// Implementation for TYPE_LOOKUP_ERROR_FMT. Don't call directly.
204+
template <typename... Args>
205+
static TypeLookupError TypeLookupErrorImpl(const char *fmt, Args... args) {
206+
return TypeLookupError([=] {
207+
char *str;
208+
swift_asprintf(&str, fmt, args...);
209+
return str;
210+
});
211+
}
212+
204213
} // namespace swift
205214

206215
#endif // SWIFT_DEMANGLING_TypeLookupError_H

include/swift/Runtime/Portability.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ size_t _swift_strlcpy(char *dst, const char *src, size_t maxlen);
2828
#ifdef SWIFT_RUNTIME_ATTRIBUTE_ALWAYS_INLINE
2929
SWIFT_RUNTIME_ATTRIBUTE_ALWAYS_INLINE
3030
#endif
31-
inline static int swift_asprintf(char **strp, const char *fmt, ...) {
31+
__attribute((__format__(__printf__, 2, 3))) inline static int
32+
swift_asprintf(char **strp, const char *fmt, ...) {
3233
va_list args;
3334
va_start(args, fmt);
3435
#if defined(_WIN32)

stdlib/public/runtime/ProtocolConformance.cpp

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -687,9 +687,9 @@ llvm::Optional<TypeLookupError> swift::_checkGenericRequirements(
687687
&witnessTable)) {
688688
const char *protoName =
689689
req.getProtocol() ? req.getProtocol().getName() : "<null>";
690-
return TypeLookupError(
691-
"subject type %s does not conform to protocol %s", req.getParam(),
692-
protoName);
690+
return TYPE_LOOKUP_ERROR_FMT(
691+
"subject type %.*s does not conform to protocol %s",
692+
(int)req.getParam().size(), req.getParam().data(), protoName);
693693
}
694694

695695
// If we need a witness table, add it.
@@ -714,8 +714,10 @@ llvm::Optional<TypeLookupError> swift::_checkGenericRequirements(
714714

715715
// Check that the types are equivalent.
716716
if (subjectType != otherType)
717-
return TypeLookupError("subject type %s does not match %s",
718-
req.getParam(), req.getMangledTypeName());
717+
return TYPE_LOOKUP_ERROR_FMT(
718+
"subject type %.*s does not match %.*s", (int)req.getParam().size(),
719+
req.getParam().data(), (int)req.getMangledTypeName().size(),
720+
req.getMangledTypeName().data());
719721

720722
continue;
721723
}
@@ -724,14 +726,14 @@ llvm::Optional<TypeLookupError> swift::_checkGenericRequirements(
724726
switch (req.getLayout()) {
725727
case GenericRequirementLayoutKind::Class:
726728
if (!subjectType->satisfiesClassConstraint())
727-
return TypeLookupError(
728-
"subject type %s does not satisfy class constraint",
729-
req.getParam());
729+
return TYPE_LOOKUP_ERROR_FMT(
730+
"subject type %.*s does not satisfy class constraint",
731+
(int)req.getParam().size(), req.getParam().data());
730732
continue;
731733
}
732734

733735
// Unknown layout.
734-
return TypeLookupError("unknown layout kind %u", req.getLayout());
736+
return TYPE_LOOKUP_ERROR_FMT("unknown layout kind %u", req.getLayout());
735737
}
736738

737739
case GenericRequirementKind::BaseClass: {
@@ -753,8 +755,10 @@ llvm::Optional<TypeLookupError> swift::_checkGenericRequirements(
753755
}
754756

755757
if (!isSubclass(subjectType, baseType))
756-
return TypeLookupError("%s is not subclass of %s", req.getParam(),
757-
req.getMangledTypeName());
758+
return TYPE_LOOKUP_ERROR_FMT(
759+
"%.*s is not subclass of %.*s", (int)req.getParam().size(),
760+
req.getParam().data(), (int)req.getMangledTypeName().size(),
761+
req.getMangledTypeName().data());
758762

759763
continue;
760764
}
@@ -766,8 +770,8 @@ llvm::Optional<TypeLookupError> swift::_checkGenericRequirements(
766770
}
767771

768772
// Unknown generic requirement kind.
769-
return TypeLookupError("unknown generic requirement kind %u",
770-
req.getKind());
773+
return TYPE_LOOKUP_ERROR_FMT("unknown generic requirement kind %u",
774+
(unsigned)req.getKind());
771775
}
772776

773777
// Success!

stdlib/public/runtime/SwiftObject.mm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1411,7 +1411,7 @@ static bool usesNativeSwiftReferenceCounting_nonNull(
14111411
char *log;
14121412
swift_asprintf(
14131413
&log, "%.*s: file %.*s, line %" PRIu32 ", column %" PRIu32 " \n",
1414-
messageLength, message, filenameLength, filename, line, column);
1414+
(int)messageLength, message, filenameLength, filename, line, column);
14151415

14161416
printCurrentBacktrace(2/*framesToSkip*/);
14171417

unittests/Basic/TypeLookupError.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ TEST(TypeLookupError, ConstantString) {
2424
}
2525

2626
TEST(TypeLookupError, FormatString) {
27-
auto error = TypeLookupError("%d %d %d %d %d %d %d %d %d %d", 0, 1, 2, 3, 4,
28-
5, 6, 7, 8, 9, 10);
27+
auto error = TYPE_LOOKUP_ERROR_FMT("%d %d %d %d %d %d %d %d %d %d", 0, 1, 2,
28+
3, 4, 5, 6, 7, 8, 9);
2929
char *str = error.copyErrorString();
3030
ASSERT_STREQ(str, "0 1 2 3 4 5 6 7 8 9");
3131
error.freeErrorString(str);
@@ -35,8 +35,8 @@ TEST(TypeLookupError, Copying) {
3535
std::vector<TypeLookupError> vec;
3636

3737
{
38-
auto originalError = TypeLookupError("%d %d %d %d %d %d %d %d %d %d", 0, 1,
39-
2, 3, 4, 5, 6, 7, 8, 9, 10);
38+
auto originalError = TYPE_LOOKUP_ERROR_FMT("%d %d %d %d %d %d %d %d %d %d",
39+
0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
4040
for (int i = 0; i < 5; i++)
4141
vec.push_back(originalError);
4242
}

0 commit comments

Comments
 (0)