diff --git a/CHANGELOG b/CHANGELOG
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,5 +1,10 @@
 HsQML - Release History
 
+release-0.3.1.1 - 2014.07.31
+
+  * Fixed crash when storing Haskell objects in QML variants.
+  * Fixed corrupted logging output caused by threading.
+
 release-0.3.1.0 - 2014.06.11
 
   * Added properties with constant annotation.
diff --git a/cbits/Canvas.cpp b/cbits/Canvas.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/Canvas.cpp
@@ -0,0 +1,142 @@
+#include "Canvas.h"
+#include "CanvasImpl.h"
+
+HsQMLGLDelegate::HsQMLGLDelegate(
+    HsQMLGLPaintCb paintCb)
+    : mImpl(new HsQMLGLDelegateImpl(paintCb))
+{
+}
+
+HsQMLGLDelegate::~HsQMLGLDelegate()
+{
+}
+
+HsQMLCanvas::HsQMLCanvas(QQuickItem* parent)
+    : QQuickItem(parent)
+    , mWindow(NULL)
+    , mBackEnd(NULL)
+    , mDisplayMode(Inline)
+    , mCanvasWidth(0)
+    , mCanvasWidthSet(false)
+    , mCanvasHeight(0)
+    , mCanvasHeightSet(false)
+{
+    QObject::connect(
+        this, SIGNAL(windowChanged(QQuickWindow*)),
+        this, SLOT(doWindowChanged(QQuickWindow*)));
+}
+
+HsQMLCanvas::~HsQMLCanvas()
+{
+    detachBackEnd();
+}
+
+void HsQMLCanvas::geometryChanged(const QRectF& rect, const QRectF&)
+{
+    if (!mCanvasWidthSet) {
+        setCanvasWidth(rect.width(), false);
+    }
+    if (!mCanvasHeightSet) {
+        setCanvasHeight(rect.height(), false);
+    }
+}
+
+void HsQMLCanvas::detachBackEnd()
+{
+    if (mBackEnd) {
+        // The back-end belongs to the rendering thread
+        mBackEnd->deleteLater();
+        mBackEnd = NULL;
+    }
+}
+
+HsQMLCanvas::DisplayMode HsQMLCanvas::displayMode() const
+{
+    return mDisplayMode;
+}
+
+void HsQMLCanvas::setDisplayMode(HsQMLCanvas::DisplayMode mode)
+{
+    bool change = mDisplayMode != mode;
+    mDisplayMode = mode;
+    if (change) {
+        displayModeChanged();
+    }
+}
+
+qreal HsQMLCanvas::canvasWidth() const
+{
+    return mCanvasWidth;
+}
+
+void HsQMLCanvas::setCanvasWidth(qreal w, bool set)
+{
+    bool change = mCanvasWidth != w;
+    mCanvasWidth = w;
+    mCanvasWidthSet |= set;
+    if (change) {
+        canvasWidthChanged();
+    }
+}
+
+void HsQMLCanvas::unsetCanvasWidth()
+{
+    mCanvasWidthSet = false;
+    setCanvasWidth(width(), false);
+}
+
+qreal HsQMLCanvas::canvasHeight() const
+{
+    return mCanvasHeight;
+}
+
+void HsQMLCanvas::setCanvasHeight(qreal h, bool set)
+{
+    bool change = mCanvasHeight != h;
+    mCanvasHeight = h;
+    mCanvasHeightSet |= set;
+    if (change) {
+        canvasHeightChanged();
+    }
+}
+
+void HsQMLCanvas::unsetCanvasHeight()
+{
+    mCanvasHeightSet = false;
+    setCanvasHeight(height(), false);
+}
+
+void HsQMLCanvas::doWindowChanged(QQuickWindow* win)
+{
+    if (mWindow) {
+        QObject::disconnect(mWindow, NULL, this, NULL);
+        detachBackEnd();
+    }
+    mWindow = win;
+    if (mWindow) {
+        QObject::connect(
+            mWindow, SIGNAL(beforeSynchronizing()),
+            this, SLOT(doPreSynchronise()), Qt::DirectConnection);
+    }
+}
+
+void HsQMLCanvas::doPreSynchronise()
+{
+    // This executes on the rendering thread
+    if (!mBackEnd) {
+        mBackEnd = new HsQMLCanvasBackEnd(mWindow);
+    }
+    mBackEnd->setModeSize(mDisplayMode, mCanvasWidth, mCanvasHeight);
+}
+
+HsQMLGLControl::HsQMLGLControl(QQuickItem* parent)
+    : QQuickItem(parent)
+{}
+
+void hsqml_init_jval_gldelegate(
+    HsQMLJValHandle* hndl,
+    HsQMLGLPaintCb paintCb)
+{
+    QJSValue* value = reinterpret_cast<QJSValue*>(hndl);
+    HsQMLGLDelegate delegate(paintCb);
+}
diff --git a/cbits/Canvas.h b/cbits/Canvas.h
new file mode 100644
--- /dev/null
+++ b/cbits/Canvas.h
@@ -0,0 +1,78 @@
+#ifndef HSQML_CANVAS_H
+#define HSQML_CANVAS_H
+
+#include <QtCore/QExplicitlySharedDataPointer>
+#include <QtQuick/QQuickItem>
+
+#include "hsqml.h"
+
+class HsQMLCanvasBackEnd;
+class HsQMLGLDelegateImpl;
+
+class HsQMLGLDelegate
+{
+public:
+    HsQMLGLDelegate(HsQMLGLPaintCb);
+    ~HsQMLGLDelegate();
+
+private:
+    QExplicitlySharedDataPointer<HsQMLGLDelegateImpl> mImpl;
+};
+
+class HsQMLCanvas : public QQuickItem
+{
+    Q_OBJECT
+    Q_ENUMS(DisplayMode)
+    Q_PROPERTY(DisplayMode displayMode READ displayMode WRITE setDisplayMode
+        NOTIFY displayModeChanged)
+    Q_PROPERTY(qreal canvasWidth READ canvasWidth WRITE setCanvasWidth
+        RESET unsetCanvasWidth NOTIFY canvasWidthChanged)
+    Q_PROPERTY(qreal canvasHeight READ canvasHeight WRITE setCanvasHeight
+        RESET unsetCanvasHeight NOTIFY canvasHeightChanged)
+
+public:
+    enum DisplayMode {Above, Below, Inline};
+
+    HsQMLCanvas(QQuickItem* = NULL);
+    ~HsQMLCanvas();
+
+private:
+    Q_DISABLE_COPY(HsQMLCanvas);
+
+    void geometryChanged(const QRectF&, const QRectF&) Q_DECL_OVERRIDE;
+    void detachBackEnd();
+    DisplayMode displayMode() const;
+    void setDisplayMode(DisplayMode);
+    qreal canvasWidth() const;
+    void setCanvasWidth(qreal, bool = true);
+    void unsetCanvasWidth();
+    qreal canvasHeight() const;
+    void setCanvasHeight(qreal, bool = true);
+    void unsetCanvasHeight();
+    Q_SIGNAL void displayModeChanged();
+    Q_SIGNAL void canvasWidthChanged();
+    Q_SIGNAL void canvasHeightChanged();
+    Q_SLOT void doWindowChanged(QQuickWindow*);
+    Q_SLOT void doPreSynchronise();
+
+    QQuickWindow* mWindow;
+    HsQMLCanvasBackEnd* mBackEnd;
+    DisplayMode mDisplayMode;
+    qreal mCanvasWidth;
+    bool mCanvasWidthSet;
+    qreal mCanvasHeight;
+    bool mCanvasHeightSet;
+};
+
+class HsQMLGLControl : public QQuickItem
+{
+    Q_OBJECT
+
+public:
+    HsQMLGLControl(QQuickItem* = NULL);
+
+private:
+    Q_DISABLE_COPY(HsQMLGLControl);
+};
+
+#endif //HSQML_CANVAS_H
diff --git a/cbits/CanvasImpl.cpp b/cbits/CanvasImpl.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/CanvasImpl.cpp
@@ -0,0 +1,56 @@
+#include <QtCore/qmath.h>
+
+#include "CanvasImpl.h"
+#include "Manager.h"
+
+HsQMLGLDelegateImpl::HsQMLGLDelegateImpl(HsQMLGLPaintCb paintCb)
+    : mPaintCb(paintCb)
+{}
+
+HsQMLGLDelegateImpl::~HsQMLGLDelegateImpl()
+{
+    gManager->freeFun(reinterpret_cast<HsFunPtr>(mPaintCb));
+}
+
+HsQMLCanvasBackEnd::HsQMLCanvasBackEnd(QQuickWindow* win)
+{
+    QObject::connect(
+        win, SIGNAL(beforeRendering()),
+        this, SLOT(doRendering()));
+}
+
+HsQMLCanvasBackEnd::~HsQMLCanvasBackEnd()
+{
+}
+
+void HsQMLCanvasBackEnd::setModeSize(
+    HsQMLCanvas::DisplayMode mode, qreal w, qreal h)
+{
+    mDisplayMode = mode;
+    mCanvasWidth = w;
+    mCanvasHeight = h;
+
+    if (HsQMLCanvas::Inline == mode) {
+        if (!mFBO || mFBO->width() != w || mFBO->height() != h) {
+            mFBO.reset(new QOpenGLFramebufferObject(
+                qCeil(w), qCeil(h), QOpenGLFramebufferObject::Depth));
+        }
+    }
+    else {
+        mFBO.reset();
+    }
+}
+
+void HsQMLCanvasBackEnd::doRendering()
+{
+    bool inlineMode = HsQMLCanvas::Inline == mDisplayMode;
+    if (inlineMode && !mFBO) {
+        return;
+    }
+    if (inlineMode) {
+        mFBO->bind();
+    }
+    if (inlineMode) {
+        mFBO->release();
+    }
+}
diff --git a/cbits/CanvasImpl.h b/cbits/CanvasImpl.h
new file mode 100644
--- /dev/null
+++ b/cbits/CanvasImpl.h
@@ -0,0 +1,41 @@
+#ifndef HSQML_CANVAS_IMPL_H
+#define HSQML_CANVAS_IMPL_H
+
+#include <QtCore/QObject>
+#include <QtCore/QScopedPointer>
+#include <QtCore/QSharedData>
+#include <QtGui/QOpenGLFramebufferObject>
+#include <QtQuick/QQuickWindow>
+
+#include "Canvas.h"
+
+class HsQMLGLDelegateImpl : public QSharedData
+{
+public:
+    HsQMLGLDelegateImpl(HsQMLGLPaintCb);
+    ~HsQMLGLDelegateImpl();
+
+    HsQMLGLPaintCb mPaintCb;
+};
+
+class HsQMLCanvasBackEnd : public QObject
+{
+    Q_OBJECT
+
+public:
+    HsQMLCanvasBackEnd(QQuickWindow*);
+    ~HsQMLCanvasBackEnd();
+    void setModeSize(HsQMLCanvas::DisplayMode, qreal, qreal);
+
+private:
+    Q_DISABLE_COPY(HsQMLCanvasBackEnd)
+
+    Q_SLOT void doRendering();
+
+    HsQMLCanvas::DisplayMode mDisplayMode;
+    qreal mCanvasWidth;
+    qreal mCanvasHeight;
+    QScopedPointer<QOpenGLFramebufferObject> mFBO;
+};
+
+#endif //HSQML_CANVAS_IMPL_H
diff --git a/cbits/Manager.cpp b/cbits/Manager.cpp
--- a/cbits/Manager.cpp
+++ b/cbits/Manager.cpp
@@ -1,4 +1,4 @@
-#include <iostream>
+#include <cstdio>
 #include <cstdlib>
 #include <QtCore/QBasicTimer>
 #include <QtCore/QMetaType>
@@ -101,7 +101,8 @@
 
 void HsQMLManager::log(const QString& msg)
 {
-    std::cerr << "HsQML: " << msg.toStdString() << std::endl;
+    QMutexLocker locker(&mLogLock);
+    fprintf(stderr, "HsQML: %s\n", msg.toUtf8().data());
 }
 
 int HsQMLManager::updateCounter(CounterId id, int delta)
@@ -119,6 +120,17 @@
     mFreeStable(stablePtr);
 }
 
+void HsQMLManager::registerObject(const QObject* obj)
+{
+    mObjectSet.insert(obj);
+}
+
+void HsQMLManager::unregisterObject(const QObject* obj)
+{
+    bool removed = mObjectSet.remove(obj);
+    Q_ASSERT(removed);
+}
+
 void HsQMLManager::hookedConstruct(QVariant::Private* p, const void* copy)
 {
     char guard;
@@ -134,7 +146,8 @@
     // that the stack can be discounted, it's possible to keep an accurate
     // count of heap references using these hooks.
     if ((pp < &guard || pp > mStackBase) && p->type == QMetaType::QObjectStar) {
-        if (HsQMLObject* obj = dynamic_cast<HsQMLObject*>(p->data.o)) {
+        if (isEventThread() && mObjectSet.contains(p->data.o)) {
+            HsQMLObject* obj = static_cast<HsQMLObject*>(p->data.o);
             HsQMLObjectProxy* proxy = obj->proxy();
             proxy->ref(HsQMLObjectProxy::Variant);
             proxy->tryGCLock();
@@ -148,7 +161,8 @@
     char guard;
     void* pp = reinterpret_cast<void*>(p);
     if ((pp < &guard || pp > mStackBase) && p->type == QMetaType::QObjectStar) {
-        if (HsQMLObject* obj = dynamic_cast<HsQMLObject*>(p->data.o)) {
+        if (isEventThread() && mObjectSet.contains(p->data.o)) {
+            HsQMLObject* obj = static_cast<HsQMLObject*>(p->data.o);
             obj->proxy()->deref(HsQMLObjectProxy::Variant);
             updateCounter(VariantCount, -1);
         }
diff --git a/cbits/Manager.h b/cbits/Manager.h
--- a/cbits/Manager.h
+++ b/cbits/Manager.h
@@ -4,6 +4,7 @@
 #include <QtCore/QAtomicPointer>
 #include <QtCore/QAtomicInt>
 #include <QtCore/QMutex>
+#include <QtCore/QSet>
 #include <QtCore/QString>
 #include <QtCore/QVariant>
 #include <QtWidgets/QApplication>
@@ -38,6 +39,8 @@
     int updateCounter(CounterId, int);
     void freeFun(HsFunPtr);
     void freeStable(HsStablePtr);
+    void registerObject(const QObject*);
+    void unregisterObject(const QObject*);
     void hookedConstruct(QVariant::Private*, const void*);
     void hookedClear(QVariant::Private*);
     bool isEventThread();
@@ -57,10 +60,12 @@
     Q_DISABLE_COPY(HsQMLManager)
 
     int mLogLevel;
+    QMutex mLogLock;
     QAtomicInt mCounters[TotalCounters];
     bool mAtExit;
     void (*mFreeFun)(HsFunPtr);
     void (*mFreeStable)(HsStablePtr);
+    QSet<const QObject*> mObjectSet;
     const QVariant::Handler* mOriginalHandler;
     QVariant::Handler mHookedHandler;
     HsQMLManagerApp* mApp;
diff --git a/cbits/Object.cpp b/cbits/Object.cpp
--- a/cbits/Object.cpp
+++ b/cbits/Object.cpp
@@ -167,6 +167,7 @@
     QQmlEngine::setObjectOwnership(
         this, QQmlEngine::JavaScriptOwnership);
     mProxy->ref(HsQMLObjectProxy::Object);
+    gManager->registerObject(this);
     gManager->updateCounter(HsQMLManager::QObjectCount, 1);
 }
 
@@ -174,6 +175,7 @@
 {
     mProxy->clearObject();
     mProxy->deref(HsQMLObjectProxy::Object);
+    gManager->unregisterObject(this);
     gManager->updateCounter(HsQMLManager::QObjectCount, -1);
 }
 
diff --git a/hsqml.cabal b/hsqml.cabal
--- a/hsqml.cabal
+++ b/hsqml.cabal
@@ -1,5 +1,5 @@
 Name:               hsqml
-Version:            0.3.1.0
+Version:            0.3.1.1
 Cabal-version:      >= 1.14
 Build-type:         Custom
 License:            BSD3
@@ -16,9 +16,9 @@
     README CHANGELOG SetupNoTH.hs
     cbits/*.cpp cbits/*.h test/Graphics/QML/Test/*.hs
 Description:
-    A Haskell binding for Qt Quick.
-
-    General documentation is present in the 'Graphics.QML' module.
+    A Haskell binding for Qt Quick, a cross-platform framework for creating
+    graphical user interfaces. For further information on installing and using
+    this library, please see the project's web site.
 
 Flag UsePkgConfig
     Description:
diff --git a/src/Graphics/QML/Internal/BindPrim.chs b/src/Graphics/QML/Internal/BindPrim.chs
--- a/src/Graphics/QML/Internal/BindPrim.chs
+++ b/src/Graphics/QML/Internal/BindPrim.chs
@@ -26,7 +26,7 @@
   `Int' fromIntegral #}
 
 hsqmlStringSize :: Int
-hsqmlStringSize = unsafePerformIO $ hsqmlGetStringSize
+hsqmlStringSize = unsafeDupablePerformIO $ hsqmlGetStringSize
 
 {#fun unsafe hsqml_init_string as ^
   {id `HsQMLStringHandle'} ->
@@ -66,14 +66,14 @@
   `Int' fromIntegral #}
 
 hsqmlJValSize :: Int
-hsqmlJValSize = unsafePerformIO $ hsqmlGetJvalSize
+hsqmlJValSize = unsafeDupablePerformIO $ hsqmlGetJvalSize
 
 {#fun unsafe hsqml_get_jval_typeid as ^
   {} ->
   `Int' fromIntegral #}
 
 hsqmlJValTypeId :: Int
-hsqmlJValTypeId = unsafePerformIO $ hsqmlGetJvalTypeid
+hsqmlJValTypeId = unsafeDupablePerformIO $ hsqmlGetJvalTypeid
 
 {#fun unsafe hsqml_init_jval_null as ^
   {id `HsQMLJValHandle',
diff --git a/src/Graphics/QML/Objects.hs b/src/Graphics/QML/Objects.hs
--- a/src/Graphics/QML/Objects.hs
+++ b/src/Graphics/QML/Objects.hs
@@ -128,12 +128,10 @@
 -- | Returns the associated value of the underlying Haskell type @tt@ from an
 -- instance of the QML class which wraps it.
 fromObjRef :: ObjRef tt -> tt
-fromObjRef =
-    unsafePerformIO . fromObjRefIO
+fromObjRef = unsafeDupablePerformIO . fromObjRefIO
 
 fromObjRefIO :: ObjRef tt -> IO tt
-fromObjRefIO =
-    hsqmlObjectGetHsValue . objHndl 
+fromObjRefIO = hsqmlObjectGetHsValue . objHndl
 
 -- | Represents an instance of a QML class which wraps an arbitrary Haskell
 -- type. Unlike 'ObjRef', an 'AnyObjRef' only carries the type of its Haskell
@@ -170,7 +168,7 @@
 -- | Attempts to downcast an 'AnyObjRef' into an 'ObjRef' with the specific
 -- underlying Haskell type @tt@.
 fromAnyObjRef :: (Typeable tt) => AnyObjRef -> Maybe (ObjRef tt)
-fromAnyObjRef = unsafePerformIO . fromAnyObjRefIO
+fromAnyObjRef = unsafeDupablePerformIO . fromAnyObjRefIO
 
 fromAnyObjRefIO :: forall tt. (Typeable tt) =>
     AnyObjRef -> IO (Maybe (ObjRef tt))
