Грешка при сегментиране само когато пренасоча stdout към /dev/null?

Имам единичен тест на C++, който произвежда полезен изход към stderr и най-вече шум (освен ако не отстранявам грешки) към stdout, така че бих искал да пренасоча stdout към /dev/null.

Любопитно е, че това изглежда причинява грешка в сегментирането.

Има ли някаква причина, поради която кодът може да маркира грешка с "> /dev/null" и да работи добре в противен случай?

Резултатът се произвежда изцяло от printfs, ако това има някакво значение.

Трудно ми е да публикувам обидния код, защото това е изследване, което се изпраща за публикуване. Надявам се, че има "очевидна" възможна причина въз основа на това описание.

следсмъртно

Segfault се причинява от код като този:

ArrayElt* array = AllocateArrayOfSize(array_size);
int index = GetIndex(..) % array_size;
ArrayElt elt = array[index];

За сетен път забравих, че x % y остава отрицателно, когато x е отрицателно в C/C++.

Добре, тогава защо се случваше само когато пренасочих към /dev/null? Предполагам, че невалидният адрес на паметта, до който имах достъп, беше в изходен буфер за stdout - и този буфер не се разпределя, когато не е необходим.

Благодаря за добрите отговори!


person Tyler    schedule 11.10.2009    source източник
comment
Кодът многонишков ли е? Ако е така, възможно е пренасочването на stdout да промени това време на критичен аспект на вашата програма и да предизвика грешка в условията на състезание.   -  person bcat    schedule 11.10.2009
comment
Не е многонишков. Как да стартирам gdb на процес с пренасочен изход? gdb ./mybinary › /dev/null също пренасочва stdout на gdb.   -  person Tyler    schedule 11.10.2009
comment
Знакът на x % y, когато някой от операндите е отрицателен, се дефинира от изпълнението, така че не можете да разчитате преносимо на поведението, което виждате.   -  person CB Bailey    schedule 11.10.2009
comment
@Tyler: ако идвате от LISP-land или някъде другаде, където се изисква (x mod y) да върне положително число, тогава може би трябва да си напишете (шаблон?) функция, която върши работата вместо вас, и да я използвате вместо операторът? Целочислената версия е лесна; вероятно ще трябва да предоставите една или повече специализации за числа с плаваща запетая.   -  person Jonathan Leffler    schedule 11.10.2009


Отговори (3)


Няма "нормална" причина I/O към stdout да задейства дъмп на ядрото, когато стандартният изход е пренасочен към /dev/null.

Най-вероятно имате указател или препълване на буфера, което задейства дъмпа на ядрото, когато е изпратено към /dev/null, а не когато е изпратено към стандартния изход - но ще бъде трудно да забележите проблема без кода.

Традиционно е полезната информация да се постави на стандартния изход, а шумът - на стандартната грешка.

person Jonathan Leffler    schedule 11.10.2009

Това не отговаря точно на въпроса ви, но може. Опитвали ли сте да използвате gdb? Това е инструмент за отстраняване на грешки от командния ред, който може да открие къде възникват сегментни грешки. Той е доста лесен за използване. Ето един доста задълбочен урок за това как да го използвате.

person Kredns    schedule 11.10.2009
comment
Добра идея - ползвал съм го малко преди. Когато стартирам gdb ./my_binary › /dev/null обаче, аз също губя интерфейса за gdb - как мога да стартирам gdb на моя процес с неговия stdout пренасочен? - person Tyler; 11.10.2009
comment
@Tyler: проверете опциите за изпълнение в рамките на gdb: gdb ./my_binary на командния ред (или добавете името на основния дъмп, ако имате такъв), и след това стартирайте програмата с 'run ›/dev/null'. - person Jonathan Leffler; 11.10.2009

Възможно е нещо да проверява „isatty“, което може да причини различно поведение за /dev/null.

Възможно е нещо да чете от stdout, което би се провалило за /dev/null.

person Martin v. Löwis    schedule 11.10.2009
comment
@Martin: ако /dev/null е отворен за четене, тогава можете да четете от него (но не получавате информация - само „EOF“). Ако някой очаква да чете от номинално канал само за запис (т.е. кодът чете от стандартен изход), тогава има сериозни проблеми (но често можете да се разминете, когато стандартният изход е терминалът). - person Jonathan Leffler; 11.10.2009