Here's another instance where we were calling fflush on an input
stream, which is illegal on NetBSD.
Details
Diff Detail
- Repository
- rG LLVM Github Monorepo
Event Timeline
I'm sorry but I won't be able to test it until later today. Visually, looks good though.
lldb/packages/Python/lldbsuite/test/python_api/file_handle/TestFileHandle.py | ||
---|---|---|
854 | For the record, this doesn't really guarantee specific order of destruction. Generally, in Python code you shouldn't rely on destructors being called at all and close files manually. That's why with is commonly used with files. |
lldb/packages/Python/lldbsuite/test/python_api/file_handle/TestFileHandle.py | ||
---|---|---|
854 | The point is not to rely on the file being closed at a certain time. They point is that each file added to the list is a borrowed reference to the previous one, and we should not allow those references to become dangling by letting the older ones go to zero-references before the younger ones. Now that I say it, I wonder if it was a bad idea to expose this kind of C++ object lifetime semantics to python programs. It might be better to restrict it to that case, and return None instead of a borrowed file in other cases. On the other hand, there's value in having a consistent API. Under the current semantics this just works: print("foo", file=debugger.GetOutputFile().GetFile()) Overall I think I'd lean towards keeping GetFile the way it is, but I can see the argument for restricting it. |
lldb/packages/Python/lldbsuite/test/python_api/file_handle/TestFileHandle.py | ||
---|---|---|
854 | On second second thought, there's a better way. We don't need to expose the borrow semantics, and we don't need to restrict GetFile like that. We can do the same thing File.cpp does when you ask it for a FILE* on a borrowed FD -- that is, use dup and create one that python can truly own. |
Thanks but I'd personally prefer splitting this into a future commit, in case it introduced unrelated issues.
I am not thrilled by all of that duping going around. Having multiple FILE objects means that you have multiple independent file caches too. That can cause different kinds of strange behavior if multiple things start reading/writing to the different FILE objects simultaneously. I think I'd rather just keep the existing borrow semantics. I don't think that should be a problem in practice -- it's just that this test is weird because is testing the extreme cases of this behavior (which is fine). Normally you'll just use one level of wrapping and so the underlying file will be naturally kept around, since lldb will still be holding onto it.
I'm not exactly thrilled with it but I will still argue it is the right thing to do. If you look at the docstring for GetFile, it doesn't mention this problem. It says you can't use a borrowed file if it becomes dangling, but it doesn't say you have to delete your references to it before it can dangle. That's because this problem is surprising enough that neither of us thought of it.
Consider this situation: The python programmer makes an object that keeps a reference to debugger and also to debugger.GetOutputFile().GetFile(). When they're done with the object they destroy the debugger and let their object go out of scope.
In python3, they may get an IOError at this point, as the saved output file tries to flush its buffer to a closed file. In python 2 they are exposed to to a use-after free violation and the program could crash!
It is very difficult to write python programs that deal with these kind of semantics correctly, and nothing about this API suggests that it is as dangerous to use as that. I think the correctness and ergonomics concerns outweigh the performance concerns here. Particularly because this issue only affects python 2. Is it really a bigger deal that we generate some extra dups on an end-of-life scripting language than that we potentially crash on that language?
I have confirmed that your previous revision fixed the problem in question. The newer one would probably require full test suite run which I can't do right now. As I said, I would prefer those two changes to be committed separately, preferably with a few hours delay so that it would be clear if it causes any breakage on buildbot.
Diff 4, I think. Lemme do a quick test with 5. Hopefully it won't request me to rebuild everything again.
For the record, this doesn't really guarantee specific order of destruction. Generally, in Python code you shouldn't rely on destructors being called at all and close files manually. That's why with is commonly used with files.