Why not a different calling convention? Push the arguments onto the stack followed by an integer saying how many arguments there are. Then it will be impossible to mistakenly pop off too many or too few.
This would slow down function calls a little bit, but it could be used as an alternative calling convention for varargs functions only. There would still be format string vulnerabilities, but this particular class of them would go away.