digitalmars.D - GC.malloc problems with the DMD
- Raphael Basso (424/427) Sep 21 2012 Hello
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_msAt 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.dllWhat can this be?
Sep 21 2012