fix: add AdDragParams size guard and document the ABI breaks

AdDragParams gained a drop_delay_ms field but, unlike AdRefEntry, had no size
guard — an old caller's smaller allocation would let Rust read past it and turn
stack garbage into a real drop delay. Add AD_DRAG_PARAMS_SIZE, ad_drag_params_size(),
a compile-time layout assertion, and a zero-init note, matching the ref-entry
pattern.

This branch makes several consumer-visible contract changes that release
tooling must cut as a major. They are gathered here because the release workflow
ships the C header as an artifact.

BREAKING CHANGE: the C ABI and CLI/JSON contract changed on this branch.
- AdPolicyKind: AD_POLICY_KIND_PHYSICAL is renamed AD_POLICY_KIND_HEADED
  (discriminant 2 unchanged, so compiled binaries are safe; source-level C
  consumers must rename). No back-compat alias is kept — "physical" is gone.
- AdRefEntry grew (caller-allocated input); validate layout with
  AD_REF_ENTRY_SIZE / ad_ref_entry_size().
- AdDragParams grew; validate with AD_DRAG_PARAMS_SIZE / ad_drag_params_size()
  and zero-initialize before use.
- close-app graceful response no longer includes closed:true; it returns
  { method: "graceful", requested: true } because a graceful quit cannot be
  synchronously confirmed.
This commit is contained in:
Lahfir 2026-06-10 03:54:38 -07:00
parent d0371caaec
commit 57edc0d470
2 changed files with 24 additions and 0 deletions

View file

@ -196,6 +196,12 @@ typedef struct AdPoint {
double y;
} AdPoint;
/*
* Caller-allocated drag parameters. Zero-initialize the whole struct before
* setting fields: `duration_ms`/`drop_delay_ms` treat 0 as the adapter-default
* sentinel, so stack garbage in an unset field would become a real delay.
* Validate layout with `AD_DRAG_PARAMS_SIZE` / `ad_drag_params_size()`.
*/
typedef struct AdDragParams {
struct AdPoint from;
struct AdPoint to;
@ -205,6 +211,10 @@ typedef struct AdDragParams {
uint64_t drop_delay_ms;
} AdDragParams;
#define AD_DRAG_PARAMS_SIZE (sizeof(AdDragParams))
uintptr_t ad_drag_params_size(void);
/**
* Action dispatched by `ad_execute_action`.
*

View file

@ -1,6 +1,11 @@
use crate::types::point::AdPoint;
use agent_desktop_core::action::{DragParams as CoreDragParams, Point as CorePoint};
/// Caller-allocated drag parameters. Callers must zero-initialize the whole
/// struct before setting fields so unset numeric fields read as the `0`
/// adapter-default sentinel rather than stack garbage. Verify layout against
/// `AD_DRAG_PARAMS_SIZE` / `ad_drag_params_size()` when binding from a language
/// whose struct layout may diverge.
#[repr(C)]
pub struct AdDragParams {
pub from: AdPoint,
@ -9,6 +14,15 @@ pub struct AdDragParams {
pub drop_delay_ms: u64,
}
pub const AD_DRAG_PARAMS_SIZE: usize = 48;
const _: () = assert!(std::mem::size_of::<AdDragParams>() == AD_DRAG_PARAMS_SIZE);
#[unsafe(no_mangle)]
pub extern "C" fn ad_drag_params_size() -> usize {
std::mem::size_of::<AdDragParams>()
}
impl AdDragParams {
/// Converts the C drag params into the core type. `duration_ms` and
/// `drop_delay_ms` use `0` as the "adapter default" sentinel because the