<!DOCTYPE article PUBLIC "-//NLM//DTD JATS (Z39.96) Journal Archiving and Interchange DTD v1.0 20120330//EN" "JATS-archivearticle1.dtd">
<article xmlns:xlink="http://www.w3.org/1999/xlink">
  <front>
    <journal-meta />
    <article-meta>
      <title-group>
        <article-title>ЗАСІБ СТАТИЧНОГО АНАЛІЗУ .NET ПРОГРАМ ЗА ДОПОМОГОЮ ПЕРЕПИСУВАЛЬНИХ ПРАВИЛ</article-title>
      </title-group>
      <contrib-group>
        <aff id="aff0">
          <label>0</label>
          <institution>CompilationUnit( UsingDeclaration(Name(cons(Identifier(“System”), NIL)))</institution>
          ,
          <addr-line>TypeDeclaration(Modifiers(1, NIL), ClassOrInterfaceDeclaration(class, Identifier(“A”), NIL, DerivesList(NIL)</addr-line>
          ,
          <country country="US">USA</country>
        </aff>
      </contrib-group>
      <pub-date>
        <year>2019</year>
      </pub-date>
      <fpage>0000</fpage>
      <lpage>0003</lpage>
      <abstract>
        <p>Розроблено програмний засіб, який виявляє в C#-програмах проблеми ресурсоспоживання з погляду роботи з файлами за допомогою переписувальних правил. Для цього використана система TermWare, яку можна легко вбудовувати в ті програмні системи, які побудовані на JVM. Для того, щоб працювати з C#-програмами, був реалізований спеціальний плагін до TermWare, який перекладає програми на мову термів. Цей плагін використовує компілятор Roslyn, який дозволяє знаходити синтаксичні помилки в програмах і дозволяє зосередитися на основній задачі - генерації термів з вихідного коду. Також описаний практичний додаток системи TermWare - статичний аналізатор, який знаходить проблеми відкритих-закритих файлів. Ключові слова: аналіз ресурсоспоживання, генератор термів, правила переписування, TermWare. Разработано программное средство, который находит в C#-программах проблемы ресурсопотребления з точки зрения работы с файлами с помощью переписывающих правил. Для этого была использована система TermWare, который можно легко встраивать в программные средства, которые работают на JVM. Для того, чтобы работать с C#-программами был реализованный специальный плагин для TermWare, который переводит программы на язык термов. Этот плагин использует компилятор Roslyn, который позволяет находить синтаксические ошибки в программах и сосредоточиться на основной задаче - генерации термов с исходного кода. Также описано практическое приложение системы TermWare статический анализатор, который находит проблемы открытых-закрытых файлов. Ключевые слова: анализ ресурсопотребления, генератор термов, правила переписывания, TermWare. A software tool that finds problems of resource consumption in case of work with files using rewriting rules was implemented. To reach the goal, the TermWare system, which could be embedded into those systems running on JVM, was used. TermWare system is a term processing system that provides a language for describing rewriting rules that operate on a data structure called term and a rules interpreter for transforming terms. In order to work with C#-programs, the special plugin for TermWare, which helps to generate appropriate terms from source code, was developed. Roslyn compiler was embedded in the plugin to make an analysis of the program. Roslyn provides definitive syntax and sematic code analysis API for C# and Visual Basic programming languages. Those, Roslyn allows users to find syntax errors in programs and focus on the primary task of generating terms from source code during the development of the plugin. Other methods and basic approaches to solving a problem of resource consumption were found, such as runtime inspection, and the advantages and disadvantages of those ways were described. The description of the problem includes the reasons for those issues being appeared and the states of the program that needs to be generated and analyzed were illustrated with the examples with syntax constructions of the C# language. Also, a practical application based on the TermWare system - a static analyzer that finds problems of open-close files, was implemented. The example of rules to find the problem of open-close files in the C#-program was illustrated in the article.Key words: analysis of resource consumption, terms generator, rewriting rules, TermWare.</p>
      </abstract>
    </article-meta>
  </front>
  <body>
    <sec id="sec-1">
      <title>-</title>
      <p>мові Java вже існують досить багато систем, з якими програми можуть взаємодіяти, в роботі головна
новизна – це використання TermWare на програмах, розроблених на мові C# для аналізу вихідного
програмного коду. Таким чином розроблений продукт може бути використаний для великої кількості систем
на ринку праці.</p>
      <p>
        Актуальність роботи аргументується наступним чином: по-перше, як було згадано раніше, техніка
переписувальних правил є дуже популярною. По-друге, верифікація та аналіз програм з погляду
ресурсоспоживання позбавить розробників від потреби додаткової перевірки коду, покращить якість, а також
запобіжить майбутнім помилкам в роботі програмного забезпечення. По-третє, проблема відкритих-закритих
файлів є новою для C#-програм, тому що навіть один з найбільш використовуваних додатків (Resharper [
        <xref ref-type="bibr" rid="ref4">4</xref>
        ])
ігнорує такі помилки у вихідному коді.
      </p>
      <p>Мета роботи – це розробка аналізатора C#-програм, яка вирішує так звану проблему
відкритихзакритих файлів за допомогою переписувальних правил.</p>
      <p>Задачі на роботу такі:
- дослідити можливість та спосіб використання TermWare для мови C#;
- розробити інтерпретатор, який би TermWare міг використовувати для переведення з C#-програми на
мову термів;</p>
      <p>- розробити сторонній додаток, який би аналізував мову термів та знаходив би проблему відкритих/
закритих файлів.</p>
      <p>Матеріал роботи організований наступним чином: в першому розділі описана система TermWare та
принцип роботи з нею; в другому розділі описана реалізація інтерпритатора мови C# на мову термів; в третьому
розділі описаний принцип роботи аналізатора та вирішення проблеми відкритих/закритих файлів; останній
розділ розкриває майбутні плани та можливі наступні кроки.
Опис системи TermWare</p>
      <p>Для аналізу C#-програми використовується система переписувальних правил TermWare. TermWare – це
система символьних обчислень для розробки динамічних додатків на основі правил переписування, яка працює
з алгеброю термів, яка складається з виразів виду f ( ).</p>
      <p>TermWare дуже зручна система переписування, оскільки її можна вбудовувати в інші Java програми за
допомогою TermWare API.</p>
      <p>
        Основні області застосування даної системи – це:
- побудова проблемно-орієнтованих мов надвисокого рівня;
- системи комп’ютерної алгебри;
- аналіз і перетворення формальних моделей різного роду;
- програмна інженерія [
        <xref ref-type="bibr" rid="ref3">3</xref>
        ].
      </p>
      <p>
        Для завдання перетворень використовуються правила Termware, тобто конструкції виду source
[condition] -&gt; destination [action]. Тут source – вихідний терм (зразок для пошуку), condition – умова
застосування правила, destination – перетворений терм, action – додаткове дія при спрацьовуванні правила.
Кожен з 4 компонентів правила може містити змінні (які записуються у вигляді $ var), що забезпечує спільність
правил. Компоненти condition і action є необов'язковими. Вони можуть виконувати довільний процедурний код,
зокрема використовувати додаткові дані про програму [
        <xref ref-type="bibr" rid="ref5">5</xref>
        ].
Опис генератора термів для C#-програм
      </p>
      <p>
        Для роботи з TermWare був розроблений генератор термів для C#-програм, описаний в роботі [
        <xref ref-type="bibr" rid="ref5">5</xref>
        ]. Але
