LINUX.ORG.RU

Пытаюсь отловить баг в чужом коде.

 , , ,


1

6

Приветствую. В чём суть:
«Модульный» синт на JUCE https://github.com/awwbees/BespokeSynth/ умеет хостить VST плагины. Но под онтопиком при добавлении плагина останавливается движок аудио, хотя ГУЙ не висит. У автора только Мак, где проблемы нет.

Вся сложность в том, что я в плюсах ноль, а починить хочется. Допустим я запускаю Debug сборку, например в https://github.com/rohanrhu/gdb-frontend или https://www.gdbgui.com/ (можете хотя бы посоветовать, в чём лучше).
Подгружаю плагин, движок вешается. Куда смотреть, чтобы выловить «застрявший» поток?

Можно даже ссылки на howto и тд. В общем, любые конструктивные советы (кроме как забить или купить Мак) приветствуются.

★★★★★

Последнее исправление: kott (всего исправлений: 1)
Ответ на: комментарий от anonymous

ок, пока в kdevelop пытаюсь
поставил брейкпоинт на ModularSynth::AudioOut и шагал до загрузки плагина, continue стал неактивным, какой поток породился - как увидеть?

kott ★★★★★
() автор топика
Ответ на: комментарий от kott

не знаю. не пользуюсь kdevelop. continue стал не активным наверное потому что вызов заблокировался, а заблокировался наверное потому что поток чего-то ждёт.

ещё у тебя есть такой вариант про который я забыл упомянуть: gdb core binary. т.к. кора отложена, ты можешь её загрузить в гдб и посмотреть состояние в момент сегфолта.

anonymous
()
Ответ на: комментарий от anonymous

да, гдб могу посмотреть на чем он сегфолтнулся, только пока это приоритетом ниже :)

kott ★★★★★
() автор топика
Ответ на: комментарий от anonymous

при запуске в valgrind баг воспроизводится раз на десятый
как это можно объяснить?

kott ★★★★★
() автор топика

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

kott ★★★★★
() автор топика
Ответ на: комментарий от kott

Кря. Это можно объяснить очень просто (но необязательно правильно): где-то есть состояние гонки и иногда оно проявляется, а иногда нет, потому что валгринд где-то вносит дополнительную задержку.

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

Потом залогируй то место где он должен инициализироваться и посмотри вызывается ли этот код когда баг проявляется. Если не вызывается - ты нашел проблему. Как исправлять проблему - это другой вопрос.

anonymous
()
Ответ на: комментарий от anonymous

я ж не сегфолт хочу отловить сейчас пока, а именно глюк с остановкой движка, и вот этот глюк (с плагином, который в обычном запуске всегда дает эффект) в valgrind воспроизводится очень неохотно

похоже, не раскурив весь код (и дебажа косяки в JUCE), найти не получится =\

kott ★★★★★
() автор топика
Ответ на: комментарий от kott

Начинаю поддерживать анона. Скинь bt от крэша с отладочным плагином.

Прогнать поделку имеет смысл под:

  • санитайзерами (будет падать где стоит дать по рукам)
  • valgrind
  • потом уже отлаживать

Ибо маковод мог поделку таки под вдохновением написать так шобыработало.

pon4ik ★★★★★
()
Ответ на: комментарий от pon4ik

похоже падает сам плагин, gdb ./PAPU.so ./vgcore.8456:

#0  0x0000000000f21bf2 in avir::calcFIRFilterResponse<avir::float4> (flt=<error reading variable: Cannot access memory at address 0x1ffeffe900>, fltlen=<error reading variable: Cannot access memory at address 0x1ffeffe8fc>,
    th=<error reading variable: Cannot access memory at address 0x1ffeffe8f0>, re0=<error reading variable: Cannot access memory at address 0x1ffeffe8e8>, im0=<error reading variable: Cannot access memory at address 0x1ffeffe8e0>,
    fltlat=<error reading variable: Cannot access memory at address 0x1ffeffe8f8>) at ../../../modules/gin/modules/gin/3rdparty/avir/avir.h:351
