Commit eeaaaabc authored by Kenton Varda's avatar Kenton Varda

Fix obscure bug where allocating an empty struct causes trouble. For reasons I…

Fix obscure bug where allocating an empty struct causes trouble.  For reasons I don't yet fully understand, this actually caused a crash on 32-bit OSX builds (but not 64-bit, nor 32-bit Linux).
parent 7339ac72
......@@ -521,8 +521,8 @@ const Compiler::Node::Content& Compiler::Node::getContent(Content::State minimum
if (minimumState <= Content::BOOTSTRAP) break;
// Create the final schema.
auto nodeSet = locked->translator->finish();
KJ_IF_MAYBE(exception, kj::runCatchingExceptions([&](){
auto nodeSet = locked->translator->finish();
locked->auxSchemas = KJ_MAP(auxNode, nodeSet.auxNodes) {
return module->getCompiler().getFinalLoader().loadOnce(auxNode);
};
......
......@@ -272,6 +272,20 @@ struct WireHelpers {
// segment belonging to the arena. `ref` will be initialized as a non-far pointer, but its
// target offset will be set to zero.
if (amount == 0 * WORDS && kind == WirePointer::STRUCT) {
// Allocating a zero-sized struct. If it happens to be allocated in the space immediately
// after the pointer, we'll have a problem: the pointer will end up all-zero, so isNull()
// will be true. This can lead to all kinds of weird behavior later on. Since the target
// has zero-size anyway, we can really set the pointer to point anywhere, as long as it
// is in-bounds. So, we can have the pointer point back at itself (an offset of -1). This
// should be exceedingly rare in practice since empty structs are pretty useless.
//
// Note that the check for kind == WirePointer::STRUCT will hopefully cause this whole branch
// to be optimized away from all the call sites that are allocating non-structs.
ref->setKindAndTarget(WirePointer::STRUCT, reinterpret_cast<word*>(ref));
return reinterpret_cast<word*>(ref);
}
if (orphanArena == nullptr) {
if (!ref->isNull()) zeroObject(segment, ref);
......
......@@ -816,7 +816,8 @@ private:
// FAR pointer.
word* location;
// Pointer to the object, or null if the tag is a FAR pointer.
// Pointer to the object. Invalid if the tag is a FAR pointer (in which case you need to follow
// the FAR pointer instead).
inline OrphanBuilder(const void* tagPtr, SegmentBuilder* segment, word* location)
: segment(segment), location(location) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment