Как взорвать ракету одной переменной
vk f t

Как взорвать ракету одной переменной

Крат­кий мастер-класс по пра­виль­но­му объ­яв­ле­нию типов дан­ных.

Что произошло

Ошиб­ки в коде быва­ют у всех, но их послед­ствия все­гда раз­ные. Одно дело — оши­бить­ся в про­грам­ме для шаго­ме­ра и поте­рять 500 шагов, и дру­гое — лишить­ся полу­мил­ли­ар­да дол­ла­ров.

Эта исто­рия про­изо­шла в 1996 году, когда Евро­пей­ское кос­ми­че­ское агент­ство поте­ря­ло кос­ми­че­скую ракету-носитель Ariane-5 из-за непра­виль­но объ­яв­лен­ной пере­мен­ной. Через 40 секунд после стар­та раке­та взо­рва­лась в воз­ду­хе, пол­но­стью уни­что­жив четы­ре спут­ни­ка, кото­рые нуж­но было выве­сти на орби­ту.

Когда комис­сия нача­ла рас­сле­до­ва­ние, она выяс­ни­ла, что во всём вино­ва­та одна пере­мен­ная, кото­рая не мог­ла при­ни­мать зна­че­ние боль­ше, чем 32 767. Это­го ока­за­лось доста­точ­но, что­бы всё вышло из-под кон­тро­ля.

Ракета-носитель Ariane-5, фото из Вики­пе­дии

В чём причина

В лета­тель­ном аппа­ра­те был модуль, кото­рый отве­чал за ори­ен­ти­ров­ку в про­стран­стве, — инер­ци­он­ная систе­ма ори­ен­ти­ров­ки, ИСО. Евро­пей­цы ста­ви­ли этот эле­мент на все раке­ты, допи­ли­вая его под раз­ные зада­чи. Ariane-5 достал­ся модуль от Ariane-4. Дума­ли, что раз он пре­крас­но пока­зал себя на преды­ду­щем аппа­ра­те, то и на новом тоже всё зара­бо­та­ет.

Раке­та Ariane-4 лета­ла не так быст­ро, как Ariane-5, и модуль мог спо­кой­но посчи­тать всё, что ему было нуж­но, исполь­зуя пере­мен­ные в диа­па­зоне от −32 768 до 32 767. При­чём этот про­ме­жу­ток был с запа­сом: в реаль­но­сти такие чис­ла на Ariane-4 не исполь­зо­ва­лись.

Но Ariane-5 лета­ла намно­го быст­рее. Пере­мен­ные очень ско­ро достиг­ли сво­е­го мак­си­маль­но­го зна­че­ния и вызва­ли сбой. Вклю­чил­ся резерв­ный модуль, но в нём сто­ял точ­но такой же софт от ста­рой раке­ты, кото­рый сде­лал всё то же самое: быст­ро достиг потол­ка в пере­мен­ной и тоже вызвал сбой. Ariane-5 про­дол­жа­ла уско­рять­ся.

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

Поче­му пере­пол­ни­лась пере­мен­ная?

Память у ком­пью­те­ров не рези­но­вая. Когда мы пишем про­грам­му и нуж­но в ней что-то запом­нить, мы гово­рим ком­пью­те­ру: «Выде­ли нам память для такой-то инфор­ма­ции».

Есть язы­ки про­грам­ми­ро­ва­ния, где место для дан­ных выде­ля­ет­ся авто­ма­ти­че­ски. Напри­мер, в JavaScript про­сто гово­ришь: «Вот новая пере­мен­ная, поло­жи в неё вот это», — и систе­ма сама опре­де­лит, сколь­ко на эту инфор­ма­цию нуж­но памя­ти. Есть язы­ки, где необ­хо­ди­мо чёт­ко ска­зать, како­го типа пере­мен­ную сле­ду­ет создать. Напри­мер, в язы­ке C:

int speed;
speed = 99;

Int озна­ча­ет integer, то есть целое чис­ло. На целое чис­ло выде­ля­ет­ся сколько-то памя­ти, в зави­си­мо­сти от язы­ка. Что­бы не погру­жать­ся в бит­ность и слож­но­сти дво­ич­но­го счис­ле­ния, пред­ставь­те такую ситу­а­цию.

Вы дела­е­те инвен­та­ри­за­цию това­ров на скла­де. По каж­дой пози­ции вы запол­ня­е­те фор­му, в кото­рой есть поле «Поряд­ко­вый номер». В этой гра­фе три пустых клет­ки, кото­рые вы може­те запол­нить циф­ра­ми от 0 до 9. Если начи­нать с това­ра 001, то мак­си­маль­ное коли­че­ство пози­ций, кото­рое вы може­те посчи­тать с помо­щью этих трёх кле­ток, — 999.

[0] [0] [1]

[0] [0] [2]

[0] [0] [3]

...

[9] [9] [9]

Если у вас на скла­де лежит более 999 това­ров, вам потре­бу­ет­ся какая-то дру­гая фор­ма, в кото­рой будет уже не три, а четы­ре клет­ки. Или мож­но объ­явить про­грамм­ный сбой и уйти на обед.

Вот это и про­изо­шло с раке­той:

  1. Раке­те дали, гру­бо гово­ря, 16 кле­ток, что­бы запи­сать какой-то пара­метр ско­ро­сти.
  2. Мак­си­маль­ное чис­ло, кото­рое мож­но было запи­сать на ком­пью­те­ре, исполь­зуя 16 ком­пью­тер­ных кле­ток, — 65 535.
  3. Если нам нуж­ны чис­ла с плю­са­ми и мину­са­ми, то мы полу­ча­ем диа­па­зон зна­че­ний от −32 768 до +32 767.
  4. Всё, что выхо­дит за рам­ки это­го про­ме­жут­ка, ком­пью­тер уже не может запи­сать — так же, как мы не можем вне­сти в три клет­ки чис­ло более 999.
  5. Про­грам­ме нуж­но было запи­сать чис­ло боль­ше, чем 32 767. А кле­ток не хва­та­ет!
  6. Даль­ше вы зна­е­те.

Вот так одна стро­ка кода может пустить на ветер кучу денег и стать одной из самых доро­гих оши­бок в исто­рии про­грам­ми­ро­ва­ния. А вот та самая стро­ка:

P_M_DERIVE(T_ALG.E_BH) := UC_16S_EN_16NS (TDB.T_ENTIER_16S

((1.0/C_M_LSB_BH) *

G_M_INFO_DERIVE(T_ALG.E_BH)))

Ещё по теме