fix(oakengine): facade bugs found by integration tests

undo:
- NULL/empty label no longer crosses to oakundo as a dangling 0x1
  pointer (push, group_begin/end) — fixed SIGSEGV
- group_abort now undoes each executed child in reverse order

task:
- create_project_import addrefs the borrowed project handle instead of
  freeing it under the async task — fixed UAF/SIGSEGV

timeline:
- toggle_enabled/delete_clips guard NULL+0 slices — fixed SIGABRT
- BlockSplitCommand halves placed correctly (oaktimeline undosplit)
- PreservingLinks / ripple remove / ripple delete-gaps commands
  self-prepare on first redo — fixes silent no-op split/ripple
- trim_clips_to targets the block containing the point, not the track
- delete_empty_tracks applies the live track removal
- ripple facades no longer free borrowed track handles still referenced
  by commands — fixed UAF

node:
- project_add_node releases the factory handle — fixes per-call leak
- inputs_from(recursive=0) matches direct feeders (BFS off-by-one)
- group passthrough id/resolve treat two-stage string length as success
- node_connect(_command) reject duplicate connects with E_STATE
- folder_add_child enforces one-folder-per-node
- value_split_to_tracks splits vector/color per component
- set_context_position/expanded establish the first entry
- node_get_flags on an empty box returns 0, not u64::MAX
- footage_borrow addrefs its wrapper — fixes double-free

render:
- renderer_create rejects invalid pixel formats (real range check)
- render_frame forwards renderer width/height to the ticket

tests: repro #[ignore]s removed, bug-behavior assertions corrected,
it_undo global-stack tests serialized with a shared lock
This commit is contained in:
2026-08-11 01:30:18 +08:00
parent b564e7a71f
commit aa5fcef66e
13 changed files with 664 additions and 405 deletions
+9 -8
View File
@@ -193,12 +193,13 @@ pub unsafe extern "C" fn oakengine_renderer_create(
if seq.is_null() || width <= 0 || height <= 0 || frame_rate_num <= 0 || frame_rate_den <= 0 {
return Ok(std::ptr::null_mut());
}
// Validate the pixel format against the oakcommon format enum.
if crate::bridge::common::oakcommon_videoparams_get_format_name(
pixel_format,
std::ptr::null_mut(),
0,
) < 0
// Validate the pixel format against the oakcore enum. The
// oakcommon format_name lookup succeeds for ANY code (unknowns
// format as "Unknown (0x…)"), so only the real formats (U8..F32)
// are accepted; Invalid (-1), the Count sentinel (5) and garbage
// codes are rejected.
if pixel_format < oakcore_rs::PixelFormat::U8 as c_int
|| pixel_format > oakcore_rs::PixelFormat::F32 as c_int
{
return Ok(std::ptr::null_mut());
}
@@ -275,8 +276,8 @@ pub unsafe extern "C" fn oakengine_renderer_render_frame(
time_den: i64::from(b.frame_rate_num),
color_manager: CHandle::null(),
mode: b.mode,
force_width: 0,
force_height: 0,
force_width: b.width,
force_height: b.height,
force_matrix: [0.0; 16],
has_force_matrix: 0,
force_format: -1,