Commit Graph
934 Commits
Author SHA1 Message Date
andrey 9a4384a378 fix(piopencl): release context on command queue creation failure
If clCreateContext succeeded but clCreateCommandQueue failed,
the context handle was returned without being released, leaking
the OpenCL context and all associated GPU resources.
2026-08-10 16:26:18 +03:00
andrey 4d2c268710 fix(piluaprogram): add destructor to close Lua state
luaL_newstate() allocates a Lua state (~2-4 MB with libraries)
in the constructor, but there was no destructor to call lua_close().
Every PILuaProgram instance leaked its entire Lua state.
Add ~PILuaProgram() that calls lua_close(PRIVATE->lua_state).
2026-08-10 16:26:13 +03:00
andrey 9294cd7b7b fix(picrypt): use crypto_box_* constants for public-key decrypt
The decrypt() function for crypto_box (public-key) used
crypto_secretbox_NONCEBYTES and crypto_secretbox_MACBYTES
(secret-key constants) instead of crypto_box_* constants.
These happen to be equal in libsodium but are semantically
different APIs. Fix ensures consistency with the encrypt()
counterpart.
2026-08-10 16:26:08 +03:00
andrey 16adea05af fix(picompress): pass correct source size to uncompress()
piDecompress() appended original size as 8-byte ullong at the end
of compressed data, but passed zba.size() (including the 8 bytes)
to uncompress(). This fed trailing metadata as part of the zlib
stream. Fix: subtract sizeof(ullong) from source length.
2026-08-10 16:26:02 +03:00
andrey aa64eb4c7f fix(pibasetransfer): fix ABBA deadlock — enforce consistent mutex lock ordering
received() acquired mutex_header and mutex_session in different orders
depending on packet type:
  - pt_Data path:  mutex_header → mutex_session
  - pt_Start path: mutex_session → mutex_header

send_process() acquires mutex_session independently. When running
concurrently with received(), the reversed lock ordering creates a
classic ABBA deadlock scenario.

Fix: enforce consistent ordering (mutex_header → mutex_session) in
all code paths. Restructured pt_Start case and buildSession() to
always acquire mutex_header before mutex_session.
2026-08-10 15:48:40 +03:00
andrey c3bdc5464e fix(piconnection): prevent UAF in DevicePool::run() during connection deletion
The background run() thread copies allConnections() then iterates
each connection's diags_ map. If a PIConnection is deleted from
another thread between the copy and the iteration, dereferencing
the pointer is UAF. Add null check and protect diags_ iteration
with __device_pool__ lock.
2026-08-10 15:48:31 +03:00
andrey b180d91b1e fix(pibasetransfer): make shared flags std::atomic<bool> to eliminate data race
Flags break_, is_sending, is_receiving, is_pause are accessed from
both the send thread (send_process) and the read thread (received)
without synchronization. Plain bool reads/writes from multiple threads
is undefined behavior per C++ standard. Convert to std::atomic<bool>
with proper initializers.
2026-08-10 15:48:24 +03:00
andrey 1c9cdbba19 fix(picloudserver): use piMin<ssize_t> to avoid signed/unsigned UB in Client::readDevice
piMini(max_size, buff.size()) implicitly narrows size_t to int,
which is UB for large buffers. Replace with explicit piMin<ssize_t>
matching the correct pattern used in picloudclient.cpp.
2026-08-10 15:48:12 +03:00
andrey f9a846a3e9 Revert "fix(PIFFT_float): correct plan entry size from 4 to 8"
This reverts commit 2bb3884aee.
2026-08-10 14:59:18 +03:00
andrey fc2e49b096 Revert "fix: PISingleApplication TOCTOU — two shm reads replaced with single atomic read"
This reverts commit 1b23a258b8.
2026-08-10 14:59:13 +03:00
andrey 1a153eefbc fix(PISystemInfo): correct guard for df output parsing
The guard ml.size_s() < 2 allowed size==2, but ml[2] was then
accessed — OOB read on truncated or unusual df output lines.
2026-08-06 17:01:30 +03:00
andrey 9e280ef976 fix(PISerial): close fd when probe read fails in availableDevicesInfo
When the non-blocking probe read returned EIO, the loop continued
without closing the file descriptor, leaking one fd per rejected
port on each call.
2026-08-06 17:01:30 +03:00
andrey c8ad8ecaf4 fix(PISPI): close fd on ioctl error paths
Three ioctl calls after successful open() returned false without
closing the file descriptor, leaking one fd per failed open attempt.
2026-08-06 17:01:30 +03:00
andrey 1aa6f1af81 fix(PIByteArray): prevent OOB in fromBase64 with non-multiple-of-4 input
The buffer was sized as floor(sz/4)*3 but the loop ran ceil(sz/4)
times, writing 3 bytes per iteration. For sz%4!=0, this wrote past
the buffer end. Also guarded sz<4 to avoid processing trivially
short or malformed input.
2026-08-06 17:01:30 +03:00
andrey 5e4a55cc0c fix(PIThread): remove spurious unlock() in _waitForFinish
The function called unlock() on thread_mutex without a matching
lock(), causing UB on Windows (releasing an unowned critical
section) or silently dropping a user-held lock.
2026-08-06 17:01:30 +03:00
andrey 31ae52623d fix(PIConditionVariable): clamp negative timeout in waitFor
When elapsed time exceeded the timeout, the remaining milliseconds
expression went negative and was implicitly converted to DWORD,
wrapping to ~0xFFFFFFFF (5 days) — effectively INFINITE.
Now clamps to 0 and returns false when time has elapsed.
2026-08-06 17:01:30 +03:00
andrey 4d9cd20ac5 fix(PIDir): initialize list pointer and check scandir return
dirent** list was uninitialized, so scandir failure (returning -1)
left it with indeterminate value. The unconditional free(list) at
the end was then UB — typically heap corruption or crash.
2026-08-06 17:01:30 +03:00
andrey 3e72f4e533 fix(PIBitArray): guard pop_back() against empty array
pop_back() called resize(size_ - 1) without checking for empty.
On empty array, uint underflow produced UINT_MAX, causing
bytesInBits(UINT_MAX) overflow and subsequent OOB access.
pop_front() already had this guard; pop_back() was missing it.
2026-08-06 17:01:30 +03:00
andrey c3cd9496dd fix(PIVariant): add missing break in setValueFromString switch
Three complex type cases (pivComplexf, pivComplexd, pivComplexld)
lacked break statements, causing fallthrough to pivTime. Setting
a complex variant from string silently overwrote the value with
PITime::fromString(), corrupting the variant's type and data.
2026-08-06 17:01:30 +03:00
andrey ef8fdb30f4 fix(PISharedMemory): reset data and unlink on mmap failure
When mmap() returned MAP_FAILED, data stayed as (void*)-1, causing
subsequent read/write/close to pass the null guard and crash.
Now resets data=nullptr, and calls shm_unlink when owner=true to
avoid orphaned shared memory objects.
2026-08-06 17:01:30 +03:00
andrey 9c3690d371 fix(PIFFT_float): correct plan entry size from 4 to 8
The float FFT plan generator wrote 8 ints per entry (indices +0..+7)
but declared entrysize=4, causing heap overwrite into the next entry
and incorrect plan array sizing.
2026-08-06 17:01:30 +03:00
andrey 288c1b3575 fix: Sender::tick accesses parent->diags_ without lock — data race / use-after-free 2026-08-06 17:01:30 +03:00
andrey f5cf06c200 fix: addDevice deletes read thread without stopAndWait — race on dev close/open 2026-08-06 17:01:30 +03:00
andrey 4f601a9408 fix: removeAllFilters holds lock during delete — move destructors outside lock scope 2026-08-06 17:01:30 +03:00
andrey c3491cbf6f fix: PISingleApplication TOCTOU — two shm reads replaced with single atomic read 2026-08-06 17:01:30 +03:00
andrey 96f0221051 fix: PIStreamPacker division by zero when max_packet_size is 0 2026-08-06 17:01:30 +03:00
andrey 9680bb2af8 fix: remove unreachable return false in PICrypt::verifySign()
fix picrypth
2026-08-06 17:01:30 +03:00
andrey cb5530c864 fix: writePipe loses data on partial write > PIPE_BUF 2026-08-06 17:01:30 +03:00
andrey 736acbd419 fix: interfaceAddress buffer overflow on long interface names 2026-08-06 17:01:30 +03:00
andrey 27ed1bc9a7 fix: SIOCGIFMTU passes int* instead of ifreq* (Android) 2026-08-06 17:01:30 +03:00
andrey 38253effc6 fix: SIOCGIFNETMASK reads ifr_addr instead of ifr_netmask 2026-08-06 17:01:30 +03:00
andrey 6d75d10ec8 fix: PICAN openDevice buffer overflow in ifr_name 2026-08-06 17:01:30 +03:00
andrey 7dd3cb5ee4 small fixes 2026-08-06 17:01:30 +03:00
andrey 1ddec15b87 threadsafe fixes 2026-08-05 19:48:01 +03:00
andrey 3f293ebd65 fix(PIFileTransfer): validate file id before array access
processFile() accessed files_[id - 1] without validating id.
When id == 0 (from a crafted network packet), id - 1 = -1 caused
out-of-bounds access. Added bounds check: id must be in range
[1, files_.size()]. Stops receive and logs error on invalid id.
2026-08-05 17:39:38 +03:00
andrey 27a9f05d65 fix(PIProcess): handle fork() failure (return value -1)
fork() can return -1 on error (too many processes, out of memory).
The old code treated pid_ == -1 as a successful fork, entering the
parent branch and calling waitpid(-1, ...) which waits for ANY
child process. Added explicit check: close pipes, free memory,
and return on fork failure.
2026-08-05 17:39:38 +03:00
andrey 13a9a75f79 fix(PISerial): break infinite loop when readDevice returns <= 0
In the blocking read path (timeout_ms <= 0), the while loop had no
exit condition for readDevice() returning 0 (EOF) or -1 (error).
This caused an infinite busy-loop at 100% CPU. Added 'else break'
to exit the loop on read failure, matching the timeout branch
which already handles this case.
2026-08-05 17:39:37 +03:00
andrey b2e637ee2b fix(PIIOByteArray): advance pos by actual bytes read, not requested size
readDevice() did pos += size instead of pos += ret. The clamping
on the next line (pos = min(pos, data_->size_s())) masked the
issue in practice, but the semantics were wrong. Aligns with
writeDevice() which correctly uses pos += rs.size_s().
2026-08-05 17:39:37 +03:00
andrey 9cd56ab66c fix(PIEthernet): check open() return value with >= 0 instead of != 0
open() returns -1 on error. The check fd != 0 treated -1 as a
valid fd (since -1 != 0 is true), causing devctl(-1, ...) and
close(-1) on QNX. Fixed to fd >= 0.
2026-08-05 17:39:36 +03:00
andrey e05abf16b5 fix(PIWaitEvent): use -1 as pipe_fd sentinel instead of 0
File descriptor 0 is stdin (a valid fd). Using 0 as the 'not-open'
sentinel caused isCreate() to return false and destroy() to skip
close() when pipe() happened to allocate fds {0, 1} (e.g. in daemons
with closed stdio). POSIX convention: -1 = invalid fd.
2026-08-05 17:39:36 +03:00
andrey 6c5c4b73e0 fix(PIClientServer): delete PIEthernet when client_factory returns nullptr
When the custom client_factory() returned nullptr, the incoming
PIEthernet pointer was leaked. Matches existing pattern used in the
max_clients overflow branch.
2026-08-05 17:39:35 +03:00
andrey e89ae88f3a fix(PICAN): align socket handling with PIEthernet patterns
- Sentinel: sock = 0 → sock = -1 (0 is stdin, valid fd)
- openDevice(): close socket on ioctl/bind failure (resource leak)
- openDevice(): set O_NONBLOCK via fcntl after socket()
- openDevice(): check setsockopt() return value
- closeDevice(): call shutdown() before close(), reset sock to -1
- readDevice() / writeDevice(): guard against sock == -1
- Add missing #include <fcntl.h>
2026-08-05 17:39:35 +03:00
andrey 216109b8ed fix(PIString): initialize toChar() return value and fix operator+= OOB
- toChar(): char v was uninitialized, causing UB when
  sscanf fails to match (empty string). Initialize to 0.

- operator+=(PIConstChars): loop iterated l < d.size() instead of
  l < str.size(), reading past the end of str after d.enlarge().
  This is a heap buffer overread with undefined behavior.
2026-08-05 17:39:34 +03:00
andrey 3603f6df13 fix piwaitevent 2026-08-05 12:59:36 +03:00
andrey 427130e2ca fix 2 2026-08-05 12:48:40 +03:00
andrey 42dd5945dd review fixes 2026-08-05 12:46:43 +03:00
andrey ec98963347 Revert "fix select usage"
This reverts commit 9da2d4fdb3.
2026-08-05 12:45:46 +03:00
andrey dc69ebe5ae fix memleak in PIEthernet::interfaces for android 2026-08-05 12:06:03 +03:00
andrey 11d6f7b0db piethernet replace inet_ntoa by threadsafe inet_ntop 2026-08-05 12:05:09 +03:00
andrey c53f1d39aa fix piethernet blocking write return value 2026-08-05 12:03:56 +03:00