Тема: C++Builder bug?
Показать сообщение отдельно
Старый 12.01.2005, 04:09     # 9
blacklist
Newbie
 
Регистрация: 25.08.2004
Сообщения: 11

blacklist Путь к славе только начался
Fix

Ну вот, как говорится - не прошло и полмесяца... Да, праздники - классная штука

Сначала немного эмоций:
1) такое ощущение, что модуль 'xx.cpp' писали с закрытыми глазами и при том левой ногой - настолько он кривой. Особенно мне понравился комментарий к одному отключённому блоку кода: 'The following code does NOT work correctly ... So for now this code is disabled again, till we figure out a better way to do this'. Как говорится - до лучших времён . Ну да ладно, оставим это на совести автора.
2) Судя по ответу zhsa , этот баг присутствует и в предыдущих версиях RTL. Мне вот что интересно, как это он умудрился продержатся шесть версий Builder'а, и ни разу не был замечен (по крайней мере, на программерских форумах я подобных тем не нашёл). Что никто ExceptionRecord никогда не пробовал использовать? Или это так много народу C++Builder юзает?

Ну всё, хватит лирики. теперь о главном, собственно Fix:
итак правим файл $(BCB)\Source\Rtl\Source\except\xx.cpp
(Комментарий *** указывает на изменённую строку, а +++ -- на добавленною)

Функция getExceptionObject
Код:
static  excDscPtr       getExceptionObject(EXCEPTION_RECORD *P, unsigned long osEsp, unsigned long osERR, PCONTEXT ctx)
{
	int             ErrorCode;
	excDscPtr       xdp;
	tpidPtr         typeID;
	tpidPtr         baseID;
	EExternal *     excObj;		//  ***
	unsigned short  mask;
	ErrorCode = mapException(P);
	if      (ErrorCode < 3 || ErrorCode > sizeof(OSExceptionTypeIDs) / sizeof(OSExceptionTypeIDs[0]))
		return 0;
	typeID = OSExceptionTypeIDs[ErrorCode].OSETid;
	switch  (ErrorCode)
	{
	case    3:      excObj = new EDivByZero(Sysconst_SDivByZero)           ; break;	// ***
	case    4:      excObj = new ERangeError(Sysconst_SRangeError)         ; break;	// ***
	case    5:      excObj = new EIntOverflow(Sysconst_SIntOverflow)       ; break;	// ***
	case    6:      excObj = new EInvalidOp(Sysconst_SInvalidOp)           ; break;	// ***
	case    7:      excObj = new EZeroDivide(Sysconst_SZeroDivide)         ; break;	// ***
	case    8:      excObj = new EOverflow(Sysconst_SOverflow)             ; break;	// ***
	case    9:      excObj = new EUnderflow(Sysconst_SUnderflow)           ; break;	// ***
//      case    10:     excObj = new EInvalidCast("EInvalidCast")       ; break;
	case    11:     excObj = new EAccessViolation(				// ***
                                  Sysconst_SAccessViolation,					// ***
                                  ARRAYOFCONST((						// ***
                                    P->ExceptionAddress,					// ***
                                    P->ExceptionInformation[0]?Sysconst_SWriteAccess:Sysconst_SReadAccess,   	// ***
                                    (PVOID)P->ExceptionInformation[1])))       ; break;		// ***
	case    12:     excObj = new EPrivilege(Sysconst_SPrivilege)           ; break;	// ***
	case    13:     excObj = new EControlC(Sysconst_SControlC)             ; break;	// ***
	case    14:     excObj = new EStackOverflow(Sysconst_SStackOverflow)   ; break; // ***
	default:
          excObj = new EExternalException(Sysconst_SExternalException, ARRAYOFCONST(((int)P->ExceptionCode)));  // ***
	}

	mask = typeID->tpMask;
	assert(mask & TM_IS_REF);
	baseID = typeID->tpPtr.tppBaseType;
	xdp = allocExceptMem(sizeof(*xdp) + sizeof(EExternal *));			// ***
	xdp->xdPrevious	  = 0;
	xdp->xdTypeID     = typeID;
	xdp->xdFlags      = XDF_OSEXCEPTION;
	xdp->xdSize       = sizeof(EExternal *);					// ***
	xdp->xdMask       = mask;
	xdp->xdCflg       = 0;
	xdp->xdBase       = baseID;
	xdp->xdFriendList = (tpidPtr TPDST *)0;
	xdp->xdERRaddr    = 0;
	xdp->xdHtabAdr    = 0;
	xdp->xdFreeFunc   = freeExceptMem;
	xdp->xdThrowLine  = 0;
	xdp->xdThrowFile  = 0;
	xdp->xdCCaddr     = 0;
	xdp->xdCCmask     = 0;
	xdp->xdArgCopy    = 0;
	xdp->xdArgBuff    = 1;
	xdp->xdOSESP      = osEsp;
	xdp->xdOSERR      = osERR;
	xdp->xdOSContext  = ctx;
	excObj->ExceptionRecord = (Sysutils::PExceptionRecord)P;	// +++
	memcpy(xdp->xdValue, &excObj, sizeof(EExternal *));		// ***
	return xdp;
}
Функция __JumpToCatch__:
Код:
void    __cdecl __JumpToCatch__(void)
{
//  Commented setting of ESP - seems to be not needed, also it would prevent 
//  our OS exception handling patch from working correctly, so ripped it...
//    __emit__(0x8B); __emit__(0xE3); /* mov esp, ebx */    // комментируем эту строку - зачем мы восстанавливаем 
					              // значение ESP до выхода из обработчика для меня вообще загадка
     __emit__(0x8B); __emit__(0xE9); /* mov ebp, ecx */
     __emit__(0xFF); __emit__(0xE0); /* jmp eax      */
}
Теперь перекомпилируем RTL с помощью скрипта build.bat (он лежит в директории $(BCB)\Source\Rtl), не забыв перед этим добавить путь $(BCB)\Source\Rtl\Tools в путь поиска (например вот так: SET PATH=%PATH%;C:\CBUILDER\Source\Rtl\Tools).
Вот и всё, осталось только скопировать созданые в директории Source\Rtl\Lib файлы *.DLL и *.TDS в папку $(BCB)\Bin, а файлы *.LIB и *.OBJ в папку $(BCB)\Lib (попутно сохранив оригиналы - на всякий случай), запустить приведеный ранее пример и убедится что теперь всё работает правильно.

Ну что ж, вроде бы нигде не ошибся , но если с новым RTL что-то начнёт глючить - пишите.
blacklist вне форума