ТипобезпечністьТипобезпечність (англ. type safety) — властивість мови програмування, яка характеризує безпеку та надійність у застосуванні її системи типів. Систему типів називають безпечною (англ. safe) або надійною (англ. sound), якщо у програмах, які пройшли перевірку узгодження типів (англ. well-typed programs або well-formed programs), виключено можливість виникнення помилок узгодження типів під час виконання[en][1][2][3][4][5][6]. Помилка узгодження типів або помилка типізації (англ. type error) — неузгодженість типів компонентів виразів у програмі, наприклад спроба використати ціле число як функцію[7]. Пропущені помилки узгодження типів на етапі виконання можуть спричиняти баги і навіть креші програм. Безпека мови не є синонімом повної відсутності багів, але щонайменше вони стають досліджуваними в рамках семантики мови (формальної або неформальної)[8]. Надійні системи типів також називають сильними (англ. strong)[1][2], але трактування цього терміна часто пом'якшують, крім того, його часто застосовують до мов, які здійснюють динамічну перевірку узгодження типів (сильна та слабка типізація). Іноді безпечність розглядають як властивість конкретної програми, а не мови, якою її написано — тому що деякі типобезпечні мови дозволяють обійти або порушити систему типів, якщо програміст практикує мізерну типобезпеку. Поширена думка, що такі можливості на практиці є необхідними, але це вигадка[9]. Поняття про «безпечність програми» є важливим у тому сенсі, що реалізація безпечної мови сама може бути небезпечною. Розкрутка компілятора вирішує цю проблему, забезпечуючи мові безпечність не лише в теорії, але й на практиці. ПодробиціРобіну Мілнеру належить вираз «Програми, що пройшли перевірку типів, не можуть „збитися зі шляху істинного“»[10]. Тобто, безпечна система типів запобігає свідомо помилковим операціям, пов'язаним із хибними типами. Наприклад, вираз Крім того, інтенсивне використання механізмів визначення нових типів запобігає логічним помилкам, які походять із семантики різних типів[5]. Наприклад, і міліметри, і дюйми є одиницями довжини і можуть бути подані цілими числами, але буде помилкою віднімати дюйми від міліметрів, і розвинена система типів не допустить цього (зрозуміло, за умови, що програміст використовує для значень, виражених у різних одиницях, різні типи даних, а не описує і ті, й інші як змінні цілого типу). Іншими словами, безпечність мови означає, що мова захищає програміста від його власних можливих помилок[9]. Багато мов системного програмування (наприклад, Ада, Сі, C++) передбачають ненадійні (англ. unsound) або небезпечні (англ. unsafe) операції, призначені для можливості порушити (англ. violate) систему типів (див. Зведення типів і Каламбур типізації). В одних випадках це допускається лише в обмежених частинах програми, в інших — не відрізняється від добре типізованих операцій[11]. У мейнстримі[уточнити] нерідко поняття типобезпеки звужують до «безпечності типів щодо доступу до пам'яті» (англ. memory type safety), що означає, що компоненти об'єктів одного агрегатного типу не можуть звертатися до комірок пам'яті, виділених під об'єкти іншого типу. Безпека доступу до пам'яті означає заборону можливості скопіювати довільний бітовий ланцюжок з однієї ділянки пам'яті в іншу. Наприклад, якщо мова передбачає тип Надійні статичні системи типів консервативні (надлишкові) в тому сенсі, що відкидають навіть програми, які виконалися б коректно. Причина цього полягає в тому, що для будь-якої тюрінг-повної мови, множина програм, які можуть породжувати помилки узгодження типів під час виконання, алгоритмічно нерозв'язна (див. Проблема зупинки)[12][13]. Як наслідок, такі системи типів забезпечують ступінь захисту, суттєво вищий, ніж це необхідно для забезпечення безпеки доступу до пам'яті. З іншого боку, безпечність деяких дій неможливо довести статично, її слід контролювати динамічно (наприклад, індексація масиву з довільним доступом). Такий контроль може здійснюватися або середовищем виконання[en] самої мови, або безпосередньо функціями, що реалізують подібні потенційно небезпечні операції. Сильно динамічно типізовані мови (наприклад, Лісп Приклади безпечних мовАдаАда (найбільш типобезпечна мова в сімействі Паскалю) орієнтована на розробку надійних вбудовуваних систем, драйверів та інші завдання системного програмування. Для реалізації критичних секцій Ада надає низку небезпечних конструкцій, імена яких зазвичай починаються з Мова SPARK є підмножиною Ади. З нього усунуто небезпечні можливості, але додано можливості проєктування за контрактом. SPARK виключає можливість виникнення завислих вказівників за допомогою виключення можливості динамічного виділення пам'яті. Статично перевірювані контракти додано до Ada2012. Гоар у тюрінгівській лекції стверджував, що задля забезпечення надійності мало статичних перевірок — надійність насамперед є наслідком простоти[15] . Тоді ж він передбачив, що складність Ади спричинить катастрофи. BitCBitC — гібридна мова, що комбінує низькорівневі можливості Сі з безпекою Standard ML CycloneДослідницька мова Cyclone є безпечним діалектом мови C, що запозичує багато ідей з ML RustБагато ідей Cyclone втілено в мові Rust. Крім сильної статичної типізації у мову додано статичний аналіз часу життя вказівників, заснований на концепції «володіння». Реалізовано статичні обмеження, що блокують потенційно некоректний доступ до пам'яті: відсутні нульові вказівники, неможлива поява неініціалізованих та деініціалізованих змінних, заборонено спільне використання змінюваних змінних кількома завданнями. Перевірка на вихід за межі масиву є обов'язковою. HaskellHaskell (нащадок ML Haskell також надає можливості слабкої динамічної типізації, і до стандарту мови включено реалізацію механізму обробки винятків за допомогою цих можливостей. Її використання може призводити до аварійного завершення програм, за що Роберт Гарпер[en] назвав Haskell виключно небезпечним[18]. Він вважає неприйнятним той факт, що винятки мають тип, визначений користувачем у контексті класу типів Лісп«Чистий» (мінімальний) Лісп є однотиповою мовою (тобто будь-яка конструкція належить до типу «S-вираз»)[19], хоча навіть перші промислові реалізації Lisp передбачали принаймні певну кількість атомів[en]. Сімейство нащадків мови Lisp утворюють переважно динамічно типізовані мови, але існують статично типізовані і такі, що поєднують обидві форми типізації. Common Lisp є сильно динамічно типізованою мовою, але передбачає можливість явно (маніфестно[en]) призначати типи (а компілятор SBCL здатний сам їх виводити), однак, ця можливість використовується для оптимізації та посилення динамічних перевірок і не означає статичної типобезпеки. Програміст, з метою підвищення швидкодії, може встановити для компілятора знижений рівень динамічних перевірок, і тоді скомпільовану програму вже не можна вважати безпечною[20][21]. Мова Scheme також є динамічно типізованою мовою, але компілятор Stalin[en] статично виводить типи, використовуючи їх для агресивної оптимізації програм. Мови «Typed Racket» (розширення Racket Scheme) і Shen типобезпечні. Clojure поєднує сильний динамічний та статичний контроль типів. MLСпочатку мова ML розроблялася як інтерактивна система доведення теорем, і лише згодом стала самостійною компільованою мовою загального призначення. Багато зусиль було приділено доведенню надійності параметрично-поліморфній системі типів Гіндлі — Мілнера, що лежить в основі ML. Доведення надійності побудовано для чисто функціональної підмножини («Fuctional ML»), розширення посилальними типами («Reference ML»), розширення винятками («Exception ML»), для мови, що об'єднує всі ці розширення («Core ML») і нарешті, його розширення першокласними продовженнями («Control ML»), спершу мономорфними, потім поліморфними[2]. Наслідком цього стало те, що нащадки ML найчастіше апріорі вважаються типобезпечними, навіть попри, що деякі з них відкладають значущі перевірки на етап виконання програми (OCaml), або відхиляються від семантики, для якої побудовано доведення надійності, і містять небезпечні можливості явно (Haskell Деякі нащадки ML також є інструментами інтерактивного доведення (Idris[en], Mercury, Agda). Багато хто з них, хоча й могли б використовуватися для безпосередньої розробки програм із доведеною надійністю, частіше використовуються для верифікації програм іншими мовами — з таких причин, як висока трудомісткість використання, низька швидкодія, відсутність FFI[en] тощо. Серед нащадків ML із доведеною надійністю виділяються як орієнтовані на промислове застосування мови Standard ML Standard MLМова Standard ML (старша в сімействі мов ML Однак деякі реалізації (SML/NJ[en], Mythryl, MLton[en]) включають нестандартні бібліотеки, що надають певні небезпечні операції (їх ідентифікатори починаються з Мова Alice, розширення Standard ML, надає можливості сильної динамічної типізації. Див. також
Примітки
Література
Посилання
|
Portal di Ensiklopedia Dunia