Skip to content

Commit

Permalink
Fix crashes on Electron 22
Browse files Browse the repository at this point in the history
  • Loading branch information
indutny-signal committed Dec 16, 2022
1 parent 22ef5d8 commit 1bf85ef
Show file tree
Hide file tree
Showing 9 changed files with 336 additions and 58 deletions.
124 changes: 85 additions & 39 deletions src/better_sqlite3.cpp

Large diffs are not rendered by default.

108 changes: 100 additions & 8 deletions src/better_sqlite3.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,52 @@
#include <algorithm>
#include <sqlite3.h>
#include <node.h>
#include <node_object_wrap.h>
#include <node_buffer.h>
#line 31 "./src/util/macros.lzz"
template <class T> using CopyablePersistent = v8::Persistent<T, v8::CopyablePersistentTraits<T>>;
#line 36 "./src/util/binder.lzz"
static bool IsPlainObject(v8::Isolate* isolate, v8::Local<v8::Object> obj);
#define LZZ_INLINE inline
#line 32 "./src/util/object_wrap.lzz"
class ObjectWrapForElectron22
{
#line 33 "./src/util/object_wrap.lzz"
public:
#line 34 "./src/util/object_wrap.lzz"
ObjectWrapForElectron22 ();
#line 39 "./src/util/object_wrap.lzz"
virtual ~ ObjectWrapForElectron22 ();
#line 47 "./src/util/object_wrap.lzz"
template <typename T>
#line 48 "./src/util/object_wrap.lzz"
static T * Unwrap (v8::Local <v8::Object> handle);
#line 61 "./src/util/object_wrap.lzz"
v8::Local <v8::Object> handle ();
#line 66 "./src/util/object_wrap.lzz"
v8::Local <v8::Object> handle (v8::Isolate * isolate);
#line 72 "./src/util/object_wrap.lzz"
v8::Persistent <v8::Object> & persistent ();
#line 77 "./src/util/object_wrap.lzz"
protected:
#line 78 "./src/util/object_wrap.lzz"
void Wrap (v8::Local <v8::Object> handle);
#line 90 "./src/util/object_wrap.lzz"
void MakeWeak ();
#line 98 "./src/util/object_wrap.lzz"
virtual void Ref ();
#line 113 "./src/util/object_wrap.lzz"
virtual void Unref ();
#line 121 "./src/util/object_wrap.lzz"
int refs_;
#line 123 "./src/util/object_wrap.lzz"
private:
#line 124 "./src/util/object_wrap.lzz"
static void WeakCallback (v8::WeakCallbackInfo <ObjectWrapForElectron22> const & data);
#line 133 "./src/util/object_wrap.lzz"
v8::Persistent <v8::Object> handle_;
#line 136 "./src/util/object_wrap.lzz"
static uint16_t kNodeEmbedderId;
};
#line 16 "./src/util/macros.lzz"
v8::Local <v8::String> StringFromUtf8 (v8::Isolate * isolate, char const * data, int length);
#line 19 "./src/util/macros.lzz"
Expand Down Expand Up @@ -49,11 +88,11 @@ template <typename T>
void FREE_ARRAY (T * array_pointer);
#line 105 "./src/util/macros.lzz"
v8::Local <v8::FunctionTemplate> NewConstructorTemplate (v8::Isolate * isolate, v8::Local <v8::External> data, v8::FunctionCallback func, char const * name);
#line 116 "./src/util/macros.lzz"
#line 118 "./src/util/macros.lzz"
void SetPrototypeMethod (v8::Isolate * isolate, v8::Local <v8::External> data, v8::Local <v8::FunctionTemplate> recv, char const * name, v8::FunctionCallback func);
#line 129 "./src/util/macros.lzz"
#line 131 "./src/util/macros.lzz"
void SetPrototypeSymbolMethod (v8::Isolate * isolate, v8::Local <v8::External> data, v8::Local <v8::FunctionTemplate> recv, v8::Local <v8::Symbol> symbol, v8::FunctionCallback func);
#line 142 "./src/util/macros.lzz"
#line 144 "./src/util/macros.lzz"
void SetPrototypeGetter (v8::Isolate * isolate, v8::Local <v8::External> data, v8::Local <v8::FunctionTemplate> recv, char const * name, v8::AccessorGetterCallback func);
#line 1 "./src/util/constants.lzz"
class CS
Expand Down Expand Up @@ -164,7 +203,7 @@ class Statement;
#line 22 "./src/better_sqlite3.lzz"
class Backup;
#line 1 "./src/objects/database.lzz"
class Database : public node::ObjectWrap
class Database : public ObjectWrapForElectron22
{
#line 2 "./src/objects/database.lzz"
public:
Expand Down Expand Up @@ -306,7 +345,7 @@ class Database : public node::ObjectWrap
std::set <Backup*, CompareBackup> backups;
};
#line 1 "./src/objects/statement.lzz"
class Statement : public node::ObjectWrap
class Statement : public ObjectWrapForElectron22
{
#line 1 "./src/objects/statement.lzz"
friend class StatementIterator;
Expand Down Expand Up @@ -384,7 +423,7 @@ class Statement : public node::ObjectWrap
bool const returns_data;
};
#line 1 "./src/objects/statement-iterator.lzz"
class StatementIterator : public node::ObjectWrap
class StatementIterator : public ObjectWrapForElectron22
{
#line 2 "./src/objects/statement-iterator.lzz"
public:
Expand Down Expand Up @@ -434,7 +473,7 @@ class StatementIterator : public node::ObjectWrap
bool logged;
};
#line 1 "./src/objects/backup.lzz"
class Backup : public node::ObjectWrap
class Backup : public ObjectWrapForElectron22
{
#line 2 "./src/objects/backup.lzz"
public:
Expand Down Expand Up @@ -803,6 +842,59 @@ struct Addon
#line 63 "./src/better_sqlite3.lzz"
std::set <Database*, Database::CompareDatabase> dbs;
};
#line 47 "./src/util/object_wrap.lzz"
template <typename T>
#line 48 "./src/util/object_wrap.lzz"
LZZ_INLINE T * ObjectWrapForElectron22::Unwrap (v8::Local <v8::Object> handle)
#line 48 "./src/util/object_wrap.lzz"
{
assert(!handle.IsEmpty());
assert(handle->InternalFieldCount() > 1);



void* ptr = handle->GetAlignedPointerFromInternalField(1);

ObjectWrapForElectron22* wrap = static_cast<ObjectWrapForElectron22*>(ptr);
return static_cast<T*>(wrap);
}
#line 61 "./src/util/object_wrap.lzz"
LZZ_INLINE v8::Local <v8::Object> ObjectWrapForElectron22::handle ()
#line 61 "./src/util/object_wrap.lzz"
{
return handle(v8::Isolate::GetCurrent());
}
#line 66 "./src/util/object_wrap.lzz"
LZZ_INLINE v8::Local <v8::Object> ObjectWrapForElectron22::handle (v8::Isolate * isolate)
#line 66 "./src/util/object_wrap.lzz"
{
return v8::Local<v8::Object>::New(isolate, persistent());
}
#line 72 "./src/util/object_wrap.lzz"
LZZ_INLINE v8::Persistent <v8::Object> & ObjectWrapForElectron22::persistent ()
#line 72 "./src/util/object_wrap.lzz"
{
return handle_;
}
#line 78 "./src/util/object_wrap.lzz"
LZZ_INLINE void ObjectWrapForElectron22::Wrap (v8::Local <v8::Object> handle)
#line 78 "./src/util/object_wrap.lzz"
{
assert(persistent().IsEmpty());
assert(handle->InternalFieldCount() > 1);

handle->SetAlignedPointerInInternalField(0, &kNodeEmbedderId);
handle->SetAlignedPointerInInternalField(1, this);

persistent().Reset(v8::Isolate::GetCurrent(), handle);
MakeWeak();
}
#line 90 "./src/util/object_wrap.lzz"
LZZ_INLINE void ObjectWrapForElectron22::MakeWeak ()
#line 90 "./src/util/object_wrap.lzz"
{
persistent().SetWeak(this, WeakCallback, v8::WeakCallbackType::kParameter);
}
#line 16 "./src/util/macros.lzz"
LZZ_INLINE v8::Local <v8::String> StringFromUtf8 (v8::Isolate * isolate, char const * data, int length)
#line 16 "./src/util/macros.lzz"
Expand Down
2 changes: 1 addition & 1 deletion src/better_sqlite3.lzz
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@
#include <algorithm>
#include <sqlite3.h>
#include <node.h>
#include <node_object_wrap.h>
#include <node_buffer.h>
#end

