Моя программа вылетает, когда Соня входит в систему

Abstract

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

Проект

Проект назывался DBCalc, см. Виртуальная память в 64 КБ.

Проблема

Мои приложения в DBCalc иногда давали сбои в непредсказуемые моменты времени. Теоретически, это должно было быть невозможно в используемой нами ОС RSX-11M. Это была многопользовательская система с разделением времени; каждому приложению была предоставлена собственная память, полностью изолированная от других приложений и системы. Я не использовал таймеров реального времени или еще чего-нибудь, что могло бы меняться от одного выполнения к другому. Я привык к абсолютно детерминированному выполнению программ.

Отладка

Для начала я, конечно, попробовал воспользоваться отладчиком. К сожалению, DBCalc не слетал, когда я запускал DBCalc в отладчике. Так-что отладчик оказался мне был бесполезен.

Когда программа слетала, она печатала содержимое 8 регистров процессора, один из которых, R7, был программным счетчиком. Каждый раз, когда DBCalc слетал, он показывал различное содержимое регистров, включая R7. Я копировал числа на лист бумаги, использовал подробный листинг сборки, чтобы разобраться, какой код выполнялся, и попытался выяснить, что с ним могло быть не так. Это заняло много времени.

После многих сеансов отладки между сбоями вскрылось сходство. Каким-то образом одна глобальная переменная $DSW была нарушена. Эта переменная была точкой входа во всю среду выполнения DBCalc, поэтому в случае повреждения $DSW вообще ничего не работало. Причина, по которой я использовал $ DSW, заключалась в том, что у него был известный фиксированный адрес памяти, 14. $DSW был описан в документации DEC следующим образом:

   $DSW - reserved. 

И больше ни слова о ней. Я прикинул, что могу использовать его в своих целях. Я пересмотрел свой код и убедился, что после инициализации переменная не менялась. Я вставил операторы печати в разных местах и стал печатать содержимое $ DSW. Вопреки моим ожиданиям, переменная менялась! Но она менялся в разное время, и я мог понять, какой фрагмент кода её менял. Я читал и перечитывал все подозрительные части системы - ничего.

В какой-то момент я вспомнил, что процессор PDP-11 имеет управляющий бит T , который, если установлен в 1, останавливает программу после каждой команды и вызовет процедуру прерывания. К этому моменту я уже потратил несколько дней на поиски ошибки, и хотя я знал, что процесс затормозит, я решил попробовать установить бит в 1. Моя процедура прерывания проверяла переменную $DSW и выводила статус программы всякий раз, когда переменная изменялсь.

Я внес необходимые изменения и был готов к 19:00 в тот день. Я запустил приложение. Оно работало несколько часов и успешно завершилось! Следующим шагом было начать биться головой о твердые поверхности.

На следующее утро новых идей у меня не появилось. Я пришел рано и запустил приложение снова, без изменений. Оно работало нормально примерно до 9 утра. Тут начали приходить люди, и моя сотрудница Соня вошла в систему и запустила текстовый редактор. Присутствие Сони, должно быть, каким-то образом повлияло на демона в машине, потому что $DSW в DBCalc изменилась, и моя программа прерывания распечатала статус приложения! Наконец то! Я остановил программу и нашел строку кода, на которой она изменилась. Строка гласила:

   MOV R1, R4

Приложение копировало целое число из одного регистра в другой! Подобная операция теоретически не может изменить никакие ячейки памяти. Я выключил терминал и вышел на улицу. Я шел и шел по снегу, пытаясь найти объяснение невозможному. И вдруг я остановился как вкопаный. Меня остановила следующая идея: моя программа могла быть выгружена из памяти, когда Соня запустила текстовый редактор . Я поспешил обратно в офис и начал читать всю документацию о механизме свопинга в RSX-11M, которую только мог найти. Вскоре я наткнулся на такой абзац:

При выгрузке процесса из памяти система использует первые 16 байтов образа процесса для сохранения контекста процесса.

Вот вам и «полностью изолирован от системы»! $DSW, адрес которого 14, будет непредсказуемо меняться всякий раз, когда DBCalc выгружается из памяти!

Я переключился с использования $DSW на какой-то другой адресом со значением больше 16. Вот и все!

Учи матчасть!

Не по существу

There is a lot of cursing going on in the programmers' vernacular. And somehow it's completely acceptable to use these expressions in everyday discourse and even in writing. Here are some egregious examples:

KISS Principle
"Keep it simple, stupid!", «Проще надо, тупой!» - выражение, используемое в разработке программного обеспечения, когда предлагаемое решение чрезмерно запутано или абстрактно.
RTFM
Read the fucking manual! Буквально: "Читай ебаное руководство!" Обычно переводится: "Учи матчасть".
BFS
Brain Fuck Scheduler. "Планировщик, который ебет мозги." Это важная часть ОС Linux. Он был некоторое время включен в Android.

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

Оставьте комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *