Skip to content

Fcntl_syscall updates #259

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

Merged
merged 11 commits into from
Jun 14, 2024
Merged

Fcntl_syscall updates #259

merged 11 commits into from
Jun 14, 2024

Conversation

ve1nard
Copy link
Contributor

@ve1nard ve1nard commented Jun 7, 2024

Description

Fixes # (issue)

The following changes include more elaborate comments and new unit tests for fcntl_syscall. Moreover, it was proposed to use "if let" construct instead of "unwrap" to get an entry from a file descriptor table to avoid "panic!" when provided with a file descriptor outside of the allowed range.

Type of change

  • Small fix for obtaining a file descriptor table entry without "panic!"
  • More detailed comments for fcntl_syscall
  • New unit tests for fcntl_syscall

How Has This Been Tested?

To run the tests, we need to run cargo test --lib command inside the safeposix-rust directory.

All the tests are present under this directory: lind_project/src/safeposix-rust/src/tests/fs_tests.rs

  • Test A - ut_lind_fs_fcntl_valid_args()
  • Test B - ut_lind_fs_fcntl_invalid_args()
  • Test C - ut_lind_fs_fcntl_invalid_fd()
  • Test D - ut_lind_fs_fcntl_dup()

Checklist:

  • My code follows the style guidelines of this project
  • I have commented my code, particularly in hard-to-understand areas
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • Any dependent changes have been added to a pull request and/or merged in other modules (native-client, lind-glibc, lind-project)

Copy link
Member

@JustinCappos JustinCappos left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The testing is good. I have a major style comment in the code itself, but much of it looks sound.

//instead, I propose using the 'if let' construct to be able to report an error to
//the user instead of simply panicking
//otherwise, file descriptor table entry is stored in 'checkedfd'
if let Ok(checkedfd) = self.get_filedescriptor(fd) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I like the philosophy here, but I think you want to reverse the if statement behavior so that you error out quickly, rather than continually nesting your if statement. This way one can much more easily read the code.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I write something like "if let Err() = self.get_filedescriptor(fd)", then in the "else", I will have to do pattern matching once again to extract checkedfd, which seems redundant. Should I use match instead?

Copy link
Member

@JustinCappos JustinCappos Jun 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would be an option.

I'm not a Rust expert, but code like this looks more "correct" to me. I'm very open to hearing from others, but certainly in Python, C, etc. it is preferred to do it in the style I've written.

//currently, O_CLOEXEC is the only defined file descriptor flag, thus only this flag is
//masked when using F_GETFD or F_SETFD
(F_GETFD, ..) => *flags & O_CLOEXEC,
// set the flags but make sure that the flags are valid
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure how this achieves your goal. Can you say more?

Copy link
Contributor Author

@ve1nard ve1nard Jun 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

F_GETFD command should return file descriptor flags only, which means that the returned value should not include access mode flags and file status flags, and because O_CLOEXEC is the only implemented file descriptor as of now, we can get it by bit-wise and'ing. Same logic applies to F_SETFD: because O_CLOEXEC is the only existing file descriptor flag, we need to check only it.

0 //TO DO: traditional SIGIO behavior
}
(F_SETOWN, arg) if arg >= 0 => {
0 //this would return the PID if positive and the process group if negative,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it set this or return it? Why do we do nothing?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I was talking to Yash, he suggested me that I should not focus on things that are not yet implemented, and that is why I left this part with F_SETOWN and F_GETOWN commands untouched. Should I work on them?

0
}
(F_DUPFD, arg) if arg >= 0 => self._dup2_helper(&filedesc_enum, arg, false),
//TO DO: implement. this one is saying get the signals
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which is saying to get the signals? What signals?

_ => syscall_error(
Errno::EINVAL,
"fcntl",
"Arguments provided do not match implemented parameters",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we list anything else useful like the arguments themselves?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you! I will include a (cmd, arg) tuple in the error message.

assert_eq!(cage.fcntl_syscall(filefd, F_GETFL, 0), 2048);

//when provided with 'F_GETFD' or 'F_GETFL' command, 'arg' should be ignored, thus even
//negative arg values should produce nomal behavior
//However, testing results in two errors
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, great! So this test will fail now, but after we fix the code later it will pass, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is my bad: everything works now and the test passes. I just forgot to delete this part of the comment.

@yashaswi2000
Copy link
Contributor

Please add documentation about the syscall, its arguments, return values and manpage link above the function definition.

@@ -1898,87 +1898,126 @@ impl Cage {
}

//------------------------------------FCNTL SYSCALL------------------------------------

//fcntl performs operations, like returning or setting file status flags,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great!

@yashaswi2000 , do you want to have the rustdoc changes be done in these edits or a different set of PRs? I do think that for new PRs, we likely should include them...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will refactor these first 3 PRs. and any new ones coming in will follow the template I will share with them.


if let Some(ins) = &mut sockhandle.innersocket {
let fcntlret;
if arg & O_NONBLOCK == O_NONBLOCK {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deep nesting. Is there a way we can avoid this?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No not easily. The rustfmt makes it looks worse than it is.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think clippy will suggest a way to change this pattern:

       match fd_table_entry_ptr {
            Err(()) => {
                syscall_error(Errno::EBADF, "fcntl", "File descriptor is out of range")
            },
            Ok(checkedfd) => {
                let mut unlocked_fd = checkedfd.write();
                ...

into an if let Ok(checkedfd) = fd_table_entry_ptr {...} in at least some cases. Here, it would unfortunately move the error condition to the end, so while this would reduce indentation, it isn't a 100% win...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems fine as it for now but may be part of a later refactor.

&mut sockfdobj.flags
}
};
&mut sockfdobj.flags
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove extra whitespace

@ve1nard ve1nard requested a review from rennergade June 13, 2024 20:34
Copy link
Contributor

@yashaswi2000 yashaswi2000 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

Copy link
Contributor

@rennergade rennergade left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved!

@rennergade rennergade merged commit c54156f into develop Jun 14, 2024
1 of 2 checks passed
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 this pull request may close these issues.

4 participants