LINUX.ORG.RU

Зачем это нужно?

 


1

2

В proc.go стандартной библиотеки Go есть следующий код завершения процесса:

	exit(0)
	for {
		var x *int32
		*x = 0
	}

Какой смысл в бесконечном цикле сразу после exit(0)? Ведь он всё равно не выполняется.


Стало интересно, погуглил за тебя

https://stackoverflow.com/questions/55416148/why-is-there-a-seemingly-useless-infinite-for-loop-in-the-main-function-in-src-r

The runtime is a special case in many ways, and this is among the more special parts. This loop exists to catch problems while testing new ports. If that loop is ever reached, something has gone badly wrong: the exit call should have caused the program to exit. We can’t assume that panic is working. We can’t really assume that anything is working. What we want to do is stop the program. Since exit failed, it’s possible that a nil dereference will succeed. If that fails too, we still have to do something, so we just loop. We can’t return because this is the main function that started the program; there is nothing to return to.

grazor ★★
()
Ответ на: комментарий от grazor

Странный подход. У них и в обработчике паники есть нечто подобное сразу после exit(2), правда без цикла. Если управление попадёт туда, получится бесконечная рекурсия паники. В чём же смысл?

	systemstack(func() {
		exit(2)
	})

	*(*int)(nil) = 0 // not reached
hummer
() автор топика
Последнее исправление: hummer (всего исправлений: 2)
Ответ на: комментарий от hummer

написано жеж.

 We can’t return because this is the main function that started the program; there is nothing to return to.

уж не знаю как у них там все организовано, но такое делается, если на стеке нет адреса возврата,и просто выход из функции приведет к джампу по мусорному адресу. им некуда выходить, о чем они громко заявляют в тексте. а адреса возврата нет потому, что на такую начальную функцию переходят джампом, а не вызовом функции.

но они надеются, что такого не произойдет поскольку там есть какой-то exit(),…. короче я то же самое делал, в таких случаях.

потому что лучше крутиться в лупе, чем улететь вообще не пойми куда. а отладчик покажет, что ты в лупе этом, если что.

alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 1)
Ответ на: удаленный комментарий

Короче, это грязный хак для нестабильных систем. Если из проги выход не срабатывает, то прога будет висеть на месте и это будет заметно, значит, проще отдебажить и разобраться почему гошный рантайм не сработал как надо в этой оси и вызов exit привёл к зависанию, а не крешу твой приложухи. Если она крешеится при выходе - не всегда сразу будет понятно из-за чего и почему…

menangen ★★★★★
()
Ответ на: удаленный комментарий

Уже расписали, дополню более дословно, что это происходит при завершении работы main и, если exit(0) не сработал (например что-то пошло не так при добавлении поддержки новых систем), расчитывать что паника или вообще что-либо сработает тоже уже нельзя. Поэтому программа будет пытаться свалиться с разыменованием нулевого указателя, что является некорректной операцией. Если и так завершиться не удалось, программа не может сделать return из мейна и ей нужно что-то делать, и всё что ей остаётся делать это висеть в бесконечном цикле. То есть разыменование в цикле это комбинация попытки аварийно завершиться, а если не получится, то зависнуть

И такой же хак немного по-разному реализованный встречается ещё в нескольких местах в стандартной либе по той же причине

grazor ★★
()

Вопрос надо ставить шире: зачем вообще нужен го, когда есть джава.

anonymous
()

Нет бы недостижимый код запихать в exit() вместо засорения основной логики бессмысленным мусором из неопределенного ошибочного поведения.

anonymous
()
Ответ на: комментарий от X512

Что будет делать, если надо будет упасть при падении?

anonymous
()
Ответ на: комментарий от anonymous

Нет бы недостижимый код запихать в exit()

мать япона. он не от сломанного эксита защищает, а защищает от выхода из их мейна обычным способом, то есть ретурном. потому, что возвращаться некуда.

