Я испытываю странное поведение, когда данные передаются определенной функции в некотором сгенерированном коде. Проблема возникает всякий раз, когда оптимизация включена (-O1
и выше). Но не на -O0
.
Код C генерируется OpenModelica 1.13.0-dev и компилируется в 32,9 битах Centos 6.9 с использованием gcc 4.4.7. Я знаю, что мои настройки немного устарели, но я не могу поступить иначе.
Мне удалось войти в код с помощью gdb, чтобы получить откат неисправной функции с помощью -O0
__OMC_DIV_SIM (threadData=0x83bb7e0, a=0.90000000000000002, b=1, msg=0xac4f6024 "PMECH1 - D * SLIP / 1.0 + SLIP", equationIndexes=0xbfffd4a0,
noThrowDivZero=1 '\001', time_=0, initial_=1 '\001')
А вот обратный след той же функции с -O2
__OMC_DIV_SIM (threadData=0x83bb7a8, a=-9.2559642734470712e+61, b=5.298772688916812e-315, msg=0x1 <Address 0x1 out of bounds>,
equationIndexes=0x3ff00000, noThrowDivZero=-60 '\304', time_=3.7134892271125328e-314, initial_=0 '\000')
Все исследования для Address 0x1 out of bounds
указывают на повреждение стека или памяти. Затем я запустил свой исполняемый файл через valgrind.
==5351== Invalid read of size 1
==5351== [...]
==5351== by 0x7EA13F4: __OMC_DIV_SIM (division.h:66)
==5351== [...]
==5351== Address 0x1 is not stack'd, malloc'd or (recently) free'd
==5351==
==5351==
==5351== Process terminating with default action of signal 11 (SIGSEGV)
==5351== Access not within mapped region at address 0x1
==5351== [...]
==5351== by 0x7EA13F4: __OMC_DIV_SIM (division.h:66)
==5351== [...]
==5351== If you believe this happened as a result of a stack
==5351== overflow in your program's main thread (unlikely but
==5351== possible), you can try to increase the size of the
==5351== main thread stack using the --main-stacksize= flag.
==5351== The main thread stack size used in this run was 8388608.
Код не очень полезен, так как он не предназначен для чтения пользователем. Я немного изменил его, чтобы сделать его более читабельным и точно определить проблему.
double value = 0.0;
if ((long)data->localData[0]->integerVars[0] /* TRIPI */ == ((long) 0))
{
double PMECH1 = data->localData[0]->realVars[24];
double D = data->simulationInfo->realParameter[21];
double SLIP = data->localData[0]->realVars[4];
double TELEC = data->localData[0]->realVars[35];
double H = data->simulationInfo->realParameter[24];
double div_1 = 0.0;
{
double a = PMECH1 - ((D) * (SLIP));
double b = 1.0 + SLIP;
div_1 = __OMC_DIV_SIM(threadData, a, b, "PMECH1 - D * SLIP / 1.0 + SLIP", equationIndexes, data->simulationInfo->noThrowDivZero, data->localData[0]->timeValue, initial());
}
// ...
}
Тогда вот файл, который содержит __OMC_DIV_SIM
#define DIVISION_SIM(a,b,msg,equation) (__OMC_DIV_SIM(threadData, a, b, msg, equationIndexes, data->simulationInfo->noThrowDivZero, data->localData[0]->timeValue, initial()))
int valid_number(double a)
{
return !isnan(a) && !isinf(a);
}
static inline modelica_real __OMC_DIV_SIM(threadData_t *threadData, const modelica_real a, const modelica_real b, const char *msg, const int *equationIndexes, modelica_boolean noThrowDivZero, const modelica_real time_, const modelica_boolean initial_)
{
modelica_real res;
if(b != 0.0)
res = a/b;
else if(initial_ && a == 0.0)
res = 0.0;
else
res = a / division_error_equation_time(threadData, a, b, msg, equationIndexes, time_, noThrowDivZero);
if(!valid_number(res))
throwStreamPrintWithEquationIndexes(threadData, equationIndexes, "division leads to inf or nan at time %g, (a=%g) / (b=%g), where divisor b is: %s", time_, a, b, msg);
return res;
}
Я не могу протестировать этот код с другим gcc, но я смог протестировать другой компонент в той же среде, и он прошел без каких-либо проблем.
Я до сих пор не знаю, что портит данные, переданные __OMC_DIV_SIM
. Может ли это быть ошибкой в компиляторе? Или в сгенерированном коде?