Skip to content

tons of memory leaks #52

Closed as not planned
Closed as not planned
@louis030195

Description

@louis030195

hey i fixed a bunch of memory leaks in here

there is a last leak i'm facing:

leaks stdout: Process:         leak [58086]
Path:            /Users/USER/Documents/*/leak
Load Address:    0x102f40000
Identifier:      leak
Version:         0
Code Type:       ARM64
Platform:        macOS
Parent Process:  bash [40171]

Date/Time:       2024-08-30 11:09:49.548 +0200
Launch Time:     2024-08-30 11:09:48.532 +0200
OS Version:      macOS 14.5 (23F79)
Report Version:  7
Analysis Tool:   /Applications/Xcode.app/Contents/Developer/usr/bin/leaks
Analysis Tool Version:  Xcode 15.4 (15F31d)

Physical footprint:         5249K
Physical footprint (peak):  5249K
Idle exit:                  untracked
----

leaks Report Version: 4.0, multi-line stacks
Process 58086: 8540 nodes malloced for 948 KB
Process 58086: 1 leak for 224 total leaked bytes.

STACK OF 1 INSTANCE OF 'ROOT LEAK: <SCStreamConfiguration>':
23  dyld                                  0x19fa6e0e0 start + 2360
22  leak                                  0x102f4ae1c main + 36
21  leak                                  0x102f5469c std::rt::lang_start::hbf253debbfb5da83 + 84  rt.rs:158
20  leak                                  0x102fbabe8 std::rt::lang_start_internal::h27a134f18d582a1e + 640
19  leak                                  0x102f546d0 std::rt::lang_start::_$u7b$$u7b$closure$u7d$$u7d$::hd7f53490fb601a3d + 28  rt.rs:159
18  leak                                  0x102f45964 std::sys_common::backtrace::__rust_begin_short_backtrace::hbd676431ce47ec6b + 24  backtrace.rs:161
17  leak                                  0x102f50344 core::ops::function::FnOnce::call_once::h87f13f6285a6f5bc + 20  function.rs:250
16  leak                                  0x102f4ad38 leak::main::h76222d92e030bf7f + 2548  leak.rs:79
15  leak                                  0x102f4dd0c screencapturekit::sc_stream::SCStream::new::hc1a712a51f90081e + 68  sc_stream.rs:0
14  leak                                  0x102f4dc20 _$LT$T$u20$as$u20$core..convert..Into$LT$U$GT$$GT$::into::he8db2d20efc619ba + 12  mod.rs:760
13  leak                                  0x102f57804 screencapturekit::sc_stream_configuration::_$LT$impl$u20$core..convert..From$LT$screencapturekit..sc_stream_configuration..SCStreamConfiguration$GT$$u20$for$u20$objc_id..id..Id$LT$screencapturekit_sys..stream_configuration..UnsafeStreamConfigurationRef$GT$$GT$::from::hf24e8a374332729a + 48
12  leak                                  0x102f577cc _$LT$T$u20$as$u20$core..convert..Into$LT$U$GT$$GT$::into::hfbac22df0571c6a9 + 12
11  leak                                  0x102f78ab8 screencapturekit_sys::stream_configuration::_$LT$impl$u20$core..convert..From$LT$screencapturekit_sys..stream_configuration..UnsafeStreamConfiguration$GT$$u20$for$u20$objc_id..id..Id$LT$screencapturekit_sys..stream_configuration..UnsafeStreamConfigurationRef$GT$$GT$::from::h303bbc276092c257 + 564
10  leak                                  0x102f6f9b0 objc::message::platform::send_unverified::hecceebaf7d334a9f + 136
9   leak                                  0x102f98ce4 objc::exception::try::hd989aeece3baa958 + 12
8   leak                                  0x102f68248 objc_exception::try::hbe9fd473da645d90 + 72
7   leak                                  0x102f63318 objc_exception::try_no_ret::h19840b29b3cee5c9 + 144
6   leak                                  0x102fa4944 RustObjCExceptionTryCatch + 36
5   leak                                  0x102f66810 objc_exception::try_no_ret::try_objc_execute_closure::hfc53324dcf5dbd7e + 76
4   leak                                  0x102f69c6c objc_exception::try::_$u7b$$u7b$closure$u7d$$u7d$::ha391d7eab5a0b2df + 44
3   leak                                  0x102f713f8 objc::message::platform::send_unverified::_$u7b$$u7b$closure$u7d$$u7d$::h56aa810409fb6d0b + 60
2   leak                                  0x102f8f5e0 _$LT$$LP$$RP$$u20$as$u20$objc..message..MessageArguments$GT$::invoke::h9cfcb104498431d2 + 72
1   libobjc.A.dylib                       0x19fa25d84 _objc_rootAllocWithZone + 44
0   libsystem_malloc.dylib                0x19fc30d1c _malloc_zone_calloc_instrumented_or_legacy + 240 
====
    1 (224 bytes) ROOT LEAK: <SCStreamConfiguration 0x11e730130> [224]

theory of the problem

• Improper release of Objective-C object in Rust-to-ObjC conversion
• Retain cycle between Rust and Objective-C objects
• Exception thrown during object initialization, bypassing normal cleanup
• Autorelease pool not properly set up or drained
• Incorrect implementation of Drop trait for Rust wrapper
• Memory management mismatch between Rust's ownership model and ObjC's reference counting
• Unhandled edge case in exception handling code
• Thread-safety issue causing object to be retained on another thread
• Incorrect use of unsafe code in FFI layer
• Hidden retain in Apple's SCStreamConfiguration implementation

things i tried to fix

  • using autoreleasepool
  • impl my own autoreleasepool
  • using verify message
  • drop manually
  • impl drop for unsafestreamconf
  • print stuff everywhere
  • count retain
  • use panic unwind rust feat
  • commenting out properties (still leak on the init msg_send)
  • other stuff

anything else i should try?

how to reproduce

add this to examples/leak.rs

use std::process::Command;

use screencapturekit::{
    cm_sample_buffer::CMSampleBuffer,
    sc_content_filter::{InitParams, SCContentFilter},
    sc_error_handler::StreamErrorHandler,
    sc_output_handler::{SCStreamOutputType, StreamOutput},
    sc_shareable_content::SCShareableContent,
    sc_stream::SCStream,
    sc_stream_configuration::{PixelFormat, SCStreamConfiguration},
    sc_types::base::CMTime,
};
use screencapturekit_sys::{
    content_filter::{UnsafeContentFilter, UnsafeInitParams},
    shareable_content::UnsafeSCShareableContent,
};

pub struct Capturer {}

impl Capturer {
    pub fn new() -> Self {
        println!("Capturer initialized");
        Capturer {}
    }
}

impl StreamErrorHandler for Capturer {
    fn on_error(&self) {
        eprintln!("ERROR!");
    }
}

impl StreamOutput for Capturer {
    fn did_output_sample_buffer(&self, _sample: CMSampleBuffer, _of_type: SCStreamOutputType) {
        println!("New frame recvd");
    }
}
fn main() {
    println!("Starting");

    for _ in 0..1 {
        // Repeat the process multiple times to amplify leaks
        // Create SCShareableContent and SCContentFilter
        let display = SCShareableContent::current().displays.pop().unwrap();
        let windows = SCShareableContent::current().windows;

        // Create multiple filters
        let _filter1 = SCContentFilter::new(InitParams::DisplayExcludingWindows(
            display.clone(),
            windows,
        ));
        let _filter2 = SCContentFilter::new(InitParams::Display(display.clone()));
        let _filter3 =
            SCContentFilter::new(InitParams::DisplayExcludingWindows(display.clone(), vec![]));

        // Create multiple configurations
        let _config1 = SCStreamConfiguration {
            width: 1920,
            height: 1080,
            ..Default::default()
        };
        let _config2 = SCStreamConfiguration {
            width: 1280,
            height: 720,
            ..Default::default()
        };

        // Create and immediately drop streams
        let init_params = InitParams::Display(display);
        let filter = SCContentFilter::new(init_params);
        let mut sc_stream = SCStream::new(filter, _config1, Capturer {});
        let output = Capturer {};
        sc_stream.add_output(output, SCStreamOutputType::Screen);

        // Force drop of sc_stream
        drop(sc_stream);
    }

    // Get the current process ID
    let pid = std::process::id();

    // Run the 'leaks' command
    let output = Command::new("leaks")
        .args(&[pid.to_string()])
        .output()
        .expect("Failed to execute leaks command");

    // Check the output for leaks
    let stdout = String::from_utf8_lossy(&output.stdout);
    let stderr = String::from_utf8_lossy(&output.stderr);

    println!("leaks stdout: {}", stdout);
    println!("leaks stderr: {}", stderr);
}
RUST_BACKTRACE=1  MallocStackLogging=1 cargo run --example leak

thank you

related issue:

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions