{"id":25852574,"url":"https://github.com/rsashka/memsafe","last_synced_at":"2025-04-09T05:08:32.678Z","repository":{"id":270664114,"uuid":"909481223","full_name":"rsashka/memsafe","owner":"rsashka","description":"C++ Memory safety (memsafe) single-header libraries and Clang compiler plugin for safe C++, which reduces errors for reference data types and safe memory management without breaking backward compatibility with old C++ code.","archived":false,"fork":false,"pushed_at":"2025-03-21T20:58:49.000Z","size":395,"stargazers_count":246,"open_issues_count":7,"forks_count":8,"subscribers_count":9,"default_branch":"main","last_synced_at":"2025-04-02T02:12:03.643Z","etag":null,"topics":["cpp","cpp20","header-only","memory-safety","memsafe","research"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"lgpl-2.1","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rsashka.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-12-28T20:43:34.000Z","updated_at":"2025-04-02T00:15:35.000Z","dependencies_parsed_at":"2025-02-28T21:31:51.009Z","dependency_job_id":null,"html_url":"https://github.com/rsashka/memsafe","commit_stats":null,"previous_names":["rsashka/memsafe"],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rsashka%2Fmemsafe","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rsashka%2Fmemsafe/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rsashka%2Fmemsafe/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rsashka%2Fmemsafe/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rsashka","download_url":"https://codeload.github.com/rsashka/memsafe/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247980837,"owners_count":21027808,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cpp","cpp20","header-only","memory-safety","memsafe","research"],"created_at":"2025-03-01T14:20:11.592Z","updated_at":"2025-04-09T05:08:32.670Z","avatar_url":"https://github.com/rsashka.png","language":"C++","readme":"## Memory Safety for C++\n\nThere are many projects that want to make C++ a \"safer\" programming language.\nBut making changes to the language syntax usually breaks backward compatibility with older code written earlier.\n\nThis project contains code for a library header file and compiler plugin for *safe C++*, \nwhich fixes C++'s core problems with memory and reference data types without breaking backwards compatibility with old legacy code.\n\n### Motivation\n\n\u003e The global problem of the C and C++ languages ​​is that the pointer to the allocated memory block in the heap is an ordinary address\n\u003e in RAM and has no connection with variables - pointers that are in local variables on the stack,\n\u003e and whose lifetime is controlled by the compiler.\n\u003e\n\u003e The second, no less serious problem, which often leads to undefined behavior (Undefined Behavior)\n\u003e or data races (Data Races) is access to the same memory area from different threads at the same time.\n\nThere are many projects that want to make C++ a \"safer\" programming language.\nBut making changes to the language's syntax usually breaks backward compatibility with older code written earlier.\n\nThis project contains a header only library and a compiler plugin for *safe C++*,\nwhich fixes the main problems of C++ when working with memory and reference data types\nwithout breaking backward compatibility with old legacy code (it uses C++20, but can be downgraded to C++17 or C++11).\n\nThe method of marking objects in the source code and configuring the plugin's operation parameters\nis performed using C++ attributes, which is very similar to the security profiles\n[p3038](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p3038r0.pdf) by Bjarne Stroustrup\nand [P3081](https://isocpp.org/files/papers/P3081R0.pdf) by Herb Sutter,\nbut does not require the creation of a new standard (it is enough to use the existing C++20).\n\n\n### Concept\n\nThe concept of safe memory management consists of implementing the following principles:\n- If the program is guaranteed to have no strong cyclic references\n(references of an object to itself or cross-references between several objects),\nthen when implementing the [RAII](https://en.wikipedia.org/wiki/Resource_acquisition_is_initialization) principle\n*automatic memory release will be performed **always***.\n- The absence of cyclic references in the program code can only be guaranteed by prohibiting them at the level of *types* (class definitions).\n- The problem of data races when accessing memory from different threads is solved by using inter-thread synchronization objects,\nand to prevent errors in logic, only one operator (function call) should be used to capture\nthe synchronization object and dereference the reference at the same time in one place.\n\nThe concept of safe memory management is ported to C++ from the [NewLang](https://newlang.net/) language,\nbut is implemented using the standard C++ template classes *shared_ptr* and *weak_ptr*.\n\nThe main difference when working with reference variables, compared to shared_ptr and weak_ptr, \nis the method of dereferencing references (getting the address of an object), \nand the method of accessing the object, which can be done not only by dereferencing the reference \"*\", \nbut also by capturing (locking) the reference and storing it in a temporary variable, \nthe lifetime of which is limited and automatically controlled by the compiler, \nand through it direct access to the data itself (the object) is carried out.\n\nSuch an automatic variable is a *temporary* strong reference holder and is similar to\n[std::lock_guard](https://en.cppreference.com/w/cpp/thread/lock_guard) - a synchronization object holder \nuntil the end of the current scope (lifetime), after which it is automatically deleted by the compiler.\n\n### Implementation\n\nThe implementation of the concept of safe work with memory for C++ consists of two parts: a plugin for Clang and a header file of the library.\n\nClang plugin performs static analysis of C++ code during its compilation. \nIt checks for invalidation of reference types (iterators, std::span, std::string_view, etc.) \nwhen data in the original variable is changed and controls strong **cyclic** references \nat the type level (class definitions) of any nesting **\\***).\n\nThe library file contains template classes that extend the standard *std::shared_ptr* and *std::weak_ptr* \nand add automatic data race protection to them when accessing shared variables from different threads \n(the access control method must be specified when defining the variable, after which the acquisition \nand release of the synchronization object will occur automatically when the reference is renamed).\n*By default, shared variables are created without multi-thread access control \nand have no additional overhead compared to the standard template classes `std::shared_ptr` and `std::weak_ptr`*.\n\nThe library header file also contains options for controlling the analyzer plugin \n(a list of classes that need to be monitored for invalid reference data types is defined).\n\n---\n\n**\\***) - since C++ compiles files separately, and the class (data structure) \ndefinition may be in a different translation unit due to forward declaration,\ntwo passes may be required for the circular reference analyzer to work correctly.\n*First run the plugin with the '--circleref-write -fsyntax-only' option to generate a list of classes with strong references, \nthen a second time with the '--circleref-read' option to perform the analysis. \nOr disable the circular reference analyzer completely with the '--circleref-disable' option.*\n\n\n## Examples\n\nCommand line for compiling a file with clang and using a plugin\n\n```bash\nclang++ -std=c++20 -Xclang -load -Xclang ./memsafe_clang.so -Xclang -add-plugin -Xclang memsafe -Xclang -plugin-arg-memsafe -Xclang circleref-disable _example.cpp\n```\n\n### Output of the plugin with  pointer invalidation control:\n\n```cpp\n    std::vector\u003cint\u003e vec(100000, 0);\n    auto x = vec.begin();\n    vec = {};\n    vec.shrink_to_fit(); \n    std::sort(x, vec.end()); // malloc(): unaligned tcache chunk detected or Segmentation fault\n```\n\n**A fragment of the compiler plugin output with error messages related \nto invalidation of reference variables after changing data in the main variable:**\n\n```bash\n_example.cpp:29:17: warning: using main variable 'vect'\n   29 |                 vect = {};\n      |                 ^\n_example.cpp:30:17: warning: using main variable 'vect'\n   30 |                 vect.shrink_to_fit();\n      |                 ^\n_example.cpp:31:27: error: Using the dependent variable 'x' after changing the main variable 'vect'!\n   31 |                 std::sort(x, vect.end()); // malloc(): unaligned tcache chunk detected or Segmentation fault \n      |                           ^\n```\n\n\n### Example of analyzing classes with recursive references:\n\n```cpp\n\n    class SharedCross2;\n\n    class SharedCross {\n        SharedCross2 *cross2;\n    };\n\n    class SharedCross2 {\n        SharedCross *cross;\n    };\n```\n\nA fragment of the compiler plugin output with error messages when analyzing a class:\n\n```bash\n_cycles.cpp:53:23: error: The class 'cycles::SharedCross' has a circular reference through class 'cycles::SharedCross2'\n   53 |         SharedCross2 *cross2;\n      |                       ^\n_cycles.cpp:57:22: error: The class 'cycles::SharedCross2' has a circular reference through class 'cycles::SharedCross'\n   57 |         SharedCross *cross;\n      |                      ^\n_cycles.cpp:53:23: error: Field type raw pointer\n   53 |         SharedCross2 *cross2;\n      |                       ^\n_cycles.cpp:53:23: error: The class 'cycles::SharedCross' has a circular reference through class 'cycles::SharedCross2'\n_cycles.cpp:57:22: error: Field type raw pointer\n   57 |         SharedCross *cross;\n      |                      ^\n```\n\n\nThe plugin's message level can be limited using a macro or command line argument,\nor after checking the source code, the plugin can be omitted altogether,\nsince it only parses the AST, but does not make any corrections to it.\n\n\n### Full output of plugin messages when compiling the test file `_example.cpp`: \n\n\u003cdetails\u003e\n\u003csummary\u003e Show output: \u003c/summary\u003e\n\n```bash\nclang++-20 -std=c++26 -ferror-limit=500 -Xclang -load -Xclang ./memsafe_clang.so -Xclang -add-plugin -Xclang memsafe -Xclang -plugin-arg-memsafe -Xclang circleref-disable _example.cpp\n\n...\n\n```\n\u003c/details\u003e\n\n\n## Feedback\nIf you have any suggestions for the development and improvement of the project, join or [write](https://github.com/rsashka/memsafe/discussions).\n\n\n---\n\n\n## Безопасная работа с памятью для С++\n\n### Мотивация\n\n\u003e Глобальная проблема языка C++ в том, что указатель на выделенный блок памяти в куче является обычным адресом \n\u003e оперативной памяти и у него отсутствует связь с локальными переменными - указателями, которые находятся на стеке,\n\u003e и временем жизни которых управляет компилятор. \n\u003e \n\u003e Вторая, не менее серьезная проблема, которая часто приводить к неопределенному поведению (Undefined Behaviour) \n\u003e или гонке данных (Data Races) - это доступ к одной и той же области памяти из разных потоков одновременно.\n\nЕсть много проектов, целью которых является превратить С++ более \"безопасный\" язык программирования.\nНо внесение изменений в синтаксис языка обычно нарушает обратную совместимость со старым кодом, который был написан до этого.\n\nДанный проект содержит заголовочный файл библиотеки и плагин компилятора для *безопасного С++*, \nкоторый устраняет основные проблемы С++ при работе с памятью и ссылочными типами данных \nбез нарушения обратной совместимости со старым легаси кодом (используется С++20, но можно понизить до С++17 или С++11).\n\nСпособ маркировки объектов в исходноом коде и настройка параметров работы плагина\nвыполняется с помощью  C++ атрибутов, что очень похоже на профили безопасности \n[p3038](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p3038r0.pdf) от Bjarne Stroustrup \nи [P3081](https://isocpp.org/files/papers/P3081R0.pdf) от Herb Sutter, \nно не требует принятия нового стандарта С++.\n\n### Концепция\n\nКонцепция безопасной работы с памятью заключается в реализации следующих принципов:   \n- Если в программе гарантированно отсутствуют сильные циклические ссылки \n(ссылка объекта на самого себя или перекрестные ссылки между несколькими объектами), \nтогда при реализации принципа [RAII](https://en.wikipedia.org/wiki/Resource_acquisition_is_initialization), \n*автоматическое освобождение памяти будет выполнятся **всегда без исключений***.\n- Гарантировать отсутствие циклических ссылок можно только путем их запрета на уровне *типов* (определений классов).\n- Проблема гонок данных при обращении к памяти из разных потоков решается за счет использования объектов межпотоковой синхронизации.\nЧтобы исключить ошибки в логике для захвата объекта синхронизации и разименования ссылки используются единый оператор (вызов функции).\n\nИзначальная идея безопасной работы с памятью  была взята из языка [NewLang](https://newlang.net/), \nно реализована на базе стандартных шаблонных классов С++ *shared_ptr* и *weak_ptr*.\n\nОсновное отличие новых шаблонов заключается в способе обращения к объекту, \nкоторый может выполняться не только с помощью разименования \"**\\***\", \nно и через захват (блокировку) ссылки с сохранением её во *временную переменную*, \nвремя жизни которой ограничено и автоматически контролируется компилятором,\nи уже через неё получается доступ непосредственный к самим данным (объекту). \n\nТакая автоматическая переменная является *временным* владельцем сильной ссылки и выполняет функции удержания\nобъекта межпотоковой синхронизации в стиле [std::lock_guard](https://en.cppreference.com/w/cpp/thread/lock_guard),\nвремя жизни которого ограничено текущей областью видимости и управляется компилятором автоматически.\n\n### Реализация\n\nРеализация концепции безопасной работы с памятью для С++ состоит из двух частей: плагина для Clang и заголовочного файла библиотеки.\n\nС помощью плагина для Clang выполняется статический анализ С++ кода во время его компиляции.\nВ плагине реализованы проверка инвалидации ссылочных типов (итераторов, std::span, std::string_view и т.д.) при изменении данных в исходной переменной\nи контроль сильных **циклических** ссылок на уровне типов (определений классов) любой вложенности **\\***).\n\nВ файле библиотеки находятся шаблонные классы, расширяющие стандартные *std::shared_ptr* и *std::weak_ptr* \nс автоматической защитой от гонок данных при доступе к общим переменным из разных потоков\n(способ контроля доступа требуется указать при определении переменной, \nпосле чего захват и освобождение объекта синхронизации будут происходить автоматически при разименовании ссылки).\n*По умолчанию общие переменные создаются без контроля многопоточного доступа \nи не имеют дополнительных накладных расходов по стравнению с стандартными шаблонными классами `std::shared_ptr` и `std::weak_ptr`*.\n\nТак же в заголовочным файле библиотеки находятся опции для управления плагином анализатора \n(опредляется список классов, которые необходимо отслеживать для инвалидации ссылочных типов данных).\n\n---\n\n**\\***) - *поскольку C++ компилирует файлы по отдельности, а определение класса (структуры данных)\nможет находиться в другой единице трансляции из-за предварительного объявления,\nдля корректной работы анализатора циклических ссылок может потребоваться два прохода.* \n*Сначала запустить плагин с ключом '--circleref-write -fsyntax-only', чтобы сгенерировать список классов\nс сильными ссылками, затем второй раз с ключом '--circleref-read', чтобы выполнить анализ.\nИли полностью отключить анализатор циклических ссылок с помощью опции '--circleref-disable'.*\n\n## Примеры\n\nКомандная строка компиляции файла с помощью clang с загрузкой плагина\n\n```bash\nclang++ -std=c++20 -Xclang -load -Xclang ./memsafe_clang.so -Xclang -add-plugin -Xclang memsafe -Xclang -plugin-arg-memsafe -Xclang circleref-disable _example.cpp\n```\n\n### Вывод плагина с контролем инвалидации ссылок:\n\n```cpp\n    std::vector\u003cint\u003e vec(100000, 0);\n    auto x = vec.begin();\n    vec = {};\n    vec.shrink_to_fit(); \n    std::sort(x, vec.end()); // malloc(): unaligned tcache chunk detected or Segmentation fault\n```\n\nФрагмент вывода плагина компилятора с сообщениями об ошибках, \nсвязанных с недействительностью ссылочных переменных после изменения данных в основной переменной:\n\n```bash\n_example.cpp:29:17: warning: using main variable 'vect'\n   29 |                 vect = {};\n      |                 ^\n_example.cpp:30:17: warning: using main variable 'vect'\n   30 |                 vect.shrink_to_fit();\n      |                 ^\n_example.cpp:31:27: error: Using the dependent variable 'x' after changing the main variable 'vect'!\n   31 |                 std::sort(x, vect.end()); // malloc(): unaligned tcache chunk detected or Segmentation fault \n      |                           ^\n```\n\n### Пример анализа классов с рекурсивными ссылками:\n\n```cpp\n\n    class SharedCross2;\n\n    class SharedCross {\n        SharedCross2 *cross2;\n    };\n\n    class SharedCross2 {\n        SharedCross *cross;\n    };\n```\n\nФрагмент вывода плагина компилятора с сообщениями об ошибках при анализе класса:\n```bash\n_cycles.cpp:53:23: error: The class 'cycles::SharedCross' has a circular reference through class 'cycles::SharedCross2'\n   53 |         SharedCross2 *cross2;\n      |                       ^\n_cycles.cpp:57:22: error: The class 'cycles::SharedCross2' has a circular reference through class 'cycles::SharedCross'\n   57 |         SharedCross *cross;\n      |                      ^\n_cycles.cpp:53:23: error: Field type raw pointer\n   53 |         SharedCross2 *cross2;\n      |                       ^\n_cycles.cpp:53:23: error: The class 'cycles::SharedCross' has a circular reference through class 'cycles::SharedCross2'\n_cycles.cpp:57:22: error: Field type raw pointer\n   57 |         SharedCross *cross;\n      |                      ^\n```\n\n\nУровень сообщений плагина можно ограничить с помощью макроса или аргумента командной строки, \nлибо после проверки исходного кода плагин можно вообще не использовать,  \nпоскольку он только анализирует AST, но не вносит в него никаких исправлений.\n\n\n### Полный вывод сообщений плагина при компиляции тестового файла `_example.cpp`:\n\u003cdetails\u003e\n\u003csummary\u003eПоказать вывод\u003c/summary\u003e\n\n```bash\nclang++-20 -std=c++20 -ferror-limit=500 -Xclang -load -Xclang ./memsafe_clang.so -Xclang -add-plugin -Xclang memsafe -Xclang -plugin-arg-memsafe -Xclang circleref-disable _example.cpp\n\n\n...\n\n\n```\n\u003c/details\u003e\n\n\n## Обратная связь\nЕсли у вас есть предложения по развитию и улучшению проекта, присоединяйтесь или [пишите](https://github.com/rsashka/memsafe/discussions)\n\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frsashka%2Fmemsafe","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frsashka%2Fmemsafe","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frsashka%2Fmemsafe/lists"}