то есть, чтобы по-любому никто до этого кода не доходил. а уж что там другие индусы придумают, как до него не дойти - это вовсе вопрос неважный. ну допустим экситом этим.

alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 2)
Ответ на: комментарий от alysnix

он не от сломанного эксита защищает

С чем споришь? Сломанного ёкзита не должно быть в приличном обществе, как непаникующей паники.

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

anonymous
()
Ответ на: комментарий от anonymous

С чем споришь? Сломанного ёкзита не должно быть в приличном обществе, как непаникующей паники.

ты программируешь то на чем? типа язык и платформа

alysnix ★★★
()
Ответ на: комментарий от anonymous

а ты на чем? Только на позикс тредах конкурируешь?

а я первый спросил.

вот ты явно не из обсуждаемой предметной области. питонист небось какой-нить, с более чем абстрактными представлениями о железках, загрузчиках и рантаймах

alysnix ★★★
()
Ответ на: комментарий от alysnix

go

абстрактными представлениями о железках, загрузчиках и рантаймах

Поэтому сам к себе примени своё

ты явно не из обсуждаемой предметной области.

Язык программирования, тем более не машинного уровня, как go, должен обеспечить самое главное для написания вычислимых алгоритмов - завершение. Если у этого языка проблемы с завершением (паника тоже), то нет смысла говорить про написание алгоритмов на этом языке.

anonymous
()
Ответ на: комментарий от anonymous

Если у этого языка проблемы с завершением (паника тоже), то нет смысла говорить про написание алгоритмов на этом языке.

госпидя… да я вот уверен, что в ядре линуха такой же код имеется.

защитное программирование это называется. тут просто написана некая гарантия, что исполнение дальше не пойдет, потому что это будет полным UB. и фсе. и это не первое место в мире, где такое написано.

alysnix ★★★
()
Ответ на: комментарий от alysnix

защитное программирование это называется.

Оно должно быть внутри специальной команды exit(), а не в коде программы.

anonymous
()
Ответ на: комментарий от anonymous

код этого мейна(без такого лупа в конце) внешне выглядит так, что из него можно выйти куда-то там еще, а поскольку софт разрабатывает не один человек, а много - то другим такой вот хинт рисуется, чтобы они понимали, что это не простая функция. и еще пишется правильный коммент.

а если они этого не поймут, этот код их поймает.

команда exit() в данном случае может и отсутствовать, и функциональность ее непонтна, в случае какого-то пересмотра концептов, там может и не быть exit, а что-то еще.

а сам выход может осуществляться просто выходом их мейна. тут вопрос - как запускают этот мейн. если его пускать как функцию, а после этого вызова вызывать exit() - то завершение тоже будет, но выходом из мейна.

но в данном решении из мейна выходить нельзя, exit стоит прямо в нем, а потом стоит луп. такой вот вариант оформления мейна они выбрали

ps у них счас такой псевдокод вызова мейна

 jmp main_func. 

и exit внутри мейна

а если будет такой - то тоже будет работать. exit - снаружи мейна.

 call main_func
 call exit

в первом случае из мейня нельзя выходить..а во втором - из него НУЖНО выходить, чтобы завершиться

alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 2)
Ответ на: комментарий от alysnix

При чем тут оформление кода? Код должен быть корректным. Иначе придется компилятор специально искривлять, чтобы компилировал явно ошибочный код, а не оптимизировал и выкидывал как бессмысленный.

anonymous
()
Ответ на: комментарий от anonymous

Код должен быть корректным.

да ты чо!!! у тебя есть способы сделать его корректным всегда? тогда тебя с руками оторвут в любой конторе мирового уровня, а тестеров разгонят палками, развозить пиццу.

луп кстати тут код совершенно корректный. поскольку никак не сформулированы условия на функцию exit. компиялтор не может автоматически проверить, что из нее не могут выйти. вот если б такое условие можно было написать в декларации этой функции, это проверял бы компилятор - вопрос необходимости лупа стоял бы.

alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 1)
Ответ на: комментарий от alysnix

у тебя есть способы сделать его корректным всегда?

Причем тут общий случай? У тебя проблемы с определением явно ошибочного кода, который специально написан в этом примере?

anonymous
()
Ответ на: комментарий от anonymous

У тебя проблемы с определением явно ошибочного кода, который специально написан в этом примере?

он не ошибочен. пока нет гарантий, что из exit нельзя выйти, код неошибочен. компилятор тут не ругнется, что луп недостижим.

с какой стати вообще бесконечный луп стал ошибочным кодом? это где такое написано?

alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 1)
Ответ на: комментарий от alysnix

что луп недостижим.

Ясно, ты слепой. Внутри линзы явное разыменование нулевого указателя и запись (если я правильно понимаю go) - бесконечная контрольная очередь прицельно в голову.

anonymous
()
Ответ на: комментарий от alysnix

он не от сломанного эксита защищает, а защищает от выхода из их мейна обычным способом, то есть ретурном. потому, что возвращаться некуда.

Тогда почему этот код идёт сразу после вызова exit(0), а в другом месте аналогичный код после exit(2)? Этот код с дереференсом нуля сработает тогда и только тогда, когда кто-то сумел вернуться из exit(), что само по себе уже странно.

hummer
() автор топика
Ответ на: комментарий от anonymous

Ясно, ты слепой. Внутри линзы явное разыменование нулевого указателя и запись (если я правильно понимаю go) - бесконечная контрольная очередь прицельно в голову.

тебе не нравится запись нуля по нулевому адресу? это ты считаешь некоректным кодом???

приехали. это просто вызов обработчика исключений.

подумай вот. взять и вызвать обработчик исключений по имени - это нормально? если да - то вызвать его генерацией исключения - тоже нормально. либо ненормально ни то, ни другое.

alysnix ★★★
()
Ответ на: комментарий от alysnix

тебе не нравится запись нуля по нулевому адресу?

Я тут причём? Спроси у гошников, нравится им и компилятору такое?

anonymous
()
Ответ на: комментарий от anonymous

Я тут причём? Спроси у гошников, нравится им и компилятору такое?

они рантайм языка пишут. там такое нормально. это не прикладной уровень программирования. там деление на ноль, обращение не туда и все такое - рядовой сигнал, который надо обработать. рантайм от этого не упадет, и не даст твоей проге упасть.

alysnix ★★★
()
Ответ на: комментарий от alysnix

они рантайм языка пишут.

«Обычно» в рантайме языка не используют граничные/исключительные случаи самого языка. А наоборот описывают (на другом (под)языке), что делать в таких исключительных случаях.

anonymous
()
Ответ на: комментарий от anonymous

А наоборот описывают (на другом (под)языке), что делать в таких исключительных случаях.

исключительно вздорное утверждение. рантайм языков, это системный уровень, и там пишут так, как позволяет язык реализации и никого не спрашивают. и не применяют еще каких-то левых языков, если язык реализации рантайма позволяет это делать. ну нет никакого смысла завязываться еще на какой-то язык. это только усложнит проект

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

alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 2)
Ответ на: комментарий от hummer

Этот код с дереференсом нуля сработает тогда и только тогда, когда кто-то сумел вернуться из exit(), что само по себе уже странно.

а что странного? там какой-то свой exit(), это ж го, там небось целый наворот с финализацией всей системы, сборкой мусора, закрытием хендлов, еще какая-нить пурга, и они небось уже из него бесконтрольно выскакивали… после чего догадались луп там приделать… но вообще такой луп делают сразу :)

я вот в своей жизни на голых железках правда.. то есть там все свое, кроме загрузчика в пзу процессора, делал такой же луп и сразу. только в нем не исключение генерил, а запускал какой-нить sleep режим процессора. чтобы он тихо крутился и ждал когда к нему придут.

alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 3)
Ответ на: комментарий от alysnix

Поэтому и прокомментировали, что если не сработает завершение программы-алгоритма, то понадейтесь на бога-систему, что она правильно обработает запись по адресу со значением nil значения 0 типа int32. Допустим, в роли системы - dos с таблицей векторов прерываний по адресу сильно похожему значению nil.

anonymous
()
Ответ на: комментарий от alysnix

а что странного? там какой-то свой exit()

Платформозависимый exit(), для каждой платформы свой. Например для Винды в os_windows.go такой:

//go:nosplit
func exit(code int32) {
	// Disallow thread suspension for preemption. Otherwise,
	// ExitProcess and SuspendThread can race: SuspendThread
	// queues a suspension request for this thread, ExitProcess
	// kills the suspending thread, and then this thread suspends.
	lock(&suspendLock)
	atomic.Store(&exiting, 1)
	stdcall1(_ExitProcess, uintptr(code))
}
hummer
() автор топика
Ответ на: комментарий от hummer

ну типа посмотрел. exit() этот там внутренний, системный вызов убийства процесса. непохоже что это то, что os.Exit(..) в самом голанге.

луп там стоит чисто для защиты, как я сказал.

alysnix ★★★
()
Ответ на: комментарий от alysnix

Ну в общем у них нет гарантии, что из exit() нельзя вернуться, что весьма странно.

Вот более полный код запуска main() и выходи из него без os.Exit()

	fn := main_main // make an indirect call, as the linker doesn't know the address of the main package when laying down the runtime
	fn()
	if raceenabled {
		racefini()
	}

	// Make racy client program work: if panicking on
	// another goroutine at the same time as main returns,
	// let the other goroutine finish printing the panic trace.
	// Once it does, it will exit. See issues 3934 and 20018.
	if atomic.Load(&runningPanicDefers) != 0 {
		// Running deferred functions should not take long.
		for c := 0; c < 1000; c++ {
			if atomic.Load(&runningPanicDefers) == 0 {
				break
			}
			Gosched()
		}
	}
	if atomic.Load(&panicking) != 0 {
		gopark(nil, nil, waitReasonPanicWait, traceEvGoStop, 1)
	}

	exit(0)
	for {
		var x *int32
		*x = 0
	}

fn() - это вызов main() программы. Тут ещё какое-то магическое число 1000 с комментарием: «Running deferred functions should not take long». Видимо это такой гуглостайл.

hummer
() автор топика
Ответ на: комментарий от hummer

Тут ещё какое-то магическое число 1000 с комментарием: «Running deferred functions should not take long».

это они передают управление на горутины которые остались с паническими отложенными функциями, а счетчик - типа - «тыщи их там точно нет», потому все будут выполнены

alysnix ★★★
()

Лучше бы sleep(ms) использовали в бесконечном цикле - так хотя бы процессорное время не тратилось на фигню.

iZEN ★★★★★
()
Ответ на: комментарий от CryNet

Ну да. Когда про знания человека судят по ЯПу, это как-то больше характеризует того, кто судит.

С другой стороны… по конкретному вопросу он в чём-то прав. Кристально чистый и логичный код можно написать не всегда и не везде. В данном случае, как я понимаю, у exit() 100500 реализаций под разные платформы, и вот чтобы на тех платформах, где реализации не вылизаны должным образом, программа хоть как-то корректно вела себя, этот не совсем чистый хак и написали. Ещё Питер Нортон, описывая не совсем штатные приёмы при вызове int21h, написал «…но я и не обещал, что вам не придётся запачкать руки».

Написанное, конечно же, не означает, что реализации вылизывать не нужно. Наоборот.

hobbit ★★★★★
()
Ответ на: комментарий от hobbit

Та регистран всё разжевал и расписал, а продолжают снова чёт мусолить.

CryNet ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.