Google "atomicity" and "race case" for more information, but here's a brief way how that would die: (P1 is process 1, P2 is process 2, they're not actually in the same program, but the commands from each are interleaved here since that can happen in reality)
P1: my $lflag = ( -l 'foo' ); # seems good
P2: makes foo a link - uh oh!
P1: $lflag or open my $fh, ">>foo"; # does it fine, since $lflag was s
P2: remove that link, lickity-split!
P1: $lflag = ( -l 'foo' ); # whups, everything *seems* ok...
Make sense? Dave_the_m's code will exactly perform the actions for P2, btw. (Eimi's earlier explanation did exactly what your code does, too - look it over, the -l check happens before and