Skip to content

Commit b53922e

Browse files
authored
Merge pull request #3 from fr00b0/master
Improved memory management in SQLite3Buffer
2 parents 3dcf4b6 + f147f5a commit b53922e

File tree

2 files changed

+162
-39
lines changed

2 files changed

+162
-39
lines changed

CppSQLite3.cpp

Lines changed: 115 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,16 @@
77

88
#include "CppSQLite3.h"
99
#include <cstdlib>
10+
#include <utility>
1011

1112

1213
// Named constant for passing to CppSQLite3Exception when passing it a string
1314
// that cannot be deleted.
1415
static const bool DONT_DELETE_MSG=false;
1516

17+
// Error message used when throwing CppSQLite3Exception when allocations fail.
18+
static const char* const ALLOCATION_ERROR_MESSAGE = "Cannot allocate memory";
19+
1620
////////////////////////////////////////////////////////////////////////////////
1721
// Prototypes for SQLite functions not included in SQLite DLL, but copied below
1822
// from SQLite encode.c
@@ -22,6 +26,94 @@ int sqlite3_decode_binary(const unsigned char *in, unsigned char *out);
2226

2327
////////////////////////////////////////////////////////////////////////////////
2428

29+
namespace detail
30+
{
31+
32+
SQLite3Memory::SQLite3Memory() :
33+
mnBufferLen(0),
34+
mpBuf(nullptr)
35+
{
36+
}
37+
38+
SQLite3Memory::SQLite3Memory(int nBufferLen) :
39+
mnBufferLen(nBufferLen),
40+
mpBuf(sqlite3_malloc(nBufferLen))
41+
{
42+
if (!mpBuf && mnBufferLen>0)
43+
{
44+
throw CppSQLite3Exception(CPPSQLITE_ERROR,
45+
ALLOCATION_ERROR_MESSAGE,
46+
DONT_DELETE_MSG);
47+
}
48+
}
49+
50+
SQLite3Memory::SQLite3Memory(const char* szFormat, va_list list) :
51+
mnBufferLen(0),
52+
mpBuf(sqlite3_vmprintf(szFormat, list))
53+
{
54+
if (!mpBuf)
55+
{
56+
throw CppSQLite3Exception(CPPSQLITE_ERROR,
57+
ALLOCATION_ERROR_MESSAGE,
58+
DONT_DELETE_MSG);
59+
}
60+
mnBufferLen = std::strlen(static_cast<char const*>(mpBuf))+1;
61+
}
62+
63+
SQLite3Memory::~SQLite3Memory()
64+
{
65+
clear();
66+
}
67+
68+
SQLite3Memory::SQLite3Memory(SQLite3Memory const& other) :
69+
mnBufferLen(other.mnBufferLen),
70+
mpBuf(sqlite3_malloc(other.mnBufferLen))
71+
{
72+
if (!mpBuf && mnBufferLen>0)
73+
{
74+
throw CppSQLite3Exception(CPPSQLITE_ERROR,
75+
ALLOCATION_ERROR_MESSAGE,
76+
DONT_DELETE_MSG);
77+
}
78+
std::memcpy(mpBuf, other.mpBuf, mnBufferLen);
79+
}
80+
81+
SQLite3Memory& SQLite3Memory::operator=(SQLite3Memory const& lhs)
82+
{
83+
SQLite3Memory tmp(lhs);
84+
swap(tmp);
85+
return *this;
86+
}
87+
88+
SQLite3Memory::SQLite3Memory(SQLite3Memory&& other) :
89+
mnBufferLen(other.mnBufferLen),
90+
mpBuf(other.mpBuf)
91+
{
92+
other.mnBufferLen = 0;
93+
other.mpBuf = nullptr;
94+
}
95+
96+
SQLite3Memory& SQLite3Memory::operator=(SQLite3Memory&& lhs)
97+
{
98+
swap(lhs);
99+
return *this;
100+
}
101+
102+
void SQLite3Memory::swap(SQLite3Memory& other)
103+
{
104+
std::swap(mnBufferLen, other.mnBufferLen);
105+
std::swap(mpBuf, other.mpBuf);
106+
}
107+
108+
void SQLite3Memory::clear()
109+
{
110+
sqlite3_free(mpBuf);
111+
mpBuf = nullptr;
112+
mnBufferLen = 0;
113+
}
114+
115+
}
116+
25117
////////////////////////////////////////////////////////////////////////////////
26118

27119
CppSQLite3Exception::CppSQLite3Exception(const int nErrCode,
@@ -40,7 +132,7 @@ CppSQLite3Exception::CppSQLite3Exception(const int nErrCode,
40132
}
41133
}
42134

43-
135+
44136
CppSQLite3Exception::CppSQLite3Exception(const CppSQLite3Exception& e) :
45137
mnErrCode(e.mnErrCode)
46138
{
@@ -102,37 +194,28 @@ CppSQLite3Exception::~CppSQLite3Exception()
102194

103195
////////////////////////////////////////////////////////////////////////////////
104196

105-
CppSQLite3Buffer::CppSQLite3Buffer()
106-
{
107-
mpBuf = 0;
108-
}
109-
110-
111-
CppSQLite3Buffer::~CppSQLite3Buffer()
112-
{
113-
clear();
114-
}
115-
116-
117197
void CppSQLite3Buffer::clear()
118198
{
119-
if (mpBuf)
120-
{
121-
sqlite3_free(mpBuf);
122-
mpBuf = 0;
123-
}
124-
199+
mBuf.clear();
125200
}
126201

127202

128203
const char* CppSQLite3Buffer::format(const char* szFormat, ...)
129204
{
130205
clear();
131206
va_list va;
132-
va_start(va, szFormat);
133-
mpBuf = sqlite3_vmprintf(szFormat, va);
134-
va_end(va);
135-
return mpBuf;
207+
try
208+
{
209+
va_start(va, szFormat);
210+
mBuf = detail::SQLite3Memory(szFormat, va);
211+
va_end(va);
212+
return static_cast<const char*>(mBuf.getBuffer());
213+
}
214+
catch(CppSQLite3Exception&)
215+
{
216+
va_end(va);
217+
throw;
218+
}
136219
}
137220

138221

@@ -173,7 +256,7 @@ void CppSQLite3Binary::setEncoded(const unsigned char* pBuf)
173256
if (!mpBuf)
174257
{
175258
throw CppSQLite3Exception(CPPSQLITE_ERROR,
176-
"Cannot allocate memory",
259+
ALLOCATION_ERROR_MESSAGE,
177260
DONT_DELETE_MSG);
178261
}
179262

@@ -240,7 +323,7 @@ unsigned char* CppSQLite3Binary::allocBuffer(int nLen)
240323
if (!mpBuf)
241324
{
242325
throw CppSQLite3Exception(CPPSQLITE_ERROR,
243-
"Cannot allocate memory",
326+
ALLOCATION_ERROR_MESSAGE,
244327
DONT_DELETE_MSG);
245328
}
246329

@@ -995,7 +1078,7 @@ void CppSQLite3Statement::bind(int nParam, const long long nValue)
9951078
{
9961079
checkVM();
9971080
int nRes = sqlite3_bind_int64(mpVM, nParam, nValue);
998-
1081+
9991082
if (nRes != SQLITE_OK)
10001083
{
10011084
throw CppSQLite3Exception(nRes,
@@ -1033,7 +1116,7 @@ void CppSQLite3Statement::bind(int nParam, const unsigned char* blobValue, int n
10331116
}
10341117
}
10351118

1036-
1119+
10371120
void CppSQLite3Statement::bindNull(int nParam)
10381121
{
10391122
checkVM();
@@ -1303,7 +1386,7 @@ sqlite3_stmt* CppSQLite3DB::compile(const char* szSQL)
13031386

13041387
////////////////////////////////////////////////////////////////////////////////
13051388
// SQLite encode.c reproduced here, containing implementation notes and source
1306-
// for sqlite3_encode_binary() and sqlite3_decode_binary()
1389+
// for sqlite3_encode_binary() and sqlite3_decode_binary()
13071390
////////////////////////////////////////////////////////////////////////////////
13081391

13091392
/*
@@ -1350,7 +1433,7 @@ sqlite3_stmt* CppSQLite3DB::compile(const char* szSQL)
13501433
** We would prefer to keep the size of the encoded string smaller than
13511434
** this.
13521435
**
1353-
** To minimize the encoding size, we first add a fixed offset value to each
1436+
** To minimize the encoding size, we first add a fixed offset value to each
13541437
** byte in the sequence. The addition is modulo 256. (That is to say, if
13551438
** the sum of the original character value and the offset exceeds 256, then
13561439
** the higher order bits are truncated.) The offset is chosen to minimize
@@ -1359,7 +1442,7 @@ sqlite3_stmt* CppSQLite3DB::compile(const char* szSQL)
13591442
** characters, the offset might be 0x01. Each of the 0x27 characters would
13601443
** then be converted into an 0x28 character which would not need to be
13611444
** escaped at all and so the 100 character input string would be converted
1362-
** into just 100 characters of output. Actually 101 characters of output -
1445+
** into just 100 characters of output. Actually 101 characters of output -
13631446
** we have to record the offset used as the first byte in the sequence so
13641447
** that the string can be decoded. Since the offset value is stored as
13651448
** part of the output string and the output string is not allowed to contain
@@ -1382,7 +1465,7 @@ sqlite3_stmt* CppSQLite3DB::compile(const char* szSQL)
13821465
**
13831466
** Decoding is obvious:
13841467
**
1385-
** (5) Copy encoded characters except the first into the decode
1468+
** (5) Copy encoded characters except the first into the decode
13861469
** buffer. Set the first encoded character aside for use as
13871470
** the offset in step 7 below.
13881471
**
@@ -1408,7 +1491,7 @@ sqlite3_stmt* CppSQLite3DB::compile(const char* szSQL)
14081491

14091492
/*
14101493
** Encode a binary buffer "in" of size n bytes so that it contains
1411-
** no instances of characters '\'' or '\000'. The output is
1494+
** no instances of characters '\'' or '\000'. The output is
14121495
** null-terminated and can be used as a string value in an INSERT
14131496
** or UPDATE statement. Use sqlite3_decode_binary() to convert the
14141497
** string back into its original binary.

CppSQLite3.h

Lines changed: 47 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,51 @@
1414

1515
#define CPPSQLITE_ERROR 1000
1616

17+
namespace detail
18+
{
19+
/**
20+
* RAII class for managing memory allocated by sqlite
21+
*/
22+
class SQLite3Memory
23+
{
24+
public:
25+
26+
// Default constructor
27+
SQLite3Memory();
28+
// Constructor that allocates memory of a given size
29+
SQLite3Memory(int nBufferLen);
30+
// Constructor that formats a string with sqlite memory allocation
31+
SQLite3Memory(const char* szFormat, va_list list);
32+
// Destructor
33+
~SQLite3Memory();
34+
35+
// Copy constructor
36+
SQLite3Memory(SQLite3Memory const& other);
37+
// Copy assignment
38+
SQLite3Memory& operator=(SQLite3Memory const& lhs);
39+
40+
// Move constructor
41+
SQLite3Memory(SQLite3Memory&& other);
42+
// Move assignment
43+
SQLite3Memory& operator=(SQLite3Memory&& lhs);
44+
45+
// Swap operation
46+
void swap(SQLite3Memory& other);
47+
48+
int getLength() const { return mnBufferLen; }
49+
50+
void* getBuffer() const { return mpBuf; }
51+
52+
void clear();
53+
54+
private:
55+
56+
int mnBufferLen;
57+
void* mpBuf;
58+
};
59+
}
60+
61+
1762
class CppSQLite3Exception
1863
{
1964
public:
@@ -42,20 +87,15 @@ class CppSQLite3Exception
4287
class CppSQLite3Buffer
4388
{
4489
public:
45-
46-
CppSQLite3Buffer();
47-
48-
~CppSQLite3Buffer();
49-
5090
const char* format(const char* szFormat, ...);
5191

52-
operator const char*() const { return mpBuf; }
92+
operator const char*() { return static_cast<char const*>(mBuf.getBuffer()); }
5393

5494
void clear();
5595

5696
private:
5797

58-
char* mpBuf;
98+
detail::SQLite3Memory mBuf;
5999
};
60100

61101

0 commit comments

Comments
 (0)