Files
swift-mirror/include/swift/Runtime/ExistentialContainer.h
Michael Gottesman ba9946a131 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.
2018-02-23 23:03:55 -08:00

103 lines
3.6 KiB
C++

//===--- 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