local($?) in END blocks - Why does it matter what value was assigned to it?

perl, subroutine

Solution

Looks like a bug in perl. Apparently self assignment of `$?` in `local` is broken:

% perl -wle '$? = 123; print "before: $?"; local $? = $?; print "after: $?"'    
before: 123
after: 0

But this version works fine:

% perl -wle '$? = 123; print "before: $?"; local $? = $? + 0; print "after: $?"'
before: 123
after: 123

Pretty bizarre.

A bug report has been filed.

Problem

At work, we encountered an error when interacting with child processes in an object's destructor, and eventually traced it to the $? variable being overwritten during the wait calls. This happens after the call to exit(), so $? additionally meant our program's return code to the operating system. Specifically, the perldoc talked about this sort of error: Inside an END subroutine $? contains the value that is going to be given to exit(). You can modify $? in an END subroutine to change the exit status of your program. We don't want that to happen, so we put a `local $?=$?;` inside of every END block. But now the programs return success to the OS while actually failing in their given task. I managed to break it down into two sample programs. One that works as intended, and one that fails. This occurs on both v5.8.8 and v5.10.1 for x86_64-linux-thread-multi Program A: (returns 0 to the operating system) ``` END{ local $?=$?; } exit(100); ``` Program B: (returns 100 to the operating system) ``` END{ local $?=$?>>8; } exit(100); ``` Why does it matter what value was assigned to the `local $?` in the end block?

Original source