розробка з тієї роботи не є ідеальною, тому що в ній використовувалися сторонні засоби для роботи з
компілятором Roslyn, який розроблений компанією Microsoft, та використовується повсюдно.
      </p>
      <p>
        Ця проблема була вирішена в цій версії генератора термів. По-перше, всі сторонні засоби як proxygen [
        <xref ref-type="bibr" rid="ref6">6</xref>
        ],
javonet [
        <xref ref-type="bibr" rid="ref7">7</xref>
        ] та інші були замінені на механізм серіалізації та десериалізації. Якщо говорити більш детально, то
проблема використання сторонніх засобів полягала в складності розробки програми з API, які були
представлені для користування, і внаслідок – незручний спосіб використання самого генератора термів. А
технічна проблема полягала в тому, що Roslyn запускається на CLR, а TermWare – на JVM. Тому результат
парсеру, який міг би бути використаним для перевірки правильності синтаксису, а також синтаксичне дерево,
раніше були отримані за допомогою сторонніх програм.
      </p>
      <p>
        Оновлена версія працює за допомогою сериалізації/десериалізації. Але механізм передбачає лише
синтаксичний аналіз за допомогою Roslyn та отримання результатів: правильний чи неправильний синтаксис в
програмі, яка була подана на вхід. Структурно вихідний файл, який потім десериалізується в Java виглядає так:
"Errors": [
"(1,23): error CS1733: Expected expression",
"(1,23): error CS1002: ; expected"
Якщо говорити більш детально, то об’єкт компілятора CompilationUnitSyntax має важливе поле
Diagnostic, за допомогою якого можна дізнатись всі синтаксичні проблеми коду.
Після того як за допомогою Roslyn [
        <xref ref-type="bibr" rid="ref8">8</xref>
        ] програма виконала синтаксичний аналіз, JSON-файл з результатами
десеріалізується в середовищі JVM і далі починається процес побудови абстрактного синтаксичного дерева та
генерування термів.
      </p>
      <p>На рисунку показана приблизна та спрощена структура переробленого генератора термів.</p>
      <p>Рисунок. Спрощена діаграма генератора термів
Тепер можна подивитись один з прикладів переведення C#-програми в мову термів. Допустимо, що є
наступний клас:
using System;
namespace Program {
public class A
{
string Method()
{
}
}
}</p>
      <p>return “Hello World!”;
Його інтерпретація у вигляді термального дерева зроблена наступним чином:</p>
    </sec>
    <sec id="sec-2">
      <title>ClassOrInterfaceBody(cons(</title>
      <p>cons(ClassOrInterfaceBodyDeclaration(</p>
      <p>Modifiers(0),
MethodDeclaration(NIL,</p>
      <p>String,</p>
      <p>MethodDeclarator(Identifier(“M”), FormalParameters(NIL)), NIL,
Block(cons(ReturnStatement(StringLiteral(“Hello World”)), NIL)))), NIL)
)))))
Одним з недоліків, які пов’язані з розробленим генератором термів, але ще не виправлених в цій версії –
це підтримка версійності мови. На даний момент, цей генератор термів підтримує C# 1-5 версії. Тому в
майбутніх роботах генератор буде дороблений таким чином, щоб вона підтримувала всі версії мови, включно
останню, яка вийшла нещодавно.</p>
      <p>Ще одним покращенням, яка буде в наступній версії – це перехід до системи TermWare-3.
