Environment
$ date
r2 -v
uname -ms
Fri 18 Sep 01:14:14 BST 2026
radare2 6.2.2 +37545 abi:142 @ linux-x86_64
birth: git.6.2.2 2026-09-17__17:41:32
commit: ad27058877024389292fddf12e1db6e13824ba34
options: gpl -O? cs:5 cl:2 make
Linux x86_64
Description
On x86-16, the default calling convention is fastcall.
If a function is first analysed with af, radare2 recovers a generic BP-relative argument under that convention.
Changing the function to cdecl afterwards and running afva does not reconcile the existing autogenerated variable with the known typed prototype.
The function signature is correct: int typed16 (short value);
but the recovered variable remains generic: arg int16_t arg_4h @ bp+0x4
The expected variable is:
Repeated afva calls leave the stale name and type unchanged.
This was found while testing #26747 after the typed-function recovery change.
Further debugging shows that the 2-byte slot calculation is correct: during cdecl recovery, ptr=4, bp_off=2, and frame_off=2. The problem is that the existing generic variable causes recovery to return before the prototype argument can be applied.
This appears related to, but distinct from, #19595. #19595 reports a false-positive ax register argument in x86-16 analysis; this report is about stale BP-variable metadata after changing the function calling convention.
Potential area of change
When a function's calling convention changes, invalidate or reconcile autogenerated argument variables.
For typed functions, afva could replace a default arg_* name/type when the variable's recovered storage slot matches a
declared prototype argument, while continuing to preserve explicitly renamed or retyped variables.
Test
The test uses a conventional 16-bit frame:
push bp
mov bp, sp
sub sp, 2
mov ax, word [bp+4]
mov word [bp-2], ax
leave
ret
Minimal reproduction:
r2 -NN -q -a x86 -b 16 malloc://32
wx 5589e583ec028b46048946fec9c3
f typed16
td int typed16(short value);
af
afc cdecl
afva
afcf
afvb
Actual output:
int typed16 (short value);
arg int16_t arg_4h @ bp+0x4
var int16_t var_2h @ bp-0x2
Running afva again produces the same result.
Control
If variable recovery is disabled until after the correct calling convention is
selected, the prototype is mapped correctly:
wx 5589e583ec028b46048946fec9c3
f typed16
td int typed16(short value);
e anal.vars=false
af
afc cdecl
e anal.vars=true
afva
afcf
afvb
Output:
int typed16 (short value);
arg short value @ bp+0x4
var int16_t var_2h @ bp-0x2
Deleting the recovered variables before retrying also works:
Environment
$ date r2 -v uname -ms Fri 18 Sep 01:14:14 BST 2026 radare2 6.2.2 +37545 abi:142 @ linux-x86_64 birth: git.6.2.2 2026-09-17__17:41:32 commit: ad27058877024389292fddf12e1db6e13824ba34 options: gpl -O? cs:5 cl:2 make Linux x86_64Description
On x86-16, the default calling convention is
fastcall.If a function is first analysed with
af, radare2 recovers a generic BP-relative argument under that convention.Changing the function to
cdeclafterwards and runningafvadoes not reconcile the existing autogenerated variable with the known typed prototype.The function signature is correct:
int typed16 (short value);but the recovered variable remains generic:
arg int16_t arg_4h @ bp+0x4The expected variable is:
Repeated
afvacalls leave the stale name and type unchanged.This was found while testing #26747 after the typed-function recovery change.
Further debugging shows that the 2-byte slot calculation is correct: during cdecl recovery,
ptr=4,bp_off=2, andframe_off=2. The problem is that the existing generic variable causes recovery to return before the prototype argument can be applied.This appears related to, but distinct from, #19595. #19595 reports a false-positive
axregister argument in x86-16 analysis; this report is about stale BP-variable metadata after changing the function calling convention.Potential area of change
When a function's calling convention changes, invalidate or reconcile autogenerated argument variables.
For typed functions,
afvacould replace a defaultarg_*name/type when the variable's recovered storage slot matches adeclared prototype argument, while continuing to preserve explicitly renamed or retyped variables.
Test
The test uses a conventional 16-bit frame:
Minimal reproduction:
wx 5589e583ec028b46048946fec9c3 f typed16 td int typed16(short value); af afc cdecl afva afcf afvbActual output:
int typed16 (short value); arg int16_t arg_4h @ bp+0x4 var int16_t var_2h @ bp-0x2Running
afvaagain produces the same result.Control
If variable recovery is disabled until after the correct calling convention is
selected, the prototype is mapped correctly:
wx 5589e583ec028b46048946fec9c3 f typed16 td int typed16(short value); e anal.vars=false af afc cdecl e anal.vars=true afva afcf afvbOutput:
int typed16 (short value); arg short value @ bp+0x4 var int16_t var_2h @ bp-0x2Deleting the recovered variables before retrying also works: