GC.malloc problems with the DMD
Raphael Basso
arabasso at yahoo.com.br
Fri Sep 21 09:24:53 PDT 2012
Hello
I'm porting my connection library to Firebird database for the D
language, and I'm having problems with "Access Violation" using
DMD (did some testing and this problem does not occur with GDC).
This code is based on a simple C implementation, and it works ok
in VC++ and GCC):
[code]
import std.stdio;
import core.memory;
import std.conv;
alias uint ISC_STATUS;
const ISC_STATUS_LENGTH = 20;
alias ISC_STATUS ISC_STATUS_ARRAY[ISC_STATUS_LENGTH];
alias char ISC_SCHAR;
alias ubyte ISC_UCHAR;
alias int ISC_LONG;
alias uint ISC_ULONG;
alias short ISC_SHORT;
alias ushort ISC_USHORT;
struct ISC_QUAD
{
ISC_LONG gds_quad_high;
ISC_ULONG gds_quad_low;
}
struct XSQLVAR
{
ISC_SHORT sqltype;
ISC_SHORT sqlscale;
ISC_SHORT sqlsubtype;
ISC_SHORT sqllen;
ISC_SCHAR * sqldata;
ISC_SHORT * sqlind;
ISC_SHORT sqlname_length;
ISC_SCHAR sqlname[32];
ISC_SHORT relname_length;
ISC_SCHAR relname[32];
ISC_SHORT ownname_length;
ISC_SCHAR ownname[32];
ISC_SHORT aliasname_length;
ISC_SCHAR aliasname[32];
}
const SQLDA_VERSION1 = 1;
struct XSQLDA
{
ISC_SHORT ver;
ISC_SCHAR sqldaid[8];
ISC_LONG sqldabc;
ISC_SHORT sqln;
ISC_SHORT sqld;
XSQLVAR sqlvar[1];
}
const isc_dpb_version1 = 1;
const isc_dpb_user_name = 28;
const isc_dpb_password = 29;
const isc_dpb_address = 1;
const DSQL_close = 1;
const DSQL_drop = 2;
const DSQL_unprepare = 4;
alias void * FB_API_HANDLE;
alias FB_API_HANDLE isc_db_handle;
alias FB_API_HANDLE isc_blob_handle;
alias FB_API_HANDLE isc_stmt_handle;
alias FB_API_HANDLE isc_tr_handle;
const SQL_TEXT = 452;
const SQL_VARYING = 448;
const SQL_SHORT = 500;
const SQL_LONG = 496;
const SQL_FLOAT = 482;
const SQL_DOUBLE = 480;
const SQL_D_FLOAT = 530;
const SQL_TIMESTAMP = 510;
const SQL_BLOB = 520;
const SQL_ARRAY = 540;
const SQL_QUAD = 550;
const SQL_TYPE_TIME = 560;
const SQL_TYPE_DATE = 570;
const SQL_INT64 = 580;
const SQL_NULL = 32766;
const SQL_DATE = SQL_TIMESTAMP;
const SQL_DIALECT_V5 = 1;
const SQL_DIALECT_V6_TRANSITION = 2;
const SQL_DIALECT_V6 = 3;
const SQL_DIALECT_CURRENT = SQL_DIALECT_V6;
alias int ISC_DATE;
alias uint ISC_TIME;
struct ISC_TIMESTAMP
{
ISC_DATE timestamp_date;
ISC_TIME timestamp_time;
}
struct tm
{
int tm_sec;
int tm_min;
int tm_hour;
int tm_mday;
int tm_mon;
int tm_year;
int tm_wday;
int tm_yday;
int tm_isdst;
}
const isc_segstr_eof = 335544367L;
version(DigitalMars)
{
extern(C)
{
ISC_STATUS isc_attach_database(ISC_STATUS *, short, const
ISC_SCHAR *, isc_db_handle *, short, const ISC_SCHAR *);
ISC_STATUS isc_print_status(const ISC_STATUS *);
ISC_STATUS isc_detach_database(ISC_STATUS *, isc_db_handle *);
ISC_STATUS isc_start_transaction(ISC_STATUS *, isc_tr_handle *,
short, ...);
ISC_STATUS isc_commit_transaction(ISC_STATUS *, isc_tr_handle
*);
ISC_STATUS isc_rollback_transaction(ISC_STATUS *, isc_tr_handle
*);
ISC_STATUS isc_dsql_allocate_statement(ISC_STATUS *,
isc_db_handle *, isc_stmt_handle *);
ISC_STATUS isc_dsql_alloc_statement2(ISC_STATUS *,
isc_db_handle *, isc_stmt_handle *);
ISC_STATUS isc_dsql_describe(ISC_STATUS *, isc_stmt_handle *,
ushort, XSQLDA *);
ISC_STATUS isc_dsql_describe_bind(ISC_STATUS *, isc_stmt_handle
*, ushort, XSQLDA *);
ISC_STATUS isc_dsql_execute(ISC_STATUS *, isc_tr_handle *,
isc_stmt_handle *, ushort, const XSQLDA*);
ISC_STATUS isc_dsql_execute2(ISC_STATUS *, isc_tr_handle *,
isc_stmt_handle *, ushort, const XSQLDA *, const XSQLDA *);
ISC_STATUS isc_dsql_execute_immediate(ISC_STATUS *,
isc_db_handle *, isc_tr_handle *, ushort, const ISC_SCHAR *,
ushort, const XSQLDA *);
ISC_STATUS isc_dsql_fetch(ISC_STATUS *, isc_stmt_handle *,
ushort, const XSQLDA *);
ISC_STATUS isc_dsql_finish(isc_db_handle *);
ISC_STATUS isc_dsql_free_statement(ISC_STATUS *,
isc_stmt_handle *, ushort);
ISC_STATUS isc_dsql_prepare(ISC_STATUS *, isc_tr_handle *,
isc_stmt_handle *, ushort, const ISC_SCHAR *, ushort, XSQLDA *);
ISC_LONG fb_interpret(ISC_SCHAR *, uint, const ISC_STATUS **);
ISC_STATUS isc_open_blob(ISC_STATUS *, isc_db_handle *,
isc_tr_handle *, isc_blob_handle *, ISC_QUAD *);
ISC_STATUS isc_open_blob2(ISC_STATUS *, isc_db_handle *,
isc_tr_handle *, isc_blob_handle *, ISC_QUAD *, ISC_USHORT, const
ISC_UCHAR *);
ISC_STATUS isc_get_segment(ISC_STATUS *, isc_blob_handle *,
ushort *, ushort, ISC_SCHAR *);
ISC_STATUS isc_close_blob(ISC_STATUS *, isc_blob_handle *);
void isc_decode_sql_date(const ISC_DATE *, void *);
void isc_decode_sql_time(const ISC_TIME *, void *);
void isc_decode_timestamp(const ISC_TIMESTAMP *, void *);
}
}
else
{
extern(Windows)
{
ISC_STATUS isc_attach_database(ISC_STATUS *, short, const
ISC_SCHAR *, isc_db_handle *, short, const ISC_SCHAR *);
ISC_STATUS isc_print_status(const ISC_STATUS *);
ISC_STATUS isc_detach_database(ISC_STATUS *, isc_db_handle *);
ISC_STATUS isc_start_transaction(ISC_STATUS *, isc_tr_handle *,
short, ...);
ISC_STATUS isc_commit_transaction(ISC_STATUS *, isc_tr_handle
*);
ISC_STATUS isc_rollback_transaction(ISC_STATUS *, isc_tr_handle
*);
ISC_STATUS isc_dsql_allocate_statement(ISC_STATUS *,
isc_db_handle *, isc_stmt_handle *);
ISC_STATUS isc_dsql_alloc_statement2(ISC_STATUS *,
isc_db_handle *, isc_stmt_handle *);
ISC_STATUS isc_dsql_describe(ISC_STATUS *, isc_stmt_handle *,
ushort, XSQLDA *);
ISC_STATUS isc_dsql_describe_bind(ISC_STATUS *, isc_stmt_handle
*, ushort, XSQLDA *);
ISC_STATUS isc_dsql_execute(ISC_STATUS *, isc_tr_handle *,
isc_stmt_handle *, ushort, const XSQLDA*);
ISC_STATUS isc_dsql_execute2(ISC_STATUS *, isc_tr_handle *,
isc_stmt_handle *, ushort, const XSQLDA *, const XSQLDA *);
ISC_STATUS isc_dsql_execute_immediate(ISC_STATUS *,
isc_db_handle *, isc_tr_handle *, ushort, const ISC_SCHAR *,
ushort, const XSQLDA *);
ISC_STATUS isc_dsql_fetch(ISC_STATUS *, isc_stmt_handle *,
ushort, const XSQLDA *);
ISC_STATUS isc_dsql_finish(isc_db_handle *);
ISC_STATUS isc_dsql_free_statement(ISC_STATUS *,
isc_stmt_handle *, ushort);
ISC_STATUS isc_dsql_prepare(ISC_STATUS *, isc_tr_handle *,
isc_stmt_handle *, ushort, const ISC_SCHAR *, ushort, XSQLDA *);
ISC_LONG fb_interpret(ISC_SCHAR *, uint, const ISC_STATUS **);
ISC_STATUS isc_open_blob(ISC_STATUS *, isc_db_handle *,
isc_tr_handle *, isc_blob_handle *, ISC_QUAD *);
ISC_STATUS isc_open_blob2(ISC_STATUS *, isc_db_handle *,
isc_tr_handle *, isc_blob_handle *, ISC_QUAD *, ISC_USHORT, const
ISC_UCHAR *);
ISC_STATUS isc_get_segment(ISC_STATUS *, isc_blob_handle *,
ushort *, ushort, ISC_SCHAR *);
ISC_STATUS isc_close_blob(ISC_STATUS *, isc_blob_handle *);
void isc_decode_sql_date(const ISC_DATE *, void *);
void isc_decode_sql_time(const ISC_TIME *, void *);
void isc_decode_timestamp(const ISC_TIMESTAMP *, void *);
}
}
int main(string [] args)
{
string server = "suporte-pc";
string user_name = "SYSDBA";
string user_password = "masterkey";
ISC_SCHAR [] dpbarray;
dpbarray.length = 7 + server.length + user_name.length +
user_password.length;
ISC_SCHAR * dpb = dpbarray.ptr;
ISC_SCHAR * dpb_buffer = dpb;
* dpb_buffer++ = isc_dpb_version1;
* dpb_buffer++ = isc_dpb_password;
* dpb_buffer++ = cast(ISC_SCHAR) user_password.length;
for (auto p = user_password.ptr; * p;)
{
* dpb_buffer++ = * p++;
}
* dpb_buffer++ = isc_dpb_user_name;
* dpb_buffer++ = cast(ISC_SCHAR) user_name.length;
for(auto p = user_name.ptr; * p;)
{
* dpb_buffer++ = * p++;
}
* dpb_buffer++ = isc_dpb_address;
* dpb_buffer++ = cast(ISC_SCHAR) server.length;
for(auto p = cast(ISC_SCHAR *) server.ptr; * p;)
{
* dpb_buffer++ = * p++;
}
auto dpb_length = cast(short) (dpb_buffer - dpb);
isc_db_handle handle = null;
auto status = cast(ISC_STATUS *) GC.malloc(ISC_STATUS.sizeof *
ISC_STATUS_LENGTH);
if(isc_attach_database(status, 0, "C:\\FIREBIRD.FDB", &
handle, dpb_length, dpb))
{
isc_print_status(status);
return 1;
}
isc_tr_handle trans = null;
if(isc_start_transaction(status, & trans, 1, & handle, 0, null))
{
isc_print_status(status);
return 1;
}
isc_stmt_handle stmt = null;
if(isc_dsql_allocate_statement(status, & handle, & stmt))
{
isc_print_status(status);
return 1;
}
auto sqlda = cast(XSQLDA *) GC.malloc(XSQLDA.sizeof);
sqlda.ver = SQLDA_VERSION1;
sqlda.sqln = 1;
if(isc_dsql_prepare(status, & trans, & stmt, 0, "SELECT * FROM
test", SQL_DIALECT_V6, sqlda))
{
isc_print_status(status);
return 1;
}
if(isc_dsql_describe(status, & stmt, 1, sqlda))
{
isc_print_status(status);
return 1;
}
auto num_cols = sqlda.sqld;
if(sqlda.sqld > sqlda.sqln)
{
auto n = sqlda.sqld;
GC.free(sqlda);
sqlda = cast(XSQLDA *) GC.malloc(XSQLDA.sizeof + (n - 1) *
XSQLVAR.sizeof);
sqlda.sqln = n;
sqlda.ver = SQLDA_VERSION1;
if(isc_dsql_describe(status, & stmt, 1, sqlda))
{
isc_print_status(status);
return 1;
}
num_cols = sqlda.sqld;
}
auto sqlvar = cast(XSQLVAR *) sqlda.sqlvar;
ISC_SHORT sqlind;
for(auto i = 0; i < num_cols; i++)
{
sqlvar[i].sqldata = cast(ISC_SCHAR *)
GC.malloc(sqlvar[i].sqllen);
sqlvar[i].sqlind = cast(ISC_SHORT *)
GC.malloc(ISC_SHORT.sizeof);
}
if(isc_dsql_execute(status, & trans, & stmt, 1, sqlda))
{
isc_print_status(status);
return 1;
}
while(isc_dsql_fetch(status, & stmt, 1, sqlda) == 0)
{
for(auto i = 0; i < num_cols; i++)
{
switch(sqlvar[i].sqltype & 0xFFFFFFFE)
{
case SQL_TEXT:
sqlvar[i].sqldata[sqlvar[i].sqllen] = 0;
writef("\t%s", to!(string)(sqlvar[i].sqldata));
break;
case SQL_VARYING:
sqlvar[i].sqldata[sqlvar[i].sqllen + 2] = 0;
writef("\t%s", to!(string)(sqlvar[i].sqldata + 2));
break;
case SQL_INT64:
printf("\t%d", * cast(long *) sqlvar[i].sqldata);
break;
case SQL_SHORT:
printf("\t%d", * cast(short *) sqlvar[i].sqldata);
break;
case SQL_LONG:
printf("\t%d", * cast(int *) sqlvar[i].sqldata);
break;
case SQL_D_FLOAT:
case SQL_FLOAT:
printf("\t%f", * cast(float *) sqlvar[i].sqldata);
break;
case SQL_DOUBLE:
printf("\t%lf", * cast(double *) sqlvar[i].sqldata);
break;
case SQL_TIMESTAMP:
tm timestamp;
isc_decode_timestamp(cast(const ISC_TIMESTAMP *)
sqlvar[i].sqldata, & timestamp);
printf("\t%d/%d/%d %d:%d:%d", timestamp.tm_year + 1900,
timestamp.tm_mon + 1, timestamp.tm_mday, timestamp.tm_hour,
timestamp.tm_min, timestamp.tm_sec);
break;
case SQL_TYPE_DATE:
tm date;
isc_decode_sql_date(cast(const ISC_DATE *)
sqlvar[i].sqldata, & date);
printf("\t%d/%d/%d", date.tm_year + 1900, date.tm_mon + 1,
date.tm_mday);
break;
case SQL_TYPE_TIME:
tm time;
isc_decode_sql_time(cast(const ISC_TIME *)
sqlvar[i].sqldata, & time);
printf("\t%d:%d:%d", time.tm_hour, time.tm_min, time.tm_sec);
break;
case SQL_BLOB:
isc_blob_handle blob_handle = null;
if(isc_open_blob(status, & handle, & trans, & blob_handle,
cast(ISC_QUAD *) sqlvar[i].sqldata))
{
isc_print_status(status);
return 1;
}
ISC_SCHAR buffer[80];
ushort len;
while(isc_get_segment(status, & blob_handle, & len, 80,
buffer.ptr) != isc_segstr_eof)
{
}
if(isc_close_blob(status, & blob_handle))
{
isc_print_status(status);
return 1;
}
//buffer[len] = 0;
writef("\t%d:%s", len, to!(string)(buffer.ptr));
break;
default:
break;
}
}
putchar('\n');
}
for(auto i = 0; i < num_cols; i++)
{
GC.free(sqlvar[i].sqldata);
GC.free(sqlvar[i].sqlind);
}
GC.free(sqlda);
if(isc_dsql_free_statement(status, & stmt, DSQL_drop))
{
isc_print_status(status);
return 1;
}
if(isc_commit_transaction(status, & trans))
{
isc_print_status(status);
return 1;
}
if(isc_detach_database(status, & handle))
{
isc_print_status(status);
return 1;
}
GC.free(status);
return 0;
}
[/code]
Compiling with the GDC, the code executes normally (listing the
registry database), but compiling the code with DMD, by executing:
[code]
object.Error: Access Violation
----------------
0x00415B3C
0x004159C7
0x77776299 in RtlRaiseStatus
0x7777626B in RtlRaiseStatus
0x777760F7 in KiUserExceptionDispatcher
0x77783327 in RtlTryEnterCriticalSection
0x77783352 in RtlTryEnterCriticalSection
0x77775B0C in NtWaitForSingleObject
0xFFFFFFFF
----------------
[/code]
The DMD used is 2.060 and the GDC to GCC 4.6.1. Here is how I am
compiling the code:
> dmd main.d fbclient.lib
> gdc main.d -o main.exe -lfbclient_ms
At GDC, we used the library "fbclient_ms.lib" that comes with the
default installation of Firebird, and "fbclient.lib" used in DMD
was obtained with:
> implib fbclient.lib fbclient.dll
What can this be?
More information about the Digitalmars-d
mailing list