Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 13 additions & 5 deletions guest-js/auto-reconnect-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,15 +128,18 @@ export class AutoReconnectManager {
return;
}

// Проверяем лимит ДО увеличения счётчика
if (this.maxAttempts !== null && this.currentAttempts >= this.maxAttempts) {
// Atomically check limit and increment counter to prevent race conditions
const currentAttempt = this.currentAttempts + 1;

if (this.maxAttempts !== null && currentAttempt > this.maxAttempts) {
logError(`Auto-reconnect failed after ${this.maxAttempts} attempts`);
if (this.callback) {
this.callback(false, this.currentAttempts);
}
return;
}
this.currentAttempts++;

this.currentAttempts = currentAttempt;

logInfo(`Auto-reconnect attempt ${this.currentAttempts}${this.maxAttempts !== null ? `/${this.maxAttempts}` : ''}`);

Expand All @@ -160,11 +163,16 @@ export class AutoReconnectManager {
this.callback(false, this.currentAttempts);
}

// Schedule next attempt
if (this.enabled) {
// Schedule next attempt only if still enabled and within limits
if (this.enabled && (this.maxAttempts === null || this.currentAttempts < this.maxAttempts)) {
this.timer = setTimeout(() => {
this.performAttempt();
}, this.interval);
} else if (this.enabled && this.maxAttempts !== null && this.currentAttempts >= this.maxAttempts) {
logError(`Auto-reconnect stopped: maximum attempts (${this.maxAttempts}) reached`);
if (this.callback) {
this.callback(false, this.currentAttempts);
}
}
}
}
Expand Down
6 changes: 6 additions & 0 deletions src/desktop_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,7 @@ impl<R: Runtime> SerialPort<R> {
let thread_handle = thread::spawn(move || {
let mut combined_buffer: Vec<u8> = Vec::with_capacity(size.unwrap_or(1024));
let mut start_time = Instant::now();
let max_buffer_size = size.unwrap_or(1024) * 10; // Limit buffer growth to prevent memory leaks
loop {
match rx.try_recv() {
Ok(_) => break,
Expand All @@ -483,6 +484,11 @@ impl<R: Runtime> SerialPort<R> {
let mut buffer = vec![0; size.unwrap_or(1024)];
match serial.read(&mut buffer) {
Ok(n) => {
// Prevent buffer from growing too large to avoid memory leaks
if combined_buffer.len() + n > max_buffer_size {
log_warn!("Buffer size limit reached, clearing buffer to prevent memory leak");
combined_buffer.clear();
}
combined_buffer.extend_from_slice(&buffer[..n]);
}
Err(e) if e.kind() == std::io::ErrorKind::TimedOut => {}
Expand Down
5 changes: 2 additions & 3 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,5 @@ impl From<PluginInvokeError> for Error {
}
}

// Implementing Send and Sync for Error
unsafe impl Send for Error {}
unsafe impl Sync for Error {}
// Error is automatically Send and Sync because all its fields are Send and Sync
// String is Send and Sync, so Error is safe to use across threads
Loading