This is an archive of the discontinued LLVM Phabricator instance.

[lldb/Host] Improve error messages on unowned read files
ClosedPublic

Authored by mib on Apr 23 2020, 7:07 AM.

Details

Summary

When trying to read a core file that is not owned by the user running lldb
and that doesn't have read permission on the file, lldb shows a misleading
error message:

Unable to find process plug-in for core file

This is due to the fact that currently, lldb doesn't check the file
ownership. And when trying to to open and read a core file, the syscall
fails, which prevents a process to be created.

Since lldb already have a portable open syscall interface, lets take
advantage of that and delegate the error handling to the syscall
itself. This way, no matter if the file exists or if the user has proper
ownership, lldb will always try to open the file, and behave accordingly
to the error code returned.

rdar://42630030

Signed-off-by: Med Ismail Bennani <medismail.bennani@gmail.com>

Diff Detail

Event Timeline

mib created this revision.Apr 23 2020, 7:07 AM
mib marked an inline comment as done.Apr 23 2020, 7:13 AM
mib added inline comments.
lldb/test/API/commands/target/basic/TestTargetCommand.py
343

Currently, I try to open the root user home directory, since I sure it's not readable by other users on UNIX systems.

I went this route, because doing a os.chown requires privileges, and the test suites doesn't run in a privileged mode.

I'm open to suggestions on how I could test this on different platforms.

mib edited the summary of this revision. (Show Details)Apr 23 2020, 7:14 AM
shafik added a subscriber: shafik.Apr 23 2020, 9:18 AM
shafik added inline comments.
lldb/source/Host/common/FileSystem.cpp
504 ↗(On Diff #259557)

Since file is a FileSpec can't we just use ReadableByCurrentUser(const FileSpec &file_spec) here?

mib marked 2 inline comments as done.Apr 23 2020, 9:26 AM
mib added inline comments.
lldb/source/Host/common/FileSystem.cpp
504 ↗(On Diff #259557)

Good catch!

mib updated this revision to Diff 259606.Apr 23 2020, 9:28 AM
mib marked an inline comment as done.

Address Shafik's comment.

mib updated this revision to Diff 259608.Apr 23 2020, 9:32 AM

I'm not very fond of this reverse engineering of the checks that os performs when opening a file (this is not the only place doing it). Could we just make sure that the operation for opening a file returns a reasonable error message, and then do something like

Status /*or Error, or Expected...*/ error = File::Open(core);
if (error)
  SetErrorStringWithFormatv("Cannot open {0}: {1}.", core, error);

?

If done right, that should produce messages like:

Cannot open /my/core.file: File does not exist.
Cannot open /my/core.file: Permission denied.
Cannot open /my/core.file: Is a directory.
...

It may not as "user friendly" as "file is not readable by the current user", but it will at least be correct (it's not a problem to come up with situations where this file will be readable by the "current user", but we will not print this error message, and vice-versa), and it will also match what other tools are likely to print. Plus it will be composable, and involve less code at each call site.

lldb/source/Host/common/FileSystem.cpp
503 ↗(On Diff #259608)

This is not the correct way to work with Twines. If you want to try to be efficient, you should call toStringRef (there are examples of how to do that throughout llvm). If you don't care about that, you can call str().

lldb/test/API/commands/target/basic/TestTargetCommand.py
343

if you set the mode of a file to 0000, you won't be able to open it even if you are still its owner.

mib updated this revision to Diff 260751.Apr 28 2020, 2:03 PM
mib edited the summary of this revision. (Show Details)

Removed the introduced FileSystem::ReadableByCurrentUser to rely only FileSystem::Open as Pavel suggested.
Updated the tests to reflect the changes introduced.

I also prefer this approach, seems less fragile from a testing perspective and reduces the different code paths.

lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp
102 ↗(On Diff #260751)

We should be consistent with the braces, both clauses are single-line. Personally I'd refactor the code and make this an early return instead.

187 ↗(On Diff #260751)

Not your fault, but it seems weird that we're doing this check after using the resolved_module_spec and only if it failed.. Shouldn't we try to read it first and stop early if that fails?

Yes, this is definitely better.

lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp
187 ↗(On Diff #260751)

In an ideal world the actual operation which tries to create the module would return an error and we would use that. That way we wouldn't be accessing the file twice, and creating opportunities for inconsistencies (or races). In that sense, this code is still trying to "reverse engineer" why the earlier operation failed, but I think it is a step forward, as it reduces the amount if reversing.

195 ↗(On Diff #260751)

I guess this should be also updated to use the error message from the os(?)

lldb/test/API/commands/target/basic/TestTargetCommand.py
329

Now that the error message comes from the OS, we might need to adjust the expectation based on that. Just an FYI, in case you get some failure message from some bot (most likely the windows one).

342

This is not testing an unowned file anymore, and is probably redudant given the test above it. Given that the new implementation does not do anything special wrt. ownership, I don't think an explicit test for those.

mib updated this revision to Diff 261384.Apr 30 2020, 4:09 PM
mib marked 7 inline comments as done.

Removed redundant test.
Refactored PlatformPOSIX following Jonas and Pavel's comments.

JDevlieghere accepted this revision.May 1 2020, 9:10 AM

Looks good to me.

This revision is now accepted and ready to land.May 1 2020, 9:10 AM
labath added a comment.May 4 2020, 2:13 AM

I'm not sure this new version is for the better :(.

Error and Expected objects have a contract where you're supposed to "consume" each object before you destroy or reassign it. The complex control flow in that function makes it very hard to see that this is really the case. I marked the cases where I believe you didn't do that, but I can't be sure I found all of them. For this kind of pattern to work there'd need to be more refactoring of the function in order to make the lifetime and state of the expected object more obvious. That's why I wasn't pushing for this direction in my previous comment...

lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp
96 ↗(On Diff #261384)

here you'll need to do a consumeError(resolved_module.takeError()) before you can reuse the object.

124 ↗(On Diff #261384)

error not consumed here

197 ↗(On Diff #261384)

error not consumed here.

mib updated this revision to Diff 261775.May 4 2020, 3:35 AM
mib marked 3 inline comments as done.

Add error "consumption" following @labath comment.

mib updated this revision to Diff 261815.May 4 2020, 7:42 AM

As agreed on IRC with @labath, the changes done to PlatformPOSIX::ResolveExecutable will be removed from this patch and submitted separately.

labath accepted this revision.May 4 2020, 8:08 AM

Yeah, as I said, I think this is already an improvement, which I am not sure that could be said of the other version, because of the expected-handling complexities. LGTM, modulo the overzealous conversion to AppendError.

lldb/source/Commands/CommandObjectTarget.cpp
417

I guess this should stay as AppendMessage

mib marked an inline comment as done.May 4 2020, 8:35 AM