351     inline void calcFIRFilterResponse( const T* flt, int fltlen,
[Current thread is 1 (LWP 8456)]

напомню, что release билд не падает

kott ★★★★★
() автор топика
Последнее исправление: kott (всего исправлений: 1)

Если заморочиться исправлением всех косяков, то может желание угаснуть. Я предлагаю сосредоточиться пока на изначальной проблеме - остановка движка. Если анон прав и это race condition, то как я понимаю:
Движок становится на паузу перед загрузкой плагина, ждёт когда загрузчик плагинов что-то ему сообщит, затем возобновляется. Загрузчик VST дергает движок слишком рано или вообще не дергает. Так как race condition то стреляет, то - нет с одними и теми же данными (бинарник плагина), то может быть дело в таймере, которым тикает движок? Если это звучит не совсем бредово (поправьте, если туплю) - то отпишу автору, может осенит его, где не хватает проверки

kott ★★★★★
() автор топика
Ответ на: комментарий от kott

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

можешь сказать ему, что ты не девелопер и тебе приходится разбираться в этом всём с нуля, в этом нет ничего зазорного, если он нормальный и у него есть время над этим посидеть, то он сам посмотрит в чём может быть проблема и возможно предложит какое-то решение, но у него нет линукса, но линукс есть у тебя.

anonymous
()
Ответ на: комментарий от anonymous

да мне не зазорно, но хочется максимально информативно выдать инфу

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

ты про крэш плагина или про остановку движка?

kott ★★★★★
() автор топика
Ответ на: комментарий от anonymous

я понимаю, что не видя софтины нелегко понять суть бага, могу видео записать

ну и бинарник если что есть

kott ★★★★★
() автор топика
Ответ на: комментарий от kott

ты про крэш плагина или про остановку движка?

Есть подозрение, что это одно и то же, просто в дебаге ты видишь креш, а в релизе тебе кажется, что движок остановился. На самом деле в дебаге и релизе код не меняется, ты запускаешь одну и ту же программу, меняется окружение в котором программа выполняется.

Когда ты запускает в дебаге или под валгриндом, программа работает медленнее, увеличивается пространство для возникновения состояния гонки. Если такое состояние возникает, то программа может крашнуться, а может произвести другой побочный эффект и продолжить выполняться. Поэтому может крашиться не всегда, или движок может «останавливаться» через 2-3 попытки.

Но это не точно, это умозаключения, а валдгинд показал разименование нулевого указателя - такого точно не должно быть ни при каких обстоятельствах, это 100% ошибка в программе.

anonymous
()
Ответ на: комментарий от kott

Access not within mapped region at address 0x10

Вот это разименование нулевого указателя. Это доступ через нулевой указатель к члену структуры по смещение 0х10, 0 + 0х10 = 0х10.

anonymous
()
Ответ на: комментарий от anonymous

Но в кору падает плагин же? Пытаюсь отловить баг в чужом коде. (комментарий)

дамп от него

это код, на который указывает бэктрейс:
https://github.com/FigBug/Gin/blob/af6eda9807bd4aff02275302413cca2eaa46b1de/modules/gin/3rdparty/avir/avir.h#L351

ладно хер с этим плагином, попробую другой )

kott ★★★★★
() автор топика
Последнее исправление: kott (всего исправлений: 1)
Ответ на: комментарий от kott

Даже не знаю что тебе сказать. Состояние гонки - это не тривиальная проблема, но в этом ли дело я тоже не могу сказать наверняка. Валгринд - твой друг, смотри где возникают проблемы с памятью и как они связаны. Тебе надо хоть какую то информацию получить о проблеме. Пока что ты выяснил, что оно иногда падает, а почему падает до сих пор неизвестно, есть какие то проблемы с памятью, но связаны ли они с твоим ишуем - тоже не известно.

Падает - это не информация, падает потому что такой то указатель не проинициализирован - это кое что. Стектрейсы ты тоже показываешь не полностью, поэтому сказать чтото по ним нельзя.

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

anonymous
()
Ответ на: комментарий от kott

Я не вижу где сделан bt. Но если он сделан и это действительно весь трейс от плагина, то имо ты никуда не продвинешься пока не решишь проблемы с памятью. С такими трейсами не живут.

anonymous
()
Ответ на: комментарий от anonymous

сорян, откусил только это, а дамп уже грохнул, сделаю ещё раз

собрал другой плагин в debug, ниче не падает, более того нашел, как точнее воспроизвести остановку движка, и даже нечто вроде workaround-а

kott ★★★★★
() автор топика

насчёт памяти ты прав:

Attempting to load VST: /home/kv/.config/BespokeSynth/data/VST/Phrasebox.so
Creating VST instance: Phrasebox
[New Thread 0x7fff6e145700 (LWP 17617)]
double free or corruption (out)

Thread 46 "BespokeSynth" received signal SIGABRT, Aborted.
[Switching to Thread 0x7fff6e145700 (LWP 17617)]
__GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50
50        return ret;
Missing separate debuginfos, use: zypper install libcairo2-debuginfo-1.16.0-3.3.x86_64 libexpat1-debuginfo-2.2.9-1.11.x86_64 libfontconfig1-debuginfo-2.13.1-2.7.x86_64 libogg0-debuginfo-1.3.4-1.3.x86_64 libspeex1-debuginfo-1.2-1.11.x86_64 libuuid1-debuginfo-2.35.1-2.2.x86_64 libvorbis0-debuginfo-1.3.7-1.1.x86_64 libvorbisenc2-debuginfo-1.3.7-1.1.x86_64 libxcb-image0-debuginfo-0.4.0-1.17.x86_64 libxcb-render-util0-debuginfo-0.3.9-3.16.x86_64 libxcb-render0-debuginfo-1.14-1.2.x86_64 libxcb-util1-debuginfo-0.4.0-1.17.x86_64 libxcb-xkb1-debuginfo-1.14-1.2.x86_64 libxkbcommon-x11-0-debuginfo-0.10.0-1.3.x86_64 libxkbcommon0-debuginfo-0.10.0-1.3.x86_64
(gdb) c
Continuing.
[Thread 0x7fff6e145700 (LWP 17617) exited]
[Thread 0x7ffff664b700 (LWP 17449) exited]
[Thread 0x7ffff50e9700 (LWP 17312) exited]
[Thread 0x7ffff58ea700 (LWP 17311) exited]

Program terminated with signal SIGABRT, Aborted.
The program no longer exists.
(gdb) bt
No stack.
kott ★★★★★
() автор топика
Последнее исправление: kott (всего исправлений: 1)
Ответ на: комментарий от kott

bt надо делать сразу как загрузил кору. ты сделал c(continue), треды вышли, стектрейса не будет.

перед этим можно убедиться, что ты в правильном треде. правильный должен быть описан как «paused on exception» или что-то в этом роде, остальные просто «paused».

