www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - GC.malloc problems with the DMD

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?
Sep 21 2012