Знаменитые последние слова: «Не волнуйся - мои перемены ничего не сломали». Как мы можем быть уверены в этом?
Однако есть небольшая вероятность, что вы правы, если код работал под 4.4 и вылетал под 4.5.
GCC принял некоторые агрессивные оптимизации, связанные с кодом, который пытается обнаружить целочисленное переполнение и удаляет его. В этом случае вам нужно будет найти этот код в ns-2 и попытаться исправить его - либо разработчиками ns-2, либо самостоятельно.
Возможно, вам следует попытаться запустить программу под отладчиком, чтобы вы могли получить контроль в точке, где обнаружено переполнение буфера, и посмотреть, где находится код. Если вы отключили дампы ядра (с ulimit -c 0
или эквивалентным), рассмотрите возможность их включения и посмотрите, получите ли вы дамп ядра, когда он завершится. Это должно дать вам отправную точку.
Дальнейшие мысли:
Когда вы компилировали код, насколько строгими были флаги предупреждения? Можете ли вы перекомпилировать с включенными дополнительными предупреждениями?
Одна методика, которая часто работает (с программами, настроенными на AutoTools), если вы не можете найти другого способа получить специальные опции для компилятора C или C ++:
./configure --prefix=/opt/ns CC="gcc -Wall -Wextra" CXX="g++ -Wall -Wextra"
(я также использую эту технику для определения 32-битных и 64-битных сборок, добавляя -m32
или -m64
.)
Предупреждение: если код не был создан для чистой компиляции с этими параметрами, может быть травмирующей первую компиляцию с использованием этих параметров. Тем не менее, есть также неплохая вероятность того, что среди всех предупреждений есть источник вашей проблемы. Однако, это также бесспорно, что, вероятно, будет 50 предупреждений, не связанные с ним к любому 1, который (или хуже), и фиксируя все предупреждения, таким образом, пятнистый до сих пор не может вылечить проблему. Если код компилируется со строгими предупреждениями в любом случае, тогда вы столкнетесь с включением гораздо большего количества экзотических предупреждений. Но если вы можете заставить компилятор помочь диагностировать проблему, которую он вызывает, вам, безусловно, следует это сделать - это гораздо проще, чем найти проблему без посторонней помощи.
Также убедитесь, что вы создаете отлаживаемую программу, даже если оптимизация включена.
Кроме того, рассмотрите возможность компиляции с отключенной оптимизацией и посмотрите, по-прежнему ли происходит сбой программы. Если программа не дает сбоя без оптимизации и с оптимизацией, у вас есть некоторая полезная информация. Это не поможет найти причину, но вы знаете, что это (вероятно) связано с оптимизатором. Или это может быть просто из-за того, что ошибка перемещается, если она не оптимизирована и не приводит к фатальной ошибке.
Информация трассировки расширенного стека любопытна:
#5 0x00000000008d5b5a in strcpy (interp=0xd2dda0, optionIndex=<value optimized out>,
objc=<value optimized out>, objv=0x7fffffffdad0)
at /usr/include/bits/string3.h:105
#6 TraceVariableObjCmd (interp=0xd2dda0, optionIndex=<value optimized out>,
objc=<value optimized out>, objv=0x7fffffffdad0)
at /media/Linux/ns-allinone-2.35-RC7/tcl8.5.8/unix/../generic/tclTrace.c:912
Это не обычные аргументы strcpy()
. Обычно у вас есть только два аргумента. Я не могу сразу думать об обстоятельствах, когда было бы целесообразно скопировать строку поверх указателя на основную структуру управления интерпретатора Tcl. Итак, чтобы продвинуться дальше, я бы очень внимательно посмотрел на строки 900-920 или около того в tclTrace.c
и, в частности, на строку 912. Это может быть просто артефактом того, как оптимизатор манипулирует объектным кодом, или это может быть подлинной проблемой.
Я нашел источник tcl8.5.8 и строка 912 файла tclTrace.c - это strcpy()
в этом коде:
if ((enum traceOptions) optionIndex == TRACE_ADD) {
CombinedTraceVarInfo *ctvarPtr;
ctvarPtr = (CombinedTraceVarInfo *) ckalloc((unsigned)
(sizeof(CombinedTraceVarInfo) + length + 1
- sizeof(ctvarPtr->traceCmdInfo.command)));
ctvarPtr->traceCmdInfo.flags = flags;
if (objv[0] == NULL) {
ctvarPtr->traceCmdInfo.flags |= TCL_TRACE_OLD_STYLE;
}
ctvarPtr->traceCmdInfo.length = length;
flags |= TCL_TRACE_UNSETS | TCL_TRACE_RESULT_OBJECT;
strcpy(ctvarPtr->traceCmdInfo.command, command); // Line 912
ctvarPtr->traceInfo.traceProc = TraceVarProc;
ctvarPtr->traceInfo.clientData = (ClientData)
&ctvarPtr->traceCmdInfo;
ctvarPtr->traceInfo.flags = flags;
name = Tcl_GetString(objv[3]);
if (TraceVarEx(interp,name,NULL,(VarTrace*)ctvarPtr) != TCL_OK) {
ckfree((char *) ctvarPtr);
return TCL_ERROR;
}
} else {
Итак, вывод из GDB и трассировка стека выглядит несколько вводящим в заблуждение; две переменные передаются в strcpy()
, и одна из них локально размещается в куче.
Я бы подумал о компиляции tcl
в автономном режиме из источника, встроенного в ns-2
, и посмотрю, можете ли вы исправить ошибку (извините, ужасный каламбур) самостоятельно. Этот код связан с отслеживанием переменной tcl
- trace add varname ...
AFAICT.
Предполагая, что это пройдет, я бы подумал о том, чтобы овладеть GCC 4.6 и посмотреть, возникает ли такая же проблема при компиляции ns-2
с этим вместо GCC 4.5.
Valgrind
Поскольку вы работаете в Linux, вы сможете использовать Valgrind.Отлично подходит для выявления проблем со злоупотреблением памятьюДля максимальной пользы используйте отладочную сборку ns-2
.