Add a dumper/verifier for OpaqueExistentialContainers (i.e. Any) in c++.
The dumper method dumps:
1. The container's metadata pointer.
2. A pointer to the container's value.
3. Whether or not said value is stored inline in the container.
This provides a general overview that can be used even when working with SIL
code in the debugger by grabbing a pointer to swift Anys and then calling the
c++ any method upon them.
The verifier is intended to be used in conjunction with ASAN for maximum
effect to catch use-after-frees of existential boxes.
While implementing this I refactored some code from ExistentialTypeMetadata into
methods on OpaqueExistentialContainer. ExistentialTypeMetadata just calls these
methods now instead of implementing the code inline.
diff --git a/include/swift/Runtime/ExistentialContainer.h b/include/swift/Runtime/ExistentialContainer.h
new file mode 100644
index 0000000..f042b1c
--- /dev/null
+++ b/include/swift/Runtime/ExistentialContainer.h
@@ -0,0 +1,102 @@
+//===--- ExistentialContainer.h -------------------------------------------===//
+//
+// This source file is part of the Swift.org open source project
+//
+// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See https://swift.org/LICENSE.txt for license information
+// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SWIFT_RUNTIME_EXISTENTIALCONTAINER_H
+#define SWIFT_RUNTIME_EXISTENTIALCONTAINER_H
+
+#include "swift/Runtime/Metadata.h"
+
+namespace swift {
+
+/// The basic layout of an opaque (non-class-bounded) existential type.
+template <typename Runtime>
+struct TargetOpaqueExistentialContainer {
+ ValueBuffer Buffer;
+ const TargetMetadata<Runtime> *Type;
+ // const void *WitnessTables[];
+
+ const TargetWitnessTable<Runtime> **getWitnessTables() {
+ return reinterpret_cast<const TargetWitnessTable<Runtime> **>(this + 1);
+ }
+
+ const TargetWitnessTable<Runtime> *const *getWitnessTables() const {
+ return reinterpret_cast<const TargetWitnessTable<Runtime> *const *>(this +
+ 1);
+ }
+
+ void copyTypeInto(swift::TargetOpaqueExistentialContainer<Runtime> *dest,
+ unsigned numTables) const {
+ dest->Type = Type;
+ for (unsigned i = 0; i != numTables; ++i)
+ dest->getWitnessTables()[i] = getWitnessTables()[i];
+ }
+
+ /// Return true if this opaque existential container contains a value that is
+ /// stored inline in the container. Returns false if the value is stored out
+ /// of line.
+ bool isValueInline() const;
+
+ /// Project out a pointer to the value stored in the container.
+ ///
+ /// *NOTE* If the container contains the value inline, then this will return a
+ /// pointer inside the container itself. Otherwise, it will return a pointer
+ /// to out of line memory.
+ const OpaqueValue *projectValue() const;
+
+ /// Cleans up an existential container instance whose value is uninitialized.
+ void deinit();
+
+#ifndef NDEBUG
+ /// Verify invariants of the container.
+ ///
+ /// We verify that:
+ ///
+ /// 1. The container itself is in live memory.
+ /// 2. If we have an out of line value, that the value is in live memory.
+ ///
+ /// The intention is that this is used in combination with ASAN or Guard
+ /// Malloc to catch use-after-frees.
+ void verify() const LLVM_ATTRIBUTE_USED;
+
+ /// Dump information about this specific box and its contents. Only intended
+ /// for use in the debugger.
+ LLVM_ATTRIBUTE_DEPRECATED(void dump() const LLVM_ATTRIBUTE_USED,
+ "Only meant for use in the debugger");
+#endif
+};
+using OpaqueExistentialContainer = TargetOpaqueExistentialContainer<InProcess>;
+
+/// The basic layout of a class-bounded existential type.
+template <typename ContainedValue>
+struct ClassExistentialContainerImpl {
+ ContainedValue Value;
+
+ const WitnessTable **getWitnessTables() {
+ return reinterpret_cast<const WitnessTable **>(this + 1);
+ }
+ const WitnessTable *const *getWitnessTables() const {
+ return reinterpret_cast<const WitnessTable *const *>(this + 1);
+ }
+
+ void copyTypeInto(ClassExistentialContainerImpl *dest,
+ unsigned numTables) const {
+ for (unsigned i = 0; i != numTables; ++i)
+ dest->getWitnessTables()[i] = getWitnessTables()[i];
+ }
+};
+using ClassExistentialContainer = ClassExistentialContainerImpl<void *>;
+using WeakClassExistentialContainer =
+ ClassExistentialContainerImpl<WeakReference>;
+
+} // end swift namespace
+
+#endif
diff --git a/include/swift/Runtime/Metadata.h b/include/swift/Runtime/Metadata.h
index 3501251..221319f 100644
--- a/include/swift/Runtime/Metadata.h
+++ b/include/swift/Runtime/Metadata.h
@@ -1895,54 +1895,6 @@
using WitnessTable = TargetWitnessTable<InProcess>;
-/// The basic layout of an opaque (non-class-bounded) existential type.
-template <typename Runtime>
-struct TargetOpaqueExistentialContainer {
- ValueBuffer Buffer;
- const TargetMetadata<Runtime> *Type;
- // const void *WitnessTables[];
-
- const TargetWitnessTable<Runtime> **getWitnessTables() {
- return reinterpret_cast<const TargetWitnessTable<Runtime> **>(this + 1);
- }
-
- const TargetWitnessTable<Runtime> * const *getWitnessTables() const {
- return reinterpret_cast<const TargetWitnessTable<Runtime> * const *>(
- this + 1);
- }
-
- void copyTypeInto(swift::TargetOpaqueExistentialContainer<Runtime> *dest,
- unsigned numTables) const {
- dest->Type = Type;
- for (unsigned i = 0; i != numTables; ++i)
- dest->getWitnessTables()[i] = getWitnessTables()[i];
- }
-};
-using OpaqueExistentialContainer
- = TargetOpaqueExistentialContainer<InProcess>;
-
-/// The basic layout of a class-bounded existential type.
-template <typename ContainedValue>
-struct ClassExistentialContainerImpl {
- ContainedValue Value;
-
- const WitnessTable **getWitnessTables() {
- return reinterpret_cast<const WitnessTable**>(this + 1);
- }
- const WitnessTable * const *getWitnessTables() const {
- return reinterpret_cast<const WitnessTable* const *>(this + 1);
- }
-
- void copyTypeInto(ClassExistentialContainerImpl *dest,
- unsigned numTables) const {
- for (unsigned i = 0; i != numTables; ++i)
- dest->getWitnessTables()[i] = getWitnessTables()[i];
- }
-};
-using ClassExistentialContainer = ClassExistentialContainerImpl<void *>;
-using WeakClassExistentialContainer =
- ClassExistentialContainerImpl<WeakReference>;
-
/// The possible physical representations of existential types.
enum class ExistentialTypeRepresentation {
/// The type uses an opaque existential representation.
@@ -1985,6 +1937,7 @@
OpaqueValue *projectValue(OpaqueValue *container) const {
return const_cast<OpaqueValue *>(projectValue((const OpaqueValue*)container));
}
+
/// Get the dynamic type from an existential container of the type described
/// by this metadata.
const TargetMetadata<Runtime> *
diff --git a/include/swift/Runtime/Reflection.h b/include/swift/Runtime/Reflection.h
index 23f3e99..1d62e08 100644
--- a/include/swift/Runtime/Reflection.h
+++ b/include/swift/Runtime/Reflection.h
@@ -14,6 +14,7 @@
//
//===----------------------------------------------------------------------===//
+#include "swift/Runtime/ExistentialContainer.h"
#include "swift/Runtime/Metadata.h"
#include <cstdlib>
diff --git a/stdlib/public/runtime/CMakeLists.txt b/stdlib/public/runtime/CMakeLists.txt
index 52bab17..8424276 100644
--- a/stdlib/public/runtime/CMakeLists.txt
+++ b/stdlib/public/runtime/CMakeLists.txt
@@ -48,6 +48,7 @@
Errors.cpp
ErrorDefaultImpls.cpp
Exclusivity.cpp
+ ExistentialContainer.cpp
Heap.cpp
HeapObject.cpp
ImageInspectionMachO.cpp
diff --git a/stdlib/public/runtime/Casting.cpp b/stdlib/public/runtime/Casting.cpp
index 72c3269..c551c89 100644
--- a/stdlib/public/runtime/Casting.cpp
+++ b/stdlib/public/runtime/Casting.cpp
@@ -14,12 +14,20 @@
//
//===----------------------------------------------------------------------===//
+#include "swift/Runtime/Casting.h"
+#include "../SwiftShims/RuntimeShims.h"
+#include "ErrorObject.h"
+#include "ExistentialMetadataImpl.h"
+#include "Private.h"
+#include "SwiftHashableSupport.h"
+#include "stddef.h"
#include "swift/Basic/LLVM.h"
#include "swift/Basic/Lazy.h"
#include "swift/Demangling/Demangler.h"
-#include "swift/Runtime/Casting.h"
#include "swift/Runtime/Config.h"
+#include "swift/Runtime/Debug.h"
#include "swift/Runtime/Enum.h"
+#include "swift/Runtime/ExistentialContainer.h"
#include "swift/Runtime/HeapObject.h"
#include "swift/Runtime/Metadata.h"
#include "swift/Runtime/Mutex.h"
@@ -27,13 +35,6 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/Support/Compiler.h"
-#include "swift/Runtime/Debug.h"
-#include "ErrorObject.h"
-#include "ExistentialMetadataImpl.h"
-#include "Private.h"
-#include "SwiftHashableSupport.h"
-#include "../SwiftShims/RuntimeShims.h"
-#include "stddef.h"
#if SWIFT_OBJC_INTEROP
#include "swift/Runtime/ObjCBridge.h"
#include "SwiftValue.h"
diff --git a/stdlib/public/runtime/ExistentialContainer.cpp b/stdlib/public/runtime/ExistentialContainer.cpp
new file mode 100644
index 0000000..8e380b1
--- /dev/null
+++ b/stdlib/public/runtime/ExistentialContainer.cpp
@@ -0,0 +1,83 @@
+//===--- ExistentialContainer.cpp -----------------------------------------===//
+//
+// This source file is part of the Swift.org open source project
+//
+// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See https://swift.org/LICENSE.txt for license information
+// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+//
+//===----------------------------------------------------------------------===//
+
+#include "swift/Runtime/ExistentialContainer.h"
+#include "swift/Runtime/HeapObject.h"
+
+using namespace swift;
+
+//===----------------------------------------------------------------------===//
+// OpaqueExistentialContainer Implementation
+//===----------------------------------------------------------------------===//
+
+template <>
+bool OpaqueExistentialContainer::isValueInline() const {
+ return Type->getValueWitnesses()->isValueInline();
+}
+
+template <>
+const OpaqueValue *OpaqueExistentialContainer::projectValue() const {
+ auto *vwt = Type->getValueWitnesses();
+
+ if (vwt->isValueInline())
+ return reinterpret_cast<const OpaqueValue *>(&Buffer);
+
+ // Compute the byte offset of the object in the box.
+ unsigned alignMask = vwt->getAlignmentMask();
+ unsigned byteOffset = (sizeof(HeapObject) + alignMask) & ~alignMask;
+ auto *bytePtr = reinterpret_cast<const char *>(
+ *reinterpret_cast<HeapObject *const *const>(&Buffer));
+ return reinterpret_cast<const OpaqueValue *>(bytePtr + byteOffset);
+}
+
+template <>
+void OpaqueExistentialContainer::deinit() {
+ auto *vwt = Type->getValueWitnesses();
+ if (vwt->isValueInline()) {
+ return;
+ }
+
+ unsigned alignMask = vwt->getAlignmentMask();
+ unsigned size = vwt->size;
+ swift_deallocObject(*reinterpret_cast<HeapObject **>(&Buffer), size,
+ alignMask);
+}
+
+#ifndef NDEBUG
+
+// *NOTE* This routine performs unused memory reads on purpose to try to catch
+// use-after-frees in conjunction with ASAN or Guard Malloc.
+template <>
+void OpaqueExistentialContainer::verify() const {
+ // We do not actually care about value. We just want to see if the
+ // memory is valid or not. So convert to a uint8_t and try to
+ // memcpy into firstByte. We use volatile to just ensure that this
+ // does not get dead code eliminated.
+ uint8_t firstByte;
+ memcpy(&firstByte, projectValue(), 1);
+ volatile uint8_t firstVolatileByte = firstByte;
+ (void)firstVolatileByte;
+}
+
+/// Dump information about this specific container and its contents.
+template <>
+void OpaqueExistentialContainer::dump() const {
+ // Quickly verify to make sure we are well formed.
+ verify();
+
+ printf("TargetOpaqueExistentialContainer.\n");
+ printf("Metadata Pointer: %p.\n", Type);
+ printf("Value Pointer: %p.\n", projectValue());
+ printf("Is Value Stored Inline: %s.\n", isValueInline() ? "true" : "false");
+}
+
+#endif
diff --git a/stdlib/public/runtime/ExistentialMetadataImpl.h b/stdlib/public/runtime/ExistentialMetadataImpl.h
index b31f00a..3d849e3 100644
--- a/stdlib/public/runtime/ExistentialMetadataImpl.h
+++ b/stdlib/public/runtime/ExistentialMetadataImpl.h
@@ -19,6 +19,7 @@
#define SWIFT_RUNTIME_EXISTENTIALMETADATAIMPL_H
#include "MetadataImpl.h"
+#include "swift/Runtime/ExistentialContainer.h"
namespace swift {
namespace metadataimpl {
diff --git a/stdlib/public/runtime/Metadata.cpp b/stdlib/public/runtime/Metadata.cpp
index f363392..d2a70f2 100644
--- a/stdlib/public/runtime/Metadata.cpp
+++ b/stdlib/public/runtime/Metadata.cpp
@@ -21,6 +21,7 @@
#include "swift/Basic/Range.h"
#include "swift/Demangling/Demangler.h"
#include "swift/Runtime/Casting.h"
+#include "swift/Runtime/ExistentialContainer.h"
#include "swift/Runtime/HeapObject.h"
#include "swift/Runtime/Mutex.h"
#include "swift/Strings.h"
@@ -2240,15 +2241,12 @@
case ExistentialTypeRepresentation::Class:
return true;
// Opaque existential containers uniquely own their contained value.
- case ExistentialTypeRepresentation::Opaque:
- {
+ case ExistentialTypeRepresentation::Opaque: {
// We can't take from a shared existential box without checking uniqueness.
auto *opaque =
reinterpret_cast<const OpaqueExistentialContainer *>(container);
- auto *vwt = opaque->Type->getValueWitnesses();
- return vwt->isValueInline();
+ return opaque->isValueInline();
}
-
// References to boxed existential containers may be shared.
case ExistentialTypeRepresentation::Error: {
// We can only take the value if the box is a bridged NSError, in which case
@@ -2275,13 +2273,7 @@
case ExistentialTypeRepresentation::Opaque: {
auto *opaque = reinterpret_cast<OpaqueExistentialContainer *>(container);
- auto *vwt = opaque->Type->getValueWitnesses();
- if (!vwt->isValueInline()) {
- unsigned alignMask = vwt->getAlignmentMask();
- unsigned size = vwt->size;
- swift_deallocObject(*reinterpret_cast<HeapObject **>(&opaque->Buffer),
- size, alignMask);
- }
+ opaque->deinit();
break;
}
@@ -2303,18 +2295,7 @@
case ExistentialTypeRepresentation::Opaque: {
auto *opaqueContainer =
reinterpret_cast<const OpaqueExistentialContainer*>(container);
- auto *type = opaqueContainer->Type;
- auto *vwt = type->getValueWitnesses();
-
- if (vwt->isValueInline())
- return reinterpret_cast<const OpaqueValue *>(&opaqueContainer->Buffer);
-
- unsigned alignMask = vwt->getAlignmentMask();
- // Compute the byte offset of the object in the box.
- unsigned byteOffset = (sizeof(HeapObject) + alignMask) & ~alignMask;
- auto *bytePtr = reinterpret_cast<const char *>(
- *reinterpret_cast<HeapObject *const *const>(&opaqueContainer->Buffer));
- return reinterpret_cast<const OpaqueValue *>(bytePtr + byteOffset);
+ return opaqueContainer->projectValue();
}
case ExistentialTypeRepresentation::Error: {
const SwiftError *errorBox