My favorites | Sign in
Project Home Downloads Wiki Issues Source
Repository:
Checkout   Browse   Changes   Clones  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162

#include "pyodbc.h"
#include "sqlwchar.h"
#include "wrapper.h"


static bool sqlwchar_copy(SQLWCHAR* pdest, const Py_UNICODE* psrc, Py_ssize_t len)
{
for (int i = 0; i <= len; i++) // ('<=' to include the NULL)
{
pdest[i] = (SQLWCHAR)psrc[i];
if ((Py_UNICODE)pdest[i] < psrc[i])
{
PyErr_Format(PyExc_ValueError, "Cannot convert from Unicode %zd to SQLWCHAR. Value is too large.", (Py_ssize_t)psrc[i]);
return false;
}
}
return true;
}

SQLWChar::SQLWChar(PyObject* o)
{
// Converts from a Python Unicode string.

pch = 0;
len = 0;
owns_memory = false;

Convert(o);
}

void SQLWChar::Free()
{
if (pch && owns_memory)
pyodbc_free(pch);
pch = 0;
len = 0;
owns_memory = false;
}

bool SQLWChar::Convert(PyObject* o)
{
Free();

if (!PyUnicode_Check(o))
{
PyErr_SetString(PyExc_TypeError, "Unicode required");
return false;
}

Py_UNICODE* pU = (Py_UNICODE*)PyUnicode_AS_UNICODE(o);
Py_ssize_t lenT = PyUnicode_GET_SIZE(o);

#if SQLWCHAR_SIZE == Py_UNICODE_SIZE
// The ideal case - SQLWCHAR and Py_UNICODE are the same, so we point into the Unicode object.

pch = (SQLWCHAR*)pU;
len = lenT;
owns_memory = false;
return true;
#else
SQLWCHAR* pchT = (SQLWCHAR*)pyodbc_malloc(sizeof(SQLWCHAR) * (lenT + 1));
if (pchT == 0)
{
PyErr_NoMemory();
return false;
}

if (!sqlwchar_copy(pchT, pU, lenT))
{
pyodbc_free(pchT);
return false;
}

pch = pchT;
len = lenT;
owns_memory = true;
return true;
#endif
}


PyObject* PyUnicode_FromSQLWCHAR(const SQLWCHAR* sz, Py_ssize_t cch)
{
#if SQLWCHAR_SIZE == Py_UNICODE_SIZE

return PyUnicode_FromUnicode((const Py_UNICODE*)sz, cch);

#elif HAVE_WCHAR_H && (WCHAR_T_SIZE == SQLWCHAR_SIZE)

// Python provides a function to map from wchar_t to Unicode. Since wchar_t and SQLWCHAR are the same size, we can
// use it.
return PyUnicode_FromWideChar((const wchar_t*)sz, cch);

#else

Object result(PyUnicode_FromUnicode(0, cch));
if (!result)
return 0;

Py_UNICODE* pch = PyUnicode_AS_UNICODE(result.Get());
for (Py_ssize_t i = 0; i < cch; i++)
{
pch[i] = (Py_UNICODE)sz[i];
if ((SQLWCHAR)pch[i] != sz[i])
{
PyErr_Format(PyExc_ValueError, "Cannot convert from SQLWCHAR %zd to Unicode. Value is too large.", (Py_ssize_t)pch[i]);
return 0;
}
}

return result.Detach();

#endif
}

void SQLWChar::dump()
{
printf("sqlwchar=%ld pch=%p len=%ld owns=%d\n", sizeof(SQLWCHAR), pch, len, (int)owns_memory);
if (pch && len)
{
Py_ssize_t i = 0;
while (i < len)
{
Py_ssize_t stop = min(i + 10, len);

for (Py_ssize_t x = i; x < stop; x++)
{
for (int byteindex = (int)sizeof(SQLWCHAR)-1; byteindex >= 0; byteindex--)
{
int byte = (pch[x] >> (byteindex * 8)) & 0xFF;
printf("%02x", byte);
}
printf(" ");
}

for (Py_ssize_t x = i; x < stop; x++)
printf("%c", (char)pch[x]);

printf("\n");

i += 10;
}

printf("\n\n");
}
}


SQLWCHAR* SQLWCHAR_FromUnicode(const Py_UNICODE* pch, Py_ssize_t len)
{
SQLWCHAR* p = (SQLWCHAR*)pyodbc_malloc(sizeof(SQLWCHAR) * (len + 1));
if (p != 0)
{
if (!sqlwchar_copy(p, pch, len))
{
pyodbc_free(p);
p = 0;
}
}
return p;
}

Change log

8fa1cc4af672 by Michael Kleehammer <michael....@fiserv.com> on Oct 27, 2011   Diff
 Issue 170 : Fixed memory overwrite when
converting Unicode to SQLWCHAR.

Many thanks to davidp.r...@gmail.com for
finding this.
Go to: 
Sign in to write a code review

Older revisions

9dd144f9b648 by Michael Kleehammer <mich...@kleehammer.com> on Nov 23, 2010   Diff
Added pyodbc.conf for preprocessor-
time access to sizeof(SQLWCHAR)
523aed0ec8ad by Michael Kleehammer <mich...@kleehammer.com> on Sep 4, 2010   Diff
 Issue 91 : decimal fix; Completely
reworked parameters; added leakcheck

Fixed  issue 91  - handling of decimals
was incorrect (off by 1).  Added lots
...
83bd0ff5878a by Michael Kleehammer <mich...@kleehammer.com> on Sep 4, 2010   Diff
Eliminated 64-bit Windows warnings.
All revisions of this file

File info

Size: 3856 bytes, 162 lines
Powered by Google Project Hosting