Strange bug (value on stack changed)?

From: Lothar Behrens <lothar(dot)behrens(at)lollisoft(dot)de>
To: pgsql-odbc(at)postgresql(dot)org
Subject: Strange bug (value on stack changed)?
Date: 2009-08-01 17:36:35
Message-ID: 6A39BDD5-B246-496D-ACD0-181692CC3A82@lollisoft.de
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-odbc

Hi,

I am using the ANSI ODBC driver (version 8.03.04.00, psqlodbc30a.dll)
on Windows XP and found a stack corruption.

My code uses the SQLSetPos to add a row and while this the bug occurs.
My bound columns are all malloc'ed on heap.
Now I am likely would find the reason for this, but have some problems:

My code is compiled with Open Watcom 1.7 and the bug only appears if I
compile with debug information
about the line numbers (-d1) or in release mode. The trouble is how to
debug MSVC driver (DLL) while debugging Watcom client code.

While trying more and more to get useful information for you I found
some interesting information:

The address on the stack that gets overwritten is at 0x0006ED18 and
this address is in the following log at PGAPI_SetStmtAttr.
The stack pointer ESP is about 39 dwords above the address that gets
shoot (smaller addresses are above). At this level I do a check
before calling SQLSetPos and after the call. After the call the stack
at ESP + (39*4 bytes) is shoot.

I have determined that I have a column binding problem with the
SQL_COLUMN_IGNORE flag in the last parameter of SQLBindCol that may
cause
this bug.

So basically I have two rows for each column. One for reading data to
be displayed in my GUI and another to be used to add new rows. This
corresponds
to my mode with is 0 = update and 1 = add.

if (mode == 1) {
retcode = SQLSetPos(hstmt, 2, SQL_ADD, SQL_LOCK_NO_CHANGE);
} else {
retcode = SQLSetPos(hstmt, 1, SQL_UPDATE, SQL_LOCK_NO_CHANGE);
}

It seems that I do not proper unbind the serial column:

ret = SQLBindCol(hstmt, _column, SQL_C_CHAR, NULL, (ColumnSize+1),
cbBufferLength);

While I think the value in add mode (cbBufferLength[1] is not
SQL_COLUMN_IGNORE) and the update mode (cbBufferLength[0]) is unrelated.

Is this correct?

Another question is: Do I have to use a cbBufferLength array or is one
long value enough regardless of having two working rows (update/add)?

But regardless, the shoot should not happen in either circumstance.

After my last test to correct my code at the proper place I do not get
it working in case of automatic binding - eg. bound column that is not
ignored.

At this stage I think, I cannot unbind columns to be ignored for the
next add command. I have to bind it correctly at the first time with
SQL_COLUMN_IGNORE
or it will fail with the shoot. Binding it to the buffer with
SQL_COLUMN_IGNORE also shoots my char array on stack.

I think, there is a bug in rebinding columns that causes a write to
value on stack of the caller of SQLSetPos or simply a crash without my
buffers to work around
for finding the bug. Do you agree?

void LB_STDCALL lbBoundColumn::unbindReadonlyColumns() {
SQLRETURN ret = SQL_SUCCESS;

if (isReadonly) {
if (mode == 1) {
cbBufferLength[1] = SQL_COLUMN_IGNORE; // Assumed having
to be set correctly
cbBufferLength[0] = SQL_COLUMN_IGNORE; // But this also
doesn't work
}
else
cbBufferLength[0] = SQL_COLUMN_IGNORE;

/*...sUnbind:16:*/
switch (_DataType) {
case SQL_DATE:
case SQL_TYPE_DATE:
_CL_VERBOSE << "Unbind date" LOG_
bound = 0;

ret = SQLBindCol(hstmt, _column, SQL_C_CHAR, NULL, (ColumnSize+1),
cbBufferLength);
break;
case SQL_FLOAT:
case SQL_CHAR:
case SQL_VARCHAR:
case SQL_LONGVARCHAR:
#ifndef BIND_BOOL_DEFAULT
case SQL_BIT:
case SQL_TINYINT:
#endif
_CL_VERBOSE << "Unbind char" LOG_
bound = 0;

ret = SQLBindCol(hstmt, _column, SQL_C_CHAR, NULL, (ColumnSize+1),
cbBufferLength);
break;
case SQL_BINARY:
_CL_VERBOSE << "Unbind binary" LOG_
bound = 0;

ret = SQLBindCol(hstmt, _column, SQL_C_DEFAULT, NULL, (ColumnSize
+1), cbBufferLength);
break;
case SQL_INTEGER:
_CL_LOG << "Unbind integer " << columnName LOG_
bound = 0;

SQLBindCol(hstmt, _column, SQL_C_DEFAULT, NULL, sizeof(long),
cbBufferLength);
break;
case SQL_BIGINT:
_CL_VERBOSE << "Unbind big integer" LOG_
bound = 0;
#ifndef _MSC_VER
SQLBindCol(hstmt, _column, SQL_C_DEFAULT, NULL, sizeof(long long),
cbBufferLength);
#endif
#ifdef _MSC_VER
SQLBindCol(hstmt, _column, SQL_C_DEFAULT, NULL, sizeof(__int64),
cbBufferLength);
#endif
break;
#ifdef BIND_BOOL_DEFAULT
case SQL_BIT:
case SQL_TINYINT:
_CL_VERBOSE << "Unbind bit" LOG_
bound = 0;
#ifdef OSX
SQLBindCol(hstmt, _column, SQL_BIT, NULL, sizeof(long),
cbBufferLength);
#endif
#ifndef OSX
SQLBindCol(hstmt, _column, SQL_BIT, NULL, sizeof(bool),
cbBufferLength);
#endif
if (ret != SQL_SUCCESS) {
printf("Error while unbinding a column!\n");
query->dbError("SQLBindCol()", hstmt);
}
break;
#endif
case SQL_LONGVARBINARY:
bound = 0;
break;
default:
_CL_LOG << "lbBoundColumn::unbindReadonlyColumns(...) failed:
Unknown or not supported datatype for column '" << columnName << "': "
<< _DataType LOG_
break;
}
/*...e*/
}

if (ret != SQL_SUCCESS) {
printf("Error while unbinding a column!\n");
query->dbError("SQLBindCol()", hstmt);
}
}

Before I create a plain ODBC sample code to reproduce this, please
have a look at the log snippets.

Thanks

Lothar

The mylog snippets (failure / working) are as follows

Failure