anonymous
()
Ответ на: комментарий от anonymous
Reading symbols from ./BespokeSynth...
[New LWP 17120]
[New LWP 16583]
[New LWP 16504]
[New LWP 16503]
[New LWP 16335]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
Core was generated by `'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0  0x0000000000dd3f57 in IUIControl::Delete (this=0x766b) at ../../Source/IUIControl.h:32
32         void Delete() { delete this; }
[Current thread is 1 (Thread 0x4919e700 (LWP 17120))]
Missing separate debuginfos, use: zypper install krb5-debuginfo-1.18.2-2.1.x86_64 libX11-6-debuginfo-1.6.9-2.1.x86_64 libX11-xcb1-debuginfo-1.6.9-2.1.x86_64 libXau6-debuginfo-1.0.9-1.6.x86_64 libXcursor1-debuginfo-1.2.0-1.4.x86_64 libXext6-debuginfo-1.3.4-1.6.x86_64 libXfixes3-debuginfo-5.0.3-1.10.x86_64 libXinerama1-debuginfo-1.1.4-1.7.x86_64 libXrandr-devel-debuginfo-1.5.2-1.6.x86_64 libXrender1-debuginfo-0.9.10-1.11.x86_64 libXss1-debuginfo-1.2.3-1.8.x86_64 libbrotlicommon1-debuginfo-1.0.7-3.4.x86_64 libbrotlidec1-debuginfo-1.0.7-3.4.x86_64 libbz2-1-debuginfo-1.0.8-2.19.x86_64 libcairo2-debuginfo-1.16.0-3.3.x86_64 libcom_err2-debuginfo-1.45.6-1.18.x86_64 libcurl4-debuginfo-7.71.1-1.2.x86_64 libexpat1-debuginfo-2.2.9-1.11.x86_64 libfontconfig1-debuginfo-2.13.1-2.7.x86_64 libfreetype6-debuginfo-2.10.2-1.2.x86_64 libgcc_s1-debuginfo-10.2.1+git501-1.1.x86_64 libglvnd-debuginfo-1.2.0-4.3.x86_64 libidn2-0-debuginfo-2.3.0-3.1.x86_64 libkeyutils1-debuginfo-1.6-1.18.x86_64 libldap-2_4-2-debuginfo-2.4.50-53.2.x86_64 libnghttp2-14-debuginfo-1.41.0-1.2.x86_64 libogg0-debuginfo-1.3.4-1.3.x86_64 libopenssl1_1-debuginfo-1.1.1g-2.12.x86_64 libpcre1-debuginfo-8.44-1.18.x86_64 libpng16-16-debuginfo-1.6.37-1.6.x86_64 libpsl5-debuginfo-0.21.1-1.1.x86_64 libpython2_7-1_0-debuginfo-2.7.18-2.2.x86_64 libsasl2-3-debuginfo-2.1.27-3.4.x86_64 libselinux1-debuginfo-3.0-2.2.x86_64 libspeex1-debuginfo-1.2-1.11.x86_64 libssh4-debuginfo-0.9.4-1.3.x86_64 libstdc++6-debuginfo-10.2.1+git501-1.1.x86_64 libunistring2-debuginfo-0.9.10-2.7.x86_64 libuuid1-debuginfo-2.35.1-2.2.x86_64 libvorbis0-debuginfo-1.3.7-1.1.x86_64 libvorbisenc2-debuginfo-1.3.7-1.1.x86_64 libxcb-dri3-0-debuginfo-1.14-1.2.x86_64 libxcb-glx0-debuginfo-1.14-1.2.x86_64 libxcb-image0-debuginfo-0.4.0-1.17.x86_64 libxcb-render-util0-debuginfo-0.3.9-3.16.x86_64 libxcb-render0-debuginfo-1.14-1.2.x86_64 libxcb-sync1-debuginfo-1.14-1.2.x86_64 libxcb-util1-debuginfo-0.4.0-1.17.x86_64 libxcb-xkb1-debuginfo-1.14-1.2.x86_64 libxkbcommon-x11-0-debuginfo-0.10.0-1.3.x86_64 libxkbcommon0-debuginfo-0.10.0-1.3.x86_64 libz1-debuginfo-1.2.11-13.18.x86_64 valgrind-debuginfo-3.16.0-1.1.x86_64
(gdb) bt
#0  0x0000000000dd3f57 in IUIControl::Delete (this=0x766b) at ../../Source/IUIControl.h:32
#1  IDrawableModule::~IDrawableModule (this=0x2d6ba2d8, __vtt_parm=<optimized out>, __in_chrg=<optimized out>) at ../../Source/IDrawableModule.cpp:59
#2  0x000000004a785b71 in ArpAudioProcessor::~ArpAudioProcessor() () from /home/kv/.config/BespokeSynth/data/VST/Phrasebox.so
#3  0x000000004a785c39 in ArpAudioProcessor::~ArpAudioProcessor() () from /home/kv/.config/BespokeSynth/data/VST/Phrasebox.so
#4  0x000000004a4adb34 in ?? () from /home/kv/.config/BespokeSynth/data/VST/Phrasebox.so
#5  0x000000004a4b162b in ?? () from /home/kv/.config/BespokeSynth/data/VST/Phrasebox.so
#6  0x0000000000ee76c6 in juce::ModuleHandle::closeEffect (this=<optimized out>, eff=<optimized out>) at /home/kv/src/JUCE-5.4.7/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp:1154
#7  juce::VSTPluginInstance::cleanup (this=0x30f0e6b0) at /home/kv/src/JUCE-5.4.7/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp:1154
#8  juce::VSTPluginInstance::~VSTPluginInstance()::VSTDeleter::messageCallback() (this=0x2d47e930) at /home/kv/src/JUCE-5.4.7/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp:1119
#9  0x0000000000fafeaa in juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}::operator()(int) const (__closure=0x2d4ace28, fd=24) at /home/kv/src/JUCE-5.4.7/modules/juce_events/native/juce_linux_Messaging.cpp:43
#10 0x0000000000fade72 in std::function<void (int)>::operator()(int) const (__args#0=<optimized out>, this=0x2d4ace28) at /usr/include/c++/10/bits/std_function.h:617
#11 juce::InternalRunLoop::dispatchPendingEvents (this=0x612e110) at /home/kv/src/JUCE-5.4.7/modules/juce_events/native/juce_linux_Messaging.cpp:169
#12 juce::MessageManager::dispatchNextMessageOnSystemQueue (returnIfNoPendingMessages=<optimized out>) at /home/kv/src/JUCE-5.4.7/modules/juce_events/native/juce_linux_Messaging.cpp:260
#13 0x0000000000fadf4e in juce::MessageManager::runDispatchLoopUntil (this=0x5f3ab30, millisecondsToRunFor=250) at /home/kv/src/JUCE-5.4.7/modules/juce_events/messages/juce_MessageManager.cpp:92
#14 0x000000004a4a99e2 in ?? () from /home/kv/.config/BespokeSynth/data/VST/Phrasebox.so
#15 0x0000000000f72f0c in juce::Thread::threadEntryPoint (this=0x2d3ef880) at /home/kv/src/JUCE-5.4.7/modules/juce_core/threads/juce_Thread.cpp:96
#16 0x0000000000f73069 in juce::juce_threadEntryPoint (userData=<optimized out>) at /home/kv/src/JUCE-5.4.7/modules/juce_core/threads/juce_Thread.cpp:118
#17 juce::threadEntryProc (userData=<optimized out>) at /home/kv/src/JUCE-5.4.7/modules/juce_core/native/juce_posix_SharedCode.h:834
#18 0x0000000004e61eaa in start_thread (arg=<optimized out>) at pthread_create.c:477
#19 0x0000000005383aff in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95
(gdb) list
27
28      class IUIControl : public IClickable
29      {
30      public:
31         IUIControl() : mRemoteControlCount(0), mNoHover(false), mShouldSaveState(true) {}
32         void Delete() { delete this; }
33         void AddRemoteController() { ++mRemoteControlCount; }
34         void RemoveRemoteController() { ++mRemoteControlCount; }
35         virtual void SetFromMidiCC(float slider) = 0;
36         virtual float GetValueForMidiCC(float slider) const { return 0; }
kott ★★★★★
() автор топика
Ответ на: комментарий от kott

во, теперь вижу. наверное можно сказать, что скрашился плагин при выгрузке из движка, но по ходу всё таки скрашился движок где-то в своём гуи. если твой ишуй воспроизводится только при втыкании плагина (без вытыкания), то можно предположить, что этот краш не релевантен.

но трейс нормальный. с такими трейсами живут.

anonymous
()
Ответ на: комментарий от anonymous

этот краш происходит при скане на новые плагины (Phrasebox.so), так что да, движок не задействуется

kott ★★★★★
() автор топика
Ответ на: комментарий от kott

чем дальше в лес - тем больше дров)
пока в оффлайн удалюсь

kott ★★★★★
() автор топика
Ответ на: комментарий от kott

То, что релизный билд не падает под такую отлаженную платформу как x86 - не показатель. А вот то, что стек выглядит испорченным это подтверждает теорию о том, что надо собирать под санитайзерами весь этот софт. Ну или хотя бы под valgrind’om читать кто за границы буферов пишет.

pon4ik ★★★★★
()
Ответ на: комментарий от kott

Дело может быть ещё в порядке захвата примитивов синхронизации например. Вот поймать бы этот race condition за руку, тогда можно уже идти к автору и говорить где осеняться.

pon4ik ★★★★★
()
Ответ на: комментарий от kott

Можно запустить под helgrind (это часть valgrind), но там очень много false possitives в коде который содержит condition variable. Лучше всего - включить в флагах компилятора thread sanitizer для всех зависимостей. Либо в момент подвисона анализировать примитивы синхронизации на которых оно подвисло(чем мы вроде уже занимались, но можно ещё один подход).

pon4ik ★★★★★
()
Ответ на: комментарий от pon4ik

Прикол в том, что все эти практики(кроме отладки) хорошо работают с кодом у которого есть тесты, т.е. можно в каждом компоненте поискать проблемки. А в целом приложении если его никто не проводил под такими инструментами в процессе разработки может оказаться ну капец как много проблем и они потонут на фоне false positives. Поэтому я бы ставил на отладчик. Я гляну ещё раз все бэтэхи, вот только х3 когда.

pon4ik ★★★★★
()

автор поставил линукс, увидел баг и сделал затычку:
it’s a dumb fix, and I don’t understand why it fixes it, and it probably only fixes it _most_of the time, so it warrants further investigation

+#if BESPOKE_LINUX //HACK: weird race condition, which this seems to fix for now
+   if (mPlugin == nullptr)
+      return;
+#endif

kott ★★★★★
() автор топика
Ответ на: комментарий от kott

Мде, вот вам и прекрасный open source. Хотя чьябы корова мычала - я так и не добрался по серьёзу до этих изысканий например. Добавь к теме тэг multithreading, pthreads, многопоточность, может придёт ещё кто и свежим взглядом найдёт багу.

pon4ik ★★★★★
()
Ответ на: комментарий от pon4ik

было бы здорово, если бы кто-нибудь педантичный присоединился, у создателя творческая мысль явно обгоняет необходимость писать без ошибок

у проекта есть потенциал

kott ★★★★★
() автор топика
Ответ на: комментарий от deep-purple

Ну воспроизводится же пока что только под линукс. Автор явно не системный разработчик, и скорее всего шарится по форумам и добывает обрывки знаний вместо системного подхода. Зато - он сделал продукт у которого есть пользователи(хоть они местами и страдают) и, видимо понимание предметной области и юзабилити. Было бы время свободное - я бы похакал. Если замотивированые личности пнут меня к концу октября я может даже и похакаю, летом тяжко, приходится хакать дом, пока погодные условия позволяют.

pon4ik ★★★★★
()
Ответ на: комментарий от pon4ik

Я тоже )) Весь двор обхакал: поднял песком, засыпал щебнем, залил ленту под забором, сложил клумбы, сделал дорожки и отмостку.

deep-purple ★★★★★
()
Ответ на: комментарий от kott

ну присоединился бы. там какая-нибудь ерунда, этот mPlugin где-то мьютексом не закрыт. у автора нормальная чуйка, он тебе не зря сразу про мьютекс сказал. проекту нужен кто-то кто его просто покодит, сядет и покодит, починит баги там, всё такое.

проект будет кому угодно интересным. это обработка звука в реальном времени - не хелло ворлд, придётся углубиться в системы мягкого реального времени и очень многое станет понятно.

anonymous
()
Ответ на: комментарий от anonymous

Лорчую, там есть даже некоторые претензии на локфри местами, возможно оттуда и бага.

pon4ik ★★★★★
()
Ответ на: комментарий от anonymous

ну присоединился бы

баги репорчу, идеи подкидываю, может реквест мой с расположением конфигов примет

kott ★★★★★
() автор топика
21 октября 2020 г.
Ответ на: комментарий от pon4ik

эцнова я
уже прилично багов поправлено и падений я не наблюдаю практически, но помощь в «причёсывании» будет полезной

kott ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.