You are viewing an old version of this page. View the current version.

Compare with Current View Page History

Version 1 Next »

Perl has three select() functions, with widely differing purposes. One form takes 4 arguments, and is a wrapper around the POSIX select(3) call. A second form takes zero arguments and returns the currently selected filehandle. This is the handle of the output stream used by print; it normally defaults to standard output. The third form takes one argument: a filehandle, and makes it the currently selected filehandle. That is, this form of select() changes the file that is used by all print statements (unless they each specify their own filehandle).

Modifying the filehandle used by print is counterintuitive, as subsequent print statements will no longer print to standared output. Furthermore, the globally selected filehandle is not garbage-collected, and remains open even if the filehandle itself goes out of scope. Therefore, do not modify the selected filehandle with select().

Noncompliant Code Example

This noncompliant code example tries to log a message while interacting with the user.

sub output_log {
  my $action = shift;
  open( my $log, ">>", "log.txt");
  select( $log);
  ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
  $year += 1900;
  $mon += 1;
  print "$year-$mon-$mday $hour:$min:$sec: $action\n";
}

# ...

print "Hello!\n";
output_log("Greeted user");
print "How are you?\n";

Unfortunately, the select() method causes the last print statement to print "How are you?" not to standard output, but to the log file.

Compliant Solution

This compliant solution avoids select() and directs the print() statement to use the log filehandle for output.

sub output_log {
  my $action = shift;
  open( my $log, ">>", "log.txt");
  ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
  $year += 1900;
  $mon += 1;
  print $log "$year-$mon-$mday $hour:$min:$sec: $action\n";
}

Noncompliant Code Example (autoflush)

This noncompliant code example uses the 1-argument select() function temporarily to modify the autoflush property associated with the file. The 1-argument select() returns the old filehandle (normally standard output). After the $log filehandle is selected, the modification of $| instructs Perl to autoflush everything sent to the $log filehandle. That is, every output to the $log filehandle is flushed immediately. After the modification, select() is called again to restore the original selected filehandle.

select(( select($log), $| = 1)[0]);

Compliant Solution

This compliant solution causes output to $log to be autoflushed without using select(). It uses the autoflush() object method from the IO::Handle module.

use IO::Handle;
# ...
$log->autoflush();

Risk Assessment

Failure to handle error codes or other values returned by functions can lead to incorrect program flow and violations of data integrity.

Recommendation

Severity

Likelihood

Remediation Cost

Priority

Level

EXP37-PL

medium

unlikely

medium

P14

L3

Automated Detection

Tool

Diagnostic

Perl::Critic

InputOutput::ProhibitOneArgSelect

Bibliography

[CPAN]. Elliot Shank, Perl-Critic-1.116. ProhibitOneArgSelect.
[Conway 2005], pg 224
[Wall 2011] perlfunc


EXP11-C. Do not apply operators expecting one type to data of an incompatible type      03. Expressions (EXP)      EXP13-C. Treat relational and equality operators as if they were nonassociative

  • No labels