Опис аналізатора ресурсоспоживання програм</p>
      <p>
        Одним з можливих способів вирішення проблеми ресурсоспоживання є використання переписувальних
правил. TermWare має можливість генерувати не лише термальні абстрактні синтаксичні дерева, а й можливість
будувати так звані модельні терми – де до кожного елемента синтаксичного дерева добавлений ще один
елемент, який називається контекст. Більш детальний опис модельних термів наведений в роботі [
        <xref ref-type="bibr" rid="ref9">9</xref>
        ], який і
взятий в основу цієї роботи.
      </p>
      <p>Є багато інших способів аналізувати проблеми в коді, зокрема проблему ресурсоспоживання програм.
Наприклад, одним з найвідоміших прикладів аналізу коду є Resharper. Для аналізу слабких сторін вихідного
коду Resharper використовує статичний аналіз. Переписувальні правила можуть дати більше, оскільки
користувач може зробити додатковий аналіз терму.</p>
      <p>Ще одним мінусом Resharper в контексті даної роботи є те, що даний конкурент не має вирішення
проблеми відкритих-закритих файлів. Але звісно, що функціонал Resharper поки що переважає результат цієї
статті. Це і попередження в місцях, де вихідних код можна оптимізувати з різних боків, і аналіз стилю коду та
ін. Але, задачею є більш глибокий аналіз програми з погляду саме ресурсоспоживання.</p>
      <p>
        Іншим способом аналізу C#-програм є перевірка під час виконання програми (runtime inspection). Таку
можливість використання показників дає Visual Studio, починаючи з останніх версій. Це можливість
подивитись на використання програмою CPU або безпосердньо пам’яті за допомогою Diagnostic Tools [
        <xref ref-type="bibr" rid="ref10">10</xref>
        ].
Мінусом цього способу є можливість такого аналізу лише в етапі запуску програми в Visual Studio, також
великі витрати з погляду часу для того, щоб розробник спершу аналізував дані, які він отримав за допомогою
цього інструментарію, а потім і локалізував місце, де ця проблема виникає. Також одним з мінусів такого
підходу є необхідність тестування всіх можливих ситуацій, в яких проблема витоку ресурсів може виникнути.
Серед плюсів цього способу в порівнянні з результатом цієї статті є те, що це більш універсальний спосіб
знаходження проблеми ресурсоспоживання.
      </p>
      <p>В роботі буде наведена ілюстрація підходу щодо вирішення проблеми витоку ресурсів. Зазвичай, виток
ресурсів відбувається, коли програма бере ресурси в операційній системі чи посторонньому програмному
забезпеченні. В C#-програмах такі класи, які потрібно «закривати» перед тим, як метод закінчить своє
виконання, можна ідентифікувати за допомогою інтерфейсів, які вони реалізовують.</p>
      <p>Наприклад:
- IDisposable – забезпечує механізм звільнення некерованих ресурсів (такі класи, як FileStream,
MemoryStream та ін. реалізовують саме цей інтерфейс);</p>
      <p>- IDataReader – забезпечує засіб считування одного або безліч потоків, призначених лише для прямої
передачі наборів результатів, отриманих виконанням команди у джерелі даних (яскравим прикладом
використання цього інтерфейсу є класс SqlDataReader, який використовується для отримання результатів
SQLзапиту і після його використання особливо важливим є метод Close()).</p>
      <p>Для аналізу таких даних, потрібно для кожної мовної конструкції генерувати множину станів, яку й
аналізатор буде обробляти. Для цього є декілька станів обробки:</p>
      <p>
        - Opened(expression, location) – визначає місце (location) та в C#-програмі змінна або аргумент
(expression), де потенційно можливий витік ресурсів. При цьому цей стан буде трактуватися, як ще не закритий;
- Cons(s1, s2) – позначає те, що один стан виникає після другого стану;
- Return(s) – цим символом позначається стан, при якому програмне забезпечення закінчило своє
виконання;
- Cond(v, s) – означає, що якщо виконується умова v, то програма можливо буде в стані s;
- s1 || s2 – означає, що можливе одне з двух станів, але точно невідомо, яке саме з них;
- s1 &amp;&amp; s2 – означає, що програма в стані s1 або s2 [
        <xref ref-type="bibr" rid="ref9">9</xref>
        ].
      </p>
      <p>Програма вважається коректною, тобто аналізатор не знайшов виток ресурсів, якщо фінальний стан не
містить Opened().</p>
      <p>Наступний код написаний як приклад и виводить зміст текстового файлу на екран консольного додатку:
