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

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 что-то начнёт глючить - пишите.