Skip to content

Commit a1d1911

Browse files
committedMay 13, 2025·
Fix crash around blobs
1 parent 0d40b3a commit a1d1911

File tree

5 files changed

+36
-16
lines changed

5 files changed

+36
-16
lines changed
 

‎.changeset/six-moose-buy.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@journeyapps/react-native-quick-sqlite": patch
3+
---
4+
5+
Fix crash when binding or reading blobs.

‎cpp/JSIHelper.cpp

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
#include "JSIHelper.h"
99

10+
#include <utility>
11+
1012
using namespace std;
1113
using namespace facebook;
1214

@@ -27,7 +29,7 @@ QuickValue createTextQuickValue(string value)
2729
{
2830
return QuickValue{
2931
.dataType = TEXT,
30-
.textValue = value};
32+
.textValue = std::move(value)};
3133
}
3234

3335
QuickValue createIntegerQuickValue(int value)
@@ -58,12 +60,13 @@ QuickValue createDoubleQuickValue(double value)
5860
.doubleOrIntValue = value};
5961
}
6062

61-
QuickValue createArrayBufferQuickValue(uint8_t *arrayBufferValue, size_t arrayBufferSize)
63+
QuickValue createArrayBufferQuickValueByCopying(const uint8_t *arrayBufferValue, size_t arrayBufferSize)
6264
{
65+
vector<uint8_t> copy(arrayBufferValue, arrayBufferValue + arrayBufferSize);
66+
6367
return QuickValue{
6468
.dataType = ARRAY_BUFFER,
65-
.arrayBufferValue = shared_ptr<uint8_t>{arrayBufferValue},
66-
.arrayBufferSize = arrayBufferSize};
69+
.arrayBuffer = copy};
6770
}
6871

6972
void jsiQueryArgumentsToSequelParam(jsi::Runtime &rt, jsi::Value const &params, vector<QuickValue> *target)
@@ -116,7 +119,7 @@ void jsiQueryArgumentsToSequelParam(jsi::Runtime &rt, jsi::Value const &params,
116119
if (obj.isArrayBuffer(rt))
117120
{
118121
auto buf = obj.getArrayBuffer(rt);
119-
target->push_back(createArrayBufferQuickValue(buf.data(rt), buf.size(rt)));
122+
target->push_back(createArrayBufferQuickValueByCopying(buf.data(rt), buf.size(rt)));
120123
}
121124
}
122125
else
@@ -171,10 +174,10 @@ jsi::Value createSequelQueryExecutionResult(jsi::Runtime &rt, SQLiteOPResult sta
171174
} else if (value.dataType == ARRAY_BUFFER)
172175
{
173176
jsi::Function array_buffer_ctor = rt.global().getPropertyAsFunction(rt, "ArrayBuffer");
174-
jsi::Object o = array_buffer_ctor.callAsConstructor(rt, (int) value.arrayBufferSize).getObject(rt);
177+
jsi::Object o = array_buffer_ctor.callAsConstructor(rt, (int) value.arrayBuffer.size()).getObject(rt);
175178
jsi::ArrayBuffer buf = o.getArrayBuffer(rt);
176179
// It's a shame we have to copy here: see https://github.com/facebook/hermes/pull/419 and https://github.com/facebook/hermes/issues/564.
177-
memcpy(buf.data(rt), value.arrayBufferValue.get(), value.arrayBufferSize);
180+
memcpy(buf.data(rt), value.arrayBuffer.data(), value.arrayBuffer.size());
178181
rowObject.setProperty(rt, columnName.c_str(), o);
179182
} else
180183
{

‎cpp/JSIHelper.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,7 @@ struct QuickValue
4141
double doubleOrIntValue;
4242
long long int64Value;
4343
string textValue;
44-
shared_ptr<uint8_t> arrayBufferValue;
45-
size_t arrayBufferSize;
44+
vector<uint8_t> arrayBuffer;
4645
};
4746

4847
/**
@@ -108,7 +107,7 @@ QuickValue createIntegerQuickValue(int value);
108107
QuickValue createIntegerQuickValue(double value);
109108
QuickValue createInt64QuickValue(long long value);
110109
QuickValue createDoubleQuickValue(double value);
111-
QuickValue createArrayBufferQuickValue(uint8_t *arrayBufferValue, size_t arrayBufferSize);
110+
QuickValue createArrayBufferQuickValueByCopying(const uint8_t *arrayBufferValue, size_t arrayBufferSize);
112111
jsi::Value createSequelQueryExecutionResult(jsi::Runtime &rt, SQLiteOPResult status, vector<map<string, QuickValue>> *results, vector<QuickColumnMetadata> *metadata);
113112

114113
#endif /* JSIHelper_h */

‎cpp/sqliteExecute.cpp

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ void bindStatement(sqlite3_stmt *statement, vector<QuickValue> *values) {
88

99
for (int ii = 0; ii < size; ii++) {
1010
int sqIndex = ii + 1;
11-
QuickValue value = values->at(ii);
11+
const QuickValue& value = values->at(ii);
1212
QuickDataType dataType = value.dataType;
1313
if (dataType == NULL_VALUE) {
1414
sqlite3_bind_null(statement, sqIndex);
@@ -24,8 +24,8 @@ void bindStatement(sqlite3_stmt *statement, vector<QuickValue> *values) {
2424
sqlite3_bind_text(statement, sqIndex, value.textValue.c_str(),
2525
value.textValue.length(), SQLITE_TRANSIENT);
2626
} else if (dataType == ARRAY_BUFFER) {
27-
sqlite3_bind_blob(statement, sqIndex, value.arrayBufferValue.get(),
28-
value.arrayBufferSize, SQLITE_STATIC);
27+
sqlite3_bind_blob(statement, sqIndex, value.arrayBuffer.data(),
28+
value.arrayBuffer.size(), SQLITE_STATIC);
2929
}
3030
}
3131
}
@@ -114,9 +114,7 @@ sqliteExecuteWithDB(sqlite3 *db, std::string const &query,
114114
case SQLITE_BLOB: {
115115
int blob_size = sqlite3_column_bytes(statement, i);
116116
const void *blob = sqlite3_column_blob(statement, i);
117-
uint8_t *data;
118-
memcpy(data, blob, blob_size);
119-
row[column_name] = createArrayBufferQuickValue(data, blob_size);
117+
row[column_name] = createArrayBufferQuickValueByCopying(static_cast<const uint8_t*>(blob), blob_size);
120118
break;
121119
}
122120

‎tests/tests/sqlite/rawQueries.spec.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,21 @@ export function registerBaseTests() {
133133
]);
134134
});
135135

136+
it('binding blobs', async () => {
137+
const data = new TextEncoder().encode('hello blob');
138+
const res = await db.execute('SELECT hex(?) AS r', [data.buffer]);
139+
140+
expect(res.rows?._array).to.eql([{ r: '68656C6C6F20626C6F62' }]);
141+
});
142+
143+
it('reading blobs', async () => {
144+
const res = await db.execute('SELECT unhex(1234) AS r');
145+
const value = res.rows._array[0].r;
146+
147+
expect(value).to.be.instanceOf(ArrayBuffer);
148+
expect([...new Uint8Array(value)]).to.eql([18, 52]);
149+
});
150+
136151
it('Failed insert', async () => {
137152
const id = chance.string(); // Setting the id to a string will throw an exception, it expects an int
138153
const { name, age, networth } = generateUserInfo();

0 commit comments

Comments
 (0)
Please sign in to comment.