Hacker News new | ask | show | jobs
by draegtun 5256 days ago
re: open() creating temporary file if file arg is undef

Fortunately both IO::File (core module) & Path::Class don't do this:

  use IO::File;
  my $fh = IO::File->new( $config->{file_path}, 'r' ) 
             or die "can't open $config->{file_path}: $!";
  
  
  use Path::Class qw<file>;
  my $fh = file( $config->{file_path} )->openr;
Both above spot the undef gotcha. NB. And ->openr() throws an exception.

ref: https://metacpan.org/module/IO::File | https://metacpan.org/module/Path::Class

2 comments

> Both above spot the undef gotcha.

The builtin open() even tries to spot when it's not intentional. The documentation puts "undef" in quotations in the section where it introduces the feature (suggesting it has to be the literal), and the implementation goes to some effort to agree with it. For example, the following code dies:

  my $config = { file_paht => "/opt/config" };
  my $path = $config->{file_path};

  open (my $fh, "<", $path)
    or  die "can't open $path: $!";
In the case in the article it's a bug in the implementation, combined with a typo, which introduces the little known feature.

Using Path::Class obfuscates the open, to my eyes. Using IO::File is a nice suggestion. Your lock_keys suggestion below will probably be our update to the code for future protection, though.

re: Path::Class - Each to their own :)

However you can take your original full example of this:

  open (my $fh, "<", $config->{file_path})
    or  die "can't open $config->{file_path}: $!";

  my $data;
  {
    local $/ = undef;
    $data = <$fh>;
  }
And turn it into just this with Path::Class

  use Path::Class 'file';
  
  my $data = file( $config->{file_path} )->slurp
  
When dealing with lots of files/directories especially across different platforms I find Path::Class a god send.

NB. One good habit I currently do have is using Path::Class more ubiquitously :)

!!! Supplementary for future readers of this comment thread !!!

The pragma autodie also spots this problem!

So....

    use strict;
    use warnings;
    use autodie;

    our $config;
    $config->{file_paht} = "somefile";

    open my $fh, '<', $config->{file_path};
Will throw an exception at open(). NB. Bizarrely the error is Use of uninitialized value $file in sprintf... but hey the problem is still caught :)