refactor(cava): fix thread-safety, resource leaks, and style violations - #5199
Conversation
Comprehensive refactor of the cava module backend and frontends. Style & naming - Rename Cava -> CavaRaw; snake_case methods -> lowerCamelCase - Replace NULL with nullptr; replace C-style casts with static_cast - Add explicit standard-library includes (<memory>, <string>, <chrono>) - Fix missing trailing underscores on member variables Architecture - Remove Gtk::GLArea multiple inheritance in CavaGLSL (composition) - Return std::unique_ptr from factory; add doAction() to GLSL variant - Encapsulate thread timing arithmetic in AdaptiveDelay struct Thread safety & correctness - Replace raw sigc::signal with SafeSignal for cross-thread marshalling - Fix data race between loadConfig() and out_thread_ (recursive_mutex) - Fix audio_raw shallow-copy use-after-free via deep-copy AudioRaw payload - Make loadConfig() exception-safe with CavaConfigGuard RAII - Fix blocking read_thread_ race on shutdown (condition_variable + timeout join) - Fix isSilent() data race (acquire pthread mutex) - Eliminate doUpdate() recursion (iteration instead) - Guard audio_raw_clean() against uninitialized state - Fix format-icons underflow and cava_config buffer overflow - Store config by value to prevent dangling references on reload - Cache frontend config and refresh on runtime changes - Fix signed-char icon lookup bug on x86 - Prevent Json::Value mutation bloat via const-ref lookups - Broaden exception catches in worker threads (std::exception) Resource management & GL robustness - Fix OpenGL resource leaks (persist VBO/IBO/VAO; explicit destructor cleanup) - Fix shader error handling crashes (valid infoLog allocation) - Cache uniform locations instead of querying per frame - Fix gradient color uninitialized stack memory (zero-init + clamped count) - Fix shader time uniform integer division bug (float arithmetic) - Add explicit VAO bind in onRender() - Handle runtime surface config changes independently of shader changes - Clamp negative gradient_count before GL upload Follow-up - Singleton API split (inst() + configure()) intentionally deferred to a dedicated PR because it changes the public constructor contract.
|
LGTM, yes if you can add CONVENTION.md that’ll be useful! |
Consolidate the standalone `CONVENTION.md` into `CONTRIBUTING.md` so that all contributor guidelines live in a single, discoverable file. Added sections: - Language, build system, and formatting rules (Google style, clang-format) - Naming conventions (PascalCase types, snake_case_ members, lowerCamelCase methods) - Include ordering and header self-sufficiency requirements - Class/module design patterns (AModule hierarchy, SafeSignal threading) - JSON configuration and string handling guidelines - GTK/Glib and OpenGL patterns - Platform portability and RAII conventions - Thread-safety rules (GTK single-threaded, background thread marshalling) - Unsafe patterns to avoid (C-style casts, unbounded buffer copies) - Singleton lifetime guidance (store config by value, no dangling refs)docs: merge coding conventions into CONTRIBUTING.md
|
Hi @Alexays , |
Synchronize the cava module man page with the current implementation: - Fix scdoc table syntax (correct header/body cell prefixes) - Add missing Waybar-side options: format-icons, vertex_shader, fragment_shader - Remove options not consumed by the module (data_format, raw_target) - Clarify option scope: raw-only, GLSL-only, and cava-config-only settings - Update descriptions to match backend behavior: - ascii_range is derived from format-icons length - bar_height is ignored by Waybar - bar_delimiter is used for raw output - Polish grammar, tighten structure, and fix example filenames - Refresh STYLE and FRONTENDS sections to match the actual source
|
@Alexays, |
|
Thanks! |
|
"Factory returns std::unique_ptr instead of raw new" I cannot figure out how this is an improvement, especially since the smart pointer is immediately The whole patch being a single commit was also "fun" to parse through. |
|
Dear @qbe, It was a huge list of points that could/couldn't have been improved. So in such a case, how many commits should be provided here? And each such improvement might lead to the next loop of new potential points. I think it's good form to have a rule: if you criticize something, suggest something. Otherwise, we end up in a polemic without any progress toward improvement |
|
I did not want to incite an argument, I tried to fix some merge conflicts for #4735 and could not figure out why the module pointer would be wrapped into a smart pointer, only to be immediately turned back into a normal pointer again (and any justification for this could be relevant for my dynamic loading work). I then tried to find justification for this in the commit message, but since all of the code changes were done in a single commit, the only context I could find was the line I quoted above, which does not address my question, which is why I asked You about it. IMHO doing separate Ideas in separate commits is just good, common practice (I could have formulated that point in a nicer way tho) My suggested improvement would be, therefore, to pick apart the massive commit into one commit per Idea, and to provide justification in the commit messages for every single one. I can't force you to do this rework (and I don't want to force anyone to do anything), but I think doing proper single-Idea commits encourages better software development and helps everyone else to read your code. As for now, I would be happy with any explanation for |
Hi @Alexays ,
This MR was created using the deep kimi-k2.6 support. I used it for the first time to identify what could be improved or fixed for the CAVA module. While I don’t fully agree with some of the criticisms (for example, the “high risk” points), I would still say that the AI is quite useful for reviewing existing functionality, improving it, and polishing it.
Even so, the AI helped me find some race conditions, and the fix improved the CAVA module’s performance.
All proposed changes were reviewed by me.
To outline the process:
Using the AI tool, I inspected the project at a high level to gather the necessary information, which I documented in the CONVENTION.md.
Based on that convention, I used the plan in cava_module_refactor_plan.md to construct this MR.
If it’s useful for the project, I can also push the commit for CONVENTION.md.
Please see the commit overview below.
Cava Module Refactor
Summary
This MR addresses all outstanding style violations, architectural risks, thread-safety bugs, and resource leaks in the
cavamodule.What changed
Code Style & Naming
Cava->CavaRawto match filename conventionlowerCamelCase(update(),pauseResume(), etc.)PascalCase(SignalUpdate,SignalAudioRawUpdate)NULLwithnullptrthroughout the backendstatic_cast<memory>,<string>,<chrono>frame_counter_, etc.)Architecture
CavaGLSLno longer multiply-inherits fromGtk::GLArea; it composes a privateGLAreachild widgetstd::unique_ptr<AModule>instead of rawnewdoAction()/actionMap_support to the GLSL frontendCavaBackend::AdaptiveDelayThread Safety & Correctness
waybar::SafeSignalinstead of rawsigc::signal, marshalling events safely to the GTK main threadloadConfig()andout_thread_viastd::recursive_mutex+ atomicshutdown_flagaudio_rawshallow-copy / use-after-free in GLSL frontend by introducing a deep-copyAudioRawpayloadloadConfig()is now fully exception-safe: validates into a temporarynew_prm, tears down old state, then runs risky init inside atryblock. On failurefreeBackend()scrubs partial allocations and the exception is rethrownread_thread_to exit before cleanupisSilent()now acquiresaudio_data_.lockdoUpdate()with iterationaudio_raw_clean()against uninitialized stateformat-iconsunderflow andcava_configbuffer overflowJson::Valueby value, eliminating dangling references on Waybar config reloadunsigned charcast beforegetIcon)Json::Valuegrowth by performing lookups through aconstreferenceconst std::exception&instead of onlystd::runtime_errorResource Management & OpenGL Robustness
glDelete*inputTextureuniform location instead of querying every frame[0, 8]glBindVertexArray(vao_)inonRender()initSurface()gradient_count_to0beforeglUniform1iTesting
-std=c++20Follow-up work (out of scope)
inst()contract and deciding how multi-module config reloading should behave. Best handled in a standalone PR.Related issues
Fixes style violations, thread-safety bugs, and resource leaks identified in the cava module audit.