#insert "util/object_wrap.lzz"
#insert "util/macros.lzz"
#insert "util/query-macros.lzz"
#insert "util/constants.lzz"
Expand Down
4 changes: 2 additions & 2 deletions src/objects/backup.lzz
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
class Backup : public node::ObjectWrap {
class Backup : public ObjectWrapForElectron22 {
public:

INIT(Init) {
Expand Down Expand Up @@ -39,7 +39,7 @@ private:
sqlite3_uint64 id,
bool unlink
) :
node::ObjectWrap(),
ObjectWrapForElectron22(),
db(db),
dest_handle(dest_handle),
backup_handle(backup_handle),
Expand Down
4 changes: 2 additions & 2 deletions src/objects/database.lzz
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
class Database : public node::ObjectWrap {
class Database : public ObjectWrapForElectron22 {
public:

INIT(Init) {
Expand Down Expand Up @@ -129,7 +129,7 @@ private:
sqlite3* db_handle,
v8::Local<v8::Value> logger
) :
node::ObjectWrap(),
ObjectWrapForElectron22(),
db_handle(db_handle),
open(true),
busy(false),
Expand Down
4 changes: 2 additions & 2 deletions src/objects/statement-iterator.lzz
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
class StatementIterator : public node::ObjectWrap {
class StatementIterator : public ObjectWrapForElectron22 {
public:

INIT(Init) {
Expand All @@ -16,7 +16,7 @@ public:

private:

explicit StatementIterator(Statement* stmt, bool bound) : node::ObjectWrap(),
explicit StatementIterator(Statement* stmt, bool bound) : ObjectWrapForElectron22(),
stmt(stmt),
handle(stmt->handle),
db_state(stmt->db->GetState()),
Expand Down
4 changes: 2 additions & 2 deletions src/objects/statement.lzz
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
class Statement : public node::ObjectWrap { friend class StatementIterator;
class Statement : public ObjectWrapForElectron22 { friend class StatementIterator;
public:

INIT(Init) {
Expand Down Expand Up @@ -64,7 +64,7 @@ private:
sqlite3_uint64 id,
bool returns_data
) :
node::ObjectWrap(),
ObjectWrapForElectron22(),
db(db),
handle(handle),
extras(new Extras(id)),
Expand Down
6 changes: 4 additions & 2 deletions src/util/macros.lzz
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
#define UseIsolate v8::Isolate* isolate = OnlyIsolate
#define UseContext v8::Local<v8::Context> ctx = OnlyContext
#define UseAddon Addon* addon = OnlyAddon
#define Unwrap node::ObjectWrap::Unwrap
#define Unwrap ObjectWrapForElectron22::Unwrap

inline v8::Local<v8::String> StringFromUtf8(v8::Isolate* isolate, const char* data, int length) {
return v8::String::NewFromUtf8(isolate, data, v8::NewStringType::kNormal, length).ToLocalChecked();
Expand Down Expand Up @@ -109,7 +109,9 @@ v8::Local<v8::FunctionTemplate> NewConstructorTemplate(
const char* name
) {
v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate, func, data);
t->InstanceTemplate()->SetInternalFieldCount(1);
// SIGNAL CHANGES BEGIN
t->InstanceTemplate()->SetInternalFieldCount(2);
// SIGNAL CHANGES END
t->SetClassName(InternalizedFromLatin1(isolate, name));
return t;
}
Expand Down
138 changes: 138 additions & 0 deletions src/util/object_wrap.lzz
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.

// Original code taken from:
// https://github.com/nodejs/node/blob/4166d40d0873b6d8a0c7291872c8d20dc680b1d7/src/node_object_wrap.h

// The code for ObjectWrapForElectron22 is identical to node::ObjectWrap, except
// it requires two internal fields on the object. First field is set to a
// pointer to kNodeEmbedderId, and the second to the actual object pointer.
// This fixes intermittent crashes on Electron 22-x-y.
//
// See: https://github.com/nodejs/node/pull/43521

class ObjectWrapForElectron22 {
public:
ObjectWrapForElectron22() {
refs_ = 0;
}


virtual ~ObjectWrapForElectron22() {
if (persistent().IsEmpty())
return;
persistent().ClearWeak();
persistent().Reset();
}


template <class T>
static inline T* Unwrap(v8::Local<v8::Object> handle) {
assert(!handle.IsEmpty());
assert(handle->InternalFieldCount() > 1);
// Cast to ObjectWrapForElectron22 before casting to T. A direct cast from void
// to T won't work right when T has more than one base class.
// SIGNAL CHANGES BEGIN
void* ptr = handle->GetAlignedPointerFromInternalField(1);
// SIGNAL CHANGES END
ObjectWrapForElectron22* wrap = static_cast<ObjectWrapForElectron22*>(ptr);
return static_cast<T*>(wrap);
}


inline v8::Local<v8::Object> handle() {
return handle(v8::Isolate::GetCurrent());
}


inline v8::Local<v8::Object> handle(v8::Isolate* isolate) {
return v8::Local<v8::Object>::New(isolate, persistent());
}


// NOLINTNEXTLINE(runtime/v8_persistent)
inline v8::Persistent<v8::Object>& persistent() {
return handle_;
}


protected:
inline void Wrap(v8::Local<v8::Object> handle) {
assert(persistent().IsEmpty());
assert(handle->InternalFieldCount() > 1);
// SIGNAL CHANGES BEGIN
handle->SetAlignedPointerInInternalField(0, &kNodeEmbedderId);
handle->SetAlignedPointerInInternalField(1, this);
// SIGNAL CHANGES END
persistent().Reset(v8::Isolate::GetCurrent(), handle);
MakeWeak();
}


inline void MakeWeak() {
persistent().SetWeak(this, WeakCallback, v8::WeakCallbackType::kParameter);
}

/* Ref() marks the object as being attached to an event loop.
* Refed objects will not be garbage collected, even if
* all references are lost.
*/
virtual void Ref() {
assert(!persistent().IsEmpty());
persistent().ClearWeak();
refs_++;
}

/* Unref() marks an object as detached from the event loop. This is its
* default state. When an object with a "weak" reference changes from
* attached to detached state it will be freed. Be careful not to access
* the object after making this call as it might be gone!
* (A "weak reference" means an object that only has a
* persistent handle.)
*
* DO NOT CALL THIS FROM DESTRUCTOR
*/
virtual void Unref() {
assert(!persistent().IsEmpty());
assert(!persistent().IsWeak());
assert(refs_ > 0);
if (--refs_ == 0)
MakeWeak();
}

int refs_; // ro

private:
static void WeakCallback(
const v8::WeakCallbackInfo<ObjectWrapForElectron22>& data) {
ObjectWrapForElectron22* wrap = data.GetParameter();
assert(wrap->refs_ == 0);
wrap->handle_.Reset();
delete wrap;
}

// NOLINTNEXTLINE(runtime/v8_persistent)
v8::Persistent<v8::Object> handle_;

// SIGNAL CHANGES BEGIN
static uint16_t kNodeEmbedderId = 0x90de;
// SIGNAL CHANGES END
};

0 comments on commit 1bf85ef

Please sign in to comment.