Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

S_ISENFMT from Fcntl makes no sense #22190

Open
mauke opened this issue May 3, 2024 · 0 comments · May be fixed by #22202
Open

S_ISENFMT from Fcntl makes no sense #22190

mauke opened this issue May 3, 2024 · 0 comments · May be fixed by #22202

Comments

@mauke
Copy link
Contributor

mauke commented May 3, 2024

Module: Fcntl

Description

Fcntl provides a S_ISENFMT function that makes no sense. If it exists at all (depends on whether your platform defines S_ENFMT), it always returns false. It should just be removed from Fcntl (and not mentioned in perlfunc/stat).

Background

If you want to get the type of a file in C, you get its st_mode from stat or lstat, apply the S_IFMT mask (filtering out the non-type bits), then compare the result to one of the other S_IF* constants:

if ((x.st_mode & S_IFMT) == S_IFREG) {
    // it's a regular file
}

This is annoying enough that C provides additional S_IS* helper macros, one for each type of file:

if (S_ISREG(x.st_mode)) {
    // it's a regular file
}

Perl's Fcntl module provides the same interface (mostly) with subroutines:

use Fcntl qw(:mode);
if (($mode & S_IFMT) == S_IFREG) {
    # it's a regular file
}
if (S_ISREG($mode)) {
    # it's a regular file
}

However, Fcntl also defines a S_ISENFMT function that doesn't correspond to anything in nature (C).

On some platforms, there is an S_ENFMT ("enforcement of file locks") constant, which indicates that record locks placed on this file are mandatory, not advisory. It typically shares its value with S_ISGID ("set group id") because the combination of a non-executable file with the setgid bit set is not otherwise meaningful. Note that this bit is part of the file permissions, not of its type! That's why there is no corresponding S_ISENFMT macro for it.

Perl's S_ISENFMT was originally added in ca6e1c2 (presumably by mistake), defined as:

sub S_ISENFMT  ($) { ( $_[0] & _S_IFMT ) == S_ISENFMT }

(Note that it's trying to compare to a non-existent S_ISENFMT constant. This went unnoticed because Fcntl didn't use strict.)

This code was subsequently "fixed" in 0e6f150, changing it to:

sub S_ISENFMT  { ( $_[0] & _S_IFMT ) == S_IFENFMT }

(Note the change to S_IFENFMT, which still doesn't exist because S_ENFMT is not a file type.)

Then 0f68039 added use strict and changed the code to:

sub S_ISENFMT  { ( $_[0] & _S_IFMT() ) == S_IFENFMT() }

So now it is trying to call a non-existent S_IFENFMT subroutine.

It got further "fixed" by fb59364:

sub S_ISENFMT  { ( $_[0] & _S_IFMT() ) == S_ENFMT()   }

Finally, S_ENFMT is a constant that actually exists (on some platforms)! So now it is possible to actually use S_ISENFMT without getting a runtime error. Unfortunately the code still makes no sense: $_[0] & _S_IFMT extracts the file type bits, but S_ENFMT is not a file type, so this comparison always returns false.

In 87eca6e, the whole logic was moved from Perl to XS code, but it still fails the same way: It always returns false at runtime. (If your platform defines S_ENFMT, that is; otherwise S_ISENFMT just isn't defined at all.)

Steps to Reproduce

$ perl -e 'use Fcntl qw(S_ISENFMT)'
$

Expected behavior

$ perl -e 'use Fcntl qw(S_ISENFMT)'
"S_ISENFMT" is not exported by the Fcntl module
Can't continue after import errors at -e line 1.
BEGIN failed--compilation aborted at -e line 1.
mauke added a commit to mauke/perl5 that referenced this issue May 9, 2024
S_ISENFMT($mode) has no equivalent C macro. It was implemented (in XS)
as the equivalent of `($mode & S_IFMT) == S_ENFMT`, which is always
false because S_ENFMT is not a file type and thus not covered by the
S_IFMT mask.

(See commits ca6e1c2, 0e6f150, 0f68039, fb59364, 87eca6e for the history
of this function, which has always been broken in various ways ever
since it was added in 2000.)

Fixes Perl#22190.
@mauke mauke linked a pull request May 9, 2024 that will close this issue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant