I'll report that as a misfeature
I read more documentation. You're right that it is listed as a feature, see perlvar. However you're right that it is very inconvenient. I'll suggest that that should be changed.
If you call exit with a value, you're absolutely right that you probably want to exit with that value. So Perl should set $? just before you exit.In the meantime you have 2 options. The first is to use POSIX and then call POSIX::_exit. This will skip all DESTROY and END blocks. The other is to make the following module the very first thing that you use. It will fix this bug.
\npackage FixExit;\nmy $exit_value;\nEND {\n$? = $exit_value if defined($exit_value);\n}\n\nsub my_exit {\n$exit_value = shift;\nCORE::exit();\n}\n\n*CORE::GLOBAL::exit = &my_exit;\n
(The latter is probably the best solution.)
Cheers,
Ben
PS This is something that was changed in the 5.8 series. In 5.6 and before, exit() did not run END blocks so the question never arose. Undoubtably someone made the change, thought that overriding $? in END blocks could be useful, and nobody thought about the fact that $? is set implicitly in lots of places, leading to surprising behaviour.