[1072-0.641] stmt_with_params = 'select id, bezeichnung,
action_handler, module , "ctid", "oid" from action_types where ctid =
'(0,0)';select "ctid", "oid" from action_types where module =
'lbDMFXslt' and action_handler = 'instanceOflbDMFXslt''
[1072-0.641]about to begin SC_execute
[1072-0.641] Sending SELECT statement on stmt=03D12340,
cursor_name='SQL_CUR03D12340' qflag=2,3
[1072-0.641]CC_send_query: conn=03D14FD8, query='select id,
bezeichnung, action_handler, module , "ctid", "oid" from action_types
where ctid = '(0,0)';select "ctid", "oid" from action_types where
module = 'lbDMFXslt' and action_handler = 'instanceOflbDMFXslt''
[1072-0.641]send_query: done sending query 212bytes flushed
[1072-0.641]in QR_Constructor
[1072-0.641]exit QR_Constructor
[1072-0.641]read -1, global_socket_buffersize=4096
[1072-0.641]Lasterror=10035
[1072-0.641]read 172, global_socket_buffersize=4096
[1072-0.641]send_query: got id = 'P'
[1072-0.641]send_query: got id = 'T'
[1072-0.656]QR_fetch_tuples: cursor = '', self->cursor=00000000
[1072-0.656]num_fields = 6
[1072-0.656]READING ATTTYPMOD
[1072-0.656]CI_read_fields: fieldname='id', adtid=23, adtsize=4,
atttypmod=-1 (rel,att)=(0,0)
[1072-0.656]READING ATTTYPMOD
[1072-0.656]CI_read_fields: fieldname='bezeichnung', adtid=1042,
adtsize=-1, atttypmod=255 (rel,att)=(0,0)
[1072-0.656]READING ATTTYPMOD
[1072-0.656]CI_read_fields: fieldname='action_handler', adtid=1042,
adtsize=-1, atttypmod=255 (rel,att)=(0,0)
[1072-0.656]READING ATTTYPMOD
[1072-0.656]CI_read_fields: fieldname='module', adtid=1042,
adtsize=-1, atttypmod=255 (rel,att)=(0,0)
[1072-0.656]READING ATTTYPMOD
[1072-0.656]CI_read_fields: fieldname='ctid', adtid=27, adtsize=6,
atttypmod=-1 (rel,att)=(0,0)
[1072-0.656]READING ATTTYPMOD
[1072-0.656]CI_read_fields: fieldname='oid', adtid=26, adtsize=4,
atttypmod=-1 (rel,att)=(0,0)
[1072-0.656]QR_fetch_tuples: past CI_read_fields: num_fields = 4
[1072-0.656]MALLOC: tuple_size = 100, size = 3200
[1072-0.656]QR_next_tuple: inTuples = true, falling through: fcount =
0, fetch_number = 0
[1072-0.656]end of tuple list -- setting inUse to false: this =
04B53318 SELECT
[1072-0.656]_QR_next_tuple: 'C' fetch_total = 0 & this_fetch = 0
[1072-0.656]QR_next_tuple: backend_rows < CACHE_SIZE: brows = 0,
cache_size = 0
[1072-0.656]QR_next_tuple: reached eof now
[1072-0.656]_QR_next_tuple: 'C': DONE (fcount == 0)
[1072-0.656]send_query: got id = 'P'
[1072-0.656]send_query: got id = 'T'
[1072-0.656]in QR_Constructor
[1072-0.656]exit QR_Constructor
[1072-0.656]send_query: 'T' no result_in: res = 04B58DE0
[1072-0.656]QR_fetch_tuples: cursor = '', self->cursor=00000000
[1072-0.656]num_fields = 2
[1072-0.656]READING ATTTYPMOD
[1072-0.656]CI_read_fields: fieldname='ctid', adtid=27, adtsize=6,
atttypmod=-1 (rel,att)=(0,0)
[1072-0.656]READING ATTTYPMOD
[1072-0.656]CI_read_fields: fieldname='oid', adtid=26, adtsize=4,
atttypmod=-1 (rel,att)=(0,0)
[1072-0.656]QR_fetch_tuples: past CI_read_fields: num_fields = 0
[1072-0.672]MALLOC: tuple_size = 100, size = 0
[1072-0.672]QR_next_tuple: inTuples = true, falling through: fcount =
0, fetch_number = 0
[1072-0.672]end of tuple list -- setting inUse to false: this =
04B58DE0 SELECT
[1072-0.672]_QR_next_tuple: 'C' fetch_total = 0 & this_fetch = 0
[1072-0.672]QR_next_tuple: backend_rows < CACHE_SIZE: brows = 0,
cache_size = 0
[1072-0.672]QR_next_tuple: reached eof now
[1072-0.672]_QR_next_tuple: 'C': DONE (fcount == 0)
[1072-0.672]send_query: got id = 'Z'
[1072-0.672] done sending the query:
[1072-0.672]extend_column_bindings: entering ... self=03D123C8,
bindings_allocated=0, num_columns=6
[1072-0.672]exit extend_column_bindings=03D1AB70
[1072-0.672]QResult: enter DESTRUCTOR
[1072-0.672]QResult: in QR_close_result
[1072-0.672]QResult: free memory in, fcount=0
[1072-0.672]QResult: free memory out
[1072-0.672]QResult: enter DESTRUCTOR
[1072-0.672]QResult: exit close_result
[1072-0.672]QResult: exit DESTRUCTOR
[1072-0.672]SC_init_Result(3d12340)[1072-0.672]SC_set_Result(3d12340,
4b58de0)[1072-0.672]QResult: enter DESTRUCTOR
[1072-0.672]retval=0
[1072-0.672]PGAPI_ExecDirect: returned 0 from PGAPI_Execute
[1072-0.672][SQLGetCursorName][1072-0.672]PGAPI_GetCursorName:
hstmt=03D12340, szCursor=02393F50, cbCursorMax=200, pcbCursor=0006ED88
[1072-0.672][SQLNumResultCols][1072-0.672]PGAPI_NumResultCols:
entering...
[1072-0.672]SC_pre_execute: status = 3
[1072-0.672]PGAPI_NumResultCols: result = 04B58DE0, status = 3,
numcols = 6
[1072-0.672][[SQLSetStmtAttr]] Handle=03D12340 27,1
[1072-0.672]PGAPI_SetStmtAttr Handle=03D12340 27,1(00000001)
[1072-0.672][[SQLSetStmtAttr]] Handle=03D12340 5,0
[1072-0.672]PGAPI_SetStmtAttr Handle=03D12340 5,0(00000000)
[1072-0.672]PGAPI_SetStmtOption: entering...
[1072-0.672][[SQLSetStmtAttr]] Handle=03D12340 25,453912
[1072-0.672]PGAPI_SetStmtAttr Handle=03D12340 25,453912(0006ED18)

Working:

[1632-50.797] stmt_with_params = 'select id, bezeichnung,
action_handler, module , "ctid", "oid" from action_types where ctid =
'(0,0)';select "ctid", "oid" from action_types'
[1632-50.797]about to begin SC_execute
[1632-50.797] Sending SELECT statement on stmt=05F02AD8,
cursor_name='SQL_CUR05F02AD8' qflag=2,3
[1632-50.797]CC_send_query: conn=03D04248, query='select id,
bezeichnung, action_handler, module , "ctid", "oid" from action_types
where ctid = '(0,0)';select "ctid", "oid" from action_types'
[1632-50.797]send_query: done sending query 142bytes flushed
[1632-50.797]in QR_Constructor
[1632-50.797]exit QR_Constructor
[1632-50.797]read -1, global_socket_buffersize=4096
[1632-50.797]Lasterror=10035
[1632-50.797]read 457, global_socket_buffersize=4096
[1632-50.812]send_query: got id = 'P'
[1632-50.812]send_query: got id = 'T'
[1632-50.812]QR_fetch_tuples: cursor = '', self->cursor=00000000
[1632-50.812]num_fields = 6
[1632-50.812]READING ATTTYPMOD
[1632-50.812]CI_read_fields: fieldname='id', adtid=23, adtsize=4,
atttypmod=-1 (rel,att)=(0,0)
[1632-50.812]READING ATTTYPMOD
[1632-50.812]CI_read_fields: fieldname='bezeichnung', adtid=1042,
adtsize=-1, atttypmod=255 (rel,att)=(0,0)
[1632-50.812]READING ATTTYPMOD
[1632-50.812]CI_read_fields: fieldname='action_handler', adtid=1042,
adtsize=-1, atttypmod=255 (rel,att)=(0,0)
[1632-50.812]READING ATTTYPMOD
[1632-50.812]CI_read_fields: fieldname='module', adtid=1042,
adtsize=-1, atttypmod=255 (rel,att)=(0,0)
[1632-50.812]READING ATTTYPMOD
[1632-50.812]CI_read_fields: fieldname='ctid', adtid=27, adtsize=6,
atttypmod=-1 (rel,att)=(0,0)
[1632-50.812]READING ATTTYPMOD
[1632-50.812]CI_read_fields: fieldname='oid', adtid=26, adtsize=4,
atttypmod=-1 (rel,att)=(0,0)
[1632-50.812]QR_fetch_tuples: past CI_read_fields: num_fields = 4
[1632-50.812]MALLOC: tuple_size = 100, size = 3200
[1632-50.812]QR_next_tuple: inTuples = true, falling through: fcount =
0, fetch_number = 0
[1632-50.812]end of tuple list -- setting inUse to false: this =
04B31C88 SELECT
[1632-50.812]_QR_next_tuple: 'C' fetch_total = 0 & this_fetch = 0
[1632-50.812]QR_next_tuple: backend_rows < CACHE_SIZE: brows = 0,
cache_size = 0
[1632-50.812]QR_next_tuple: reached eof now
[1632-50.812]_QR_next_tuple: 'C': DONE (fcount == 0)
[1632-50.812]send_query: got id = 'P'
[1632-50.812]send_query: got id = 'T'
[1632-50.812]in QR_Constructor
[1632-50.812]exit QR_Constructor
[1632-50.812]send_query: 'T' no result_in: res = 05F08E40
[1632-50.812]QR_fetch_tuples: cursor = '', self->cursor=00000000
[1632-50.828]num_fields = 2
[1632-50.828]READING ATTTYPMOD
[1632-50.828]CI_read_fields: fieldname='ctid', adtid=27, adtsize=6,
atttypmod=-1 (rel,att)=(0,0)
[1632-50.828]READING ATTTYPMOD
[1632-50.828]CI_read_fields: fieldname='oid', adtid=26, adtsize=4,
atttypmod=-1 (rel,att)=(0,0)
[1632-50.828]QR_fetch_tuples: past CI_read_fields: num_fields = 0
[1632-50.828]MALLOC: tuple_size = 100, size = 0
[1632-50.828]QR_next_tuple: inTuples = true, falling through: fcount =
0, fetch_number = 0
[1632-50.828]qresult: len=6, buffer='(0,11)'
[1632-50.828]qresult: len=6, buffer='194598'
[1632-50.828]qresult: len=6, buffer='(0,12)'
[1632-50.828]qresult: len=6, buffer='194592'
[1632-50.828]qresult: len=6, buffer='(0,13)'
[1632-50.828]qresult: len=6, buffer='194591'
[1632-50.828]qresult: len=6, buffer='(0,14)'
[1632-50.828]qresult: len=6, buffer='194597'
[1632-50.828]qresult: len=6, buffer='(0,15)'
[1632-50.828]qresult: len=6, buffer='194594'
[1632-50.828]qresult: len=6, buffer='(0,17)'
[1632-50.828]qresult: len=6, buffer='194593'
[1632-50.828]qresult: len=6, buffer='(0,18)'
[1632-50.828]qresult: len=6, buffer='194590'
[1632-50.828]qresult: len=6, buffer='(0,19)'
[1632-50.828]qresult: len=6, buffer='194596'
[1632-50.828]qresult: len=5, buffer='(1,7)'
[1632-50.828]qresult: len=6, buffer='194601'
[1632-50.828]qresult: len=6, buffer='(1,14)'
[1632-50.828]qresult: len=6, buffer='194600'
[1632-50.828]qresult: len=6, buffer='(2,10)'
[1632-50.828]qresult: len=6, buffer='194599'
[1632-50.828]qresult: len=6, buffer='(2,13)'
[1632-50.828]qresult: len=6, buffer='194589'
[1632-50.828]qresult: len=6, buffer='(2,25)'
[1632-50.828]qresult: len=6, buffer='195070'
[1632-50.828]end of tuple list -- setting inUse to false: this =
05F08E40 SELECT
[1632-50.828]_QR_next_tuple: 'C' fetch_total = 13 & this_fetch = 0
[1632-50.828]QR_next_tuple: backend_rows < CACHE_SIZE: brows = 0,
cache_size = 0
[1632-50.828]QR_next_tuple: reached eof now
[1632-50.828]_QR_next_tuple: 'C': DONE (fcount == 0)
[1632-50.828]send_query: got id = 'Z'
[1632-50.844] done sending the query:
[1632-50.844]extend_column_bindings: entering ... self=05F02B60,
bindings_allocated=0, num_columns=6
[1632-50.844]exit extend_column_bindings=05F08F10
[1632-50.844]QResult: enter DESTRUCTOR
[1632-50.844]QResult: in QR_close_result
[1632-50.844]QResult: free memory in, fcount=0
[1632-50.844]QResult: free memory out
[1632-50.844]QResult: enter DESTRUCTOR
[1632-50.844]QResult: exit close_result
[1632-50.844]QResult: exit DESTRUCTOR
[1632-50.844]SC_init_Result(5f02ad8)
[1632-50.844]SC_set_Result(5f02ad8, 5f08e40)[1632-50.844]QResult:
enter DESTRUCTOR
[1632-50.844]retval=0
[1632-50.844]PGAPI_ExecDirect: returned 0 from PGAPI_Execute
[1632-50.844][SQLGetCursorName][1632-50.844]PGAPI_GetCursorName:
hstmt=05F02AD8, szCursor=023939E0, cbCursorMax=200, pcbCursor=0006C524
[1632-50.844][SQLNumResultCols][1632-50.844]PGAPI_NumResultCols:
entering...
[1632-50.844]SC_pre_execute: status = 3
[1632-50.844]PGAPI_NumResultCols: result = 05F08E40, status = 3,
numcols = 6
[1632-50.844][[SQLSetStmtAttr]] Handle=05F02AD8 27,1
[1632-50.844]PGAPI_SetStmtAttr Handle=05F02AD8 27,1(00000001)
[1632-50.844][[SQLSetStmtAttr]] Handle=05F02AD8 5,0
[1632-50.844]PGAPI_SetStmtAttr Handle=05F02AD8 5,0(00000000)
[1632-50.844]PGAPI_SetStmtOption: entering...
[1632-50.844][[SQLSetStmtAttr]] Handle=05F02AD8 25,443572
[1632-50.844]PGAPI_SetStmtAttr Handle=05F02AD8 25,443572(0006C4B4)

-- | Rapid Prototyping | XSLT Codegeneration | http://www.lollisoft.de
Lothar Behrens
Heinrich-Scheufelen-Platz 2
73252 Lenningen

Browse pgsql-odbc by date

  From Date Subject
Next Message Mike McDonald 2009-08-04 22:18:52 SQLGetConnectAttr returns invalid value
Previous Message Relyea, Mike 2009-07-31 20:05:23 Re: Is there any known issue with MS-Office >2000 fetching Data?