public void OutputFileContents(string path)
{
if (string.IsNullOrEmpty(path))
{</p>
      <p>throw new ArgumentNullException(nameof(path));
}
}
try
{
}
if (!File.Exists(path))
{
}
catch (Exception ex)
{</p>
      <p>Console.WriteLine($"File does not exist in the current path: {path}");
return;
var fs = File.OpenRead(path);
StreamReader reader = new StreamReader(fs);
string fileContents = reader.ReadToEnd();
Console.WriteLine(fileContents);
fs.Dispose();
Console.WriteLine($"The program thrown an exception: {ex.Message}");
return;
}
}
using(var fs = new FileStream(path))
{</p>
      <p>// expression body
Наведений приклад є некоректним з погляду ресурсоспоживання, тому що при помилці (викидання
«винятку» на етапі читання з файлу в FileStream або StreamReader), FileStream або StreamReader не будуть
закриті, що може призвести до неочікуваних наслідків. Тобто серед всіх виразів найважливішу роль в аналізі
витоків пам’яті грають створення нових об’єктів та визови методів.</p>
      <p>При створенні нових об’єктів не можна стовідсотково говорити про проблеми витоку пам’яті навіть
якщо створений об’єкт реалізують інтерфейси IDisposible або IDataReader, оскільки в C# є конструкції такого
типу:</p>
      <p>Такі вирази рівноцінні виразу try, catch, finally, де в останньому блоці викликається Dispose() метод. Саме
тому цей вираз можливо використати тільки у тому випадку, коли створюваний клас реалізовує IDisposable.
Тепер розглянемо правила обробки виразу у тих випадках, коли створюється об’єкт на мові C#:</p>
    </sec>
    <sec id="sec-3">
      <title>CheckExpression($var,</title>
      <p>AllocationExpressionModel(TypeRef($tname,$type),$arguments,$ctx),$state)
[
$ctx.subtypeOrSame($type,
$ctx.resolveFullClassName("System.IDisposable") &amp;&amp;
!($type.getAttribute("NotDisposable")==true)) ||
$ctx.subtypeOrSame($type,</p>
      <p>$ctx.resolveFullClassName("System.System.Data.IDataReader")) &amp;&amp;
!($type.getAttribute("NotDisposable")==true)
]-&gt; CheckAllocationNotProxy($var,$type,$arguments,$ctx,$state)
!-&gt; CheckExpressions($arguments,$state),
CheckAllocationNotProxy($var,$type,$arguments,$ctx,$state)</p>
      <p>-&gt; ((
))
? cons(OPENED($var,$ctx.getFileAndLine()),$state)
: CheckExpressions($var,$arguments,$state)
!($type.getAttribute("DisposableProxy")==true) ||
apply(openclose::DisposableArguments, apply(NormalizeExpressions,$arguments))
Для початку дивимось на умову subTypeOrSame, який перевіряє, чи є даний клас, який створюється,
успадковує від інтерфейсів IDisposable або IDataReader. Після того, якщо умови виконуються, іде перевірка
на CheckAllocationNotProxy, а він у свою чергу перевіряє, чи встановлений зовнішній атрибут. Якщо
зовнішній атрибут не встановлений, то він додає стан OPENED, в іншому випадку йде перевірка аргументів
конструктора.</p>
    </sec>
  </body>
  <back>
    <ref-list>
      <ref id="ref1">
        <mixed-citation>
          1.
          <string-name>
            <surname>Dershowitz</surname>
            <given-names>N.</given-names>
          </string-name>
          ,
          <string-name>
            <surname>Jouannaud</surname>
            <given-names>J.-P.</given-names>
          </string-name>
          (
          <year>1990</year>
          ). Jan van Leeuwen (ed.).
          <source>Rewrite Systems</source>
          . Handbook of Theoretical Computer Science. B.
          <string-name>
            <surname>Elsevier</surname>
          </string-name>
          . P.
          <volume>243</volume>
          -
          <fpage>320</fpage>
          .
        </mixed-citation>
      </ref>
      <ref id="ref2">
        <mixed-citation>
          2.
          <string-name>
            <surname>Winkler</surname>
            <given-names>T.</given-names>
          </string-name>
          <article-title>Programming in OBJ and Maude</article-title>
          ,
          <source>in Functional Programming, Concurrency, Simulation and Automated Reasoning, International Lecture Series</source>
          <year>1991</year>
          -1992, McMaster University, Hamilton, Ontario, Canada, by ed.
          <source>Peter Lauer</source>
          , Springer Verland. LNCS. P.
          <volume>229</volume>
          -
          <fpage>277</fpage>
          .
        </mixed-citation>
      </ref>
      <ref id="ref3">
        <mixed-citation>
          3.
          <string-name>
            <surname>Termware</surname>
          </string-name>
          . [Online] Available from: http://www.gradsoft.ua/products/termware_rus.
          <source>html [Accessed: 18 February</source>
          <year>2020</year>
          ]
        </mixed-citation>
      </ref>
      <ref id="ref4">
        <mixed-citation>
          4.
          <string-name>
            <surname>Resharper</surname>
          </string-name>
          . [Online] Available from: https://www.jetbrains.com/resharper/ [Accessed: 18
          <source>February</source>
          <year>2020</year>
          ]
        </mixed-citation>
      </ref>
      <ref id="ref5">
        <mixed-citation>
          5.
          <string-name>
            <surname>Mamedov</surname>
            <given-names>T.</given-names>
          </string-name>
          <string-name>
            <surname>Doroshenko</surname>
          </string-name>
          <article-title>A. A method of tuning programs on .NET platform with rewriting rules</article-title>
          .
          <source>Problems of programming</source>
          .
          <year>2019</year>
          . N 2. P.
          <volume>11</volume>
          -
          <fpage>16</fpage>
          . (in Ukrainian).
        </mixed-citation>
      </ref>
      <ref id="ref6">
        <mixed-citation>
          6.
          <fpage>JNI4NET</fpage>
          . [Online] Available from: http://jni4net.com/ [Accessed: 18
          <source>February</source>
          <year>2020</year>
          ]
        </mixed-citation>
      </ref>
      <ref id="ref7">
        <mixed-citation>
          7. Javonet - Java to .
          <source>NET Bridge</source>
          ,
          <string-name>
            <surname>C#</surname>
          </string-name>
          , VB.NET. [Online] Available from: https://www.javonet.
          <source>com/ [Accessed: 18 February</source>
          <year>2020</year>
          ]
        </mixed-citation>
      </ref>
      <ref id="ref8">
        <mixed-citation>
          8.
          <string-name>
            <surname>Roslyn</surname>
          </string-name>
          . [Online] Available from: https://github.com/dotnet/roslyn [Accessed: 18
          <source>February</source>
          <year>2020</year>
          ]
        </mixed-citation>
      </ref>
      <ref id="ref9">
        <mixed-citation>
          9.
          <string-name>
            <surname>Shevchenko</surname>
            <given-names>R.</given-names>
          </string-name>
          &amp;
          <article-title>Doroshenko A. Using term rewriting systems for source code analysis</article-title>
          .
          <source>Problems of programming</source>
          .
          <year>2008</year>
          . №2-
          <fpage>3</fpage>
          , P.
          <fpage>305</fpage>
          -
          <lpage>312</lpage>
          . (in Russian).
        </mixed-citation>
      </ref>
      <ref id="ref10">
        <mixed-citation>
          10.
          <string-name>
            <surname>Quickstart</surname>
          </string-name>
          : First look at profiling Tools [Online] Available from: https://docs.microsoft.com/en-us/dotnet/api/system. data.
          <source>idatareader?view=netfnetframe-4.8 [Accessed: 18 February</source>
          <year>2020</year>
          ]
          <article-title>Про авторів: Мамедов Турал Алірзайович, аспірант Інституту програмних систем НАН України</article-title>
          .
        </mixed-citation>
      </ref>
      <ref id="ref11">
        <mixed-citation>
          http://orcid.org/0000-0003-3029-5834, Дорошенко Анатолій Юхимович,
          <article-title>доктор фізико-математичних наук, професор, завідувач відділу теорії комп'ютерних обчислень Інституту програмних систем НАН України, професор кафедри автоматики і управління в технічних системах НТУУ "КПІ імені Ігоря Сікорського"</article-title>
          .
        </mixed-citation>
      </ref>
      <ref id="ref12">
        <mixed-citation>http://orcid.org/0000-0002-8435-1451, Шевченко Руслан Сергійович, підприємець.</mixed-citation>
      </ref>
      <ref id="ref13">
        <mixed-citation>
          http://orcid.org/0000-0002-
          <fpage>1554</fpage>
          -
          <year>2019</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref14">
        <mixed-citation>
          <article-title>E-mail: tural.mamedov@outlook.com, doroshenkoanatoliy2@gmail</article-title>
          .com, ruslan@shevchenko.kiev.ua
        </mixed-citation>
      </ref>
    </ref-list>
  </back>
</article>