-
Notifications
You must be signed in to change notification settings - Fork 168
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
Throw an exception if File::unlock has failed + use same logic for all platforms, for detecting when we hold a lock on a file #6926
Throw an exception if File::unlock has failed + use same logic for all platforms, for detecting when we hold a lock on a file #6926
Conversation
965bc68
to
2dcd03f
Compare
2dcd03f
to
36b1885
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we are touching this: are there any other assertions in the file which could potentially be exceptions?
Probably, but I would not touch them to be honest, as long as we don't have a clear API that is constantly breaking, probably it is not really worth to throw an exception. If we run in one syscall failure, it is very likely that we can't recover... all this PR does is to give a better user experience, rather than crashing brutally, the user will be informed that there is a problem. |
fb4ba1f
to
70d56f9
Compare
@kiburtse I don't think it is safe to keep using realm after this exception. The whole point is to stop crashing all suddenly without giving any information. |
If that's the case then i doesn't make any sense to turn it into the exception. The original issues were filled due to unawareness about android security restrictions. So really detailed error message and suggestion were missing in general unlock assertion. What's the point of throwing exception if user code can recover and try to use realm again? After this assertion InterprocessMutex and DB are going to be in a half-interrupted state. If we can't guarantee that DB object is usable after that exception and application must be restarted, then it should not be allowed, otherwise we will get other crashes and bugreports after this, which doesn't make any sense to me. So once again, it's crashing because fundamental security policy for application is violated by user code - and it's preventable. What was missing is some helpful information for this situation, so augmented assertion message should suffice. UP: just to clarify what was my original intention in the issue discussion... Since unlock is just a method in File, we could possible check needed operation on file path in constructor and throw pretty descriptive error earlier on File object construction rather than thinking about how to bail out half way through. Or even better: earlier still on realm initialization from the path. |
To clarify, on Java and Kotlin (dunno for Dart) we don't print any stack trace as far as I know, so when we crash, the user just gets a generic failure on libRealm, which is difficult to navigate, thus adding a better message in the assertion won't suffice. We need to trigger an exception. We can then debate whether trigger this only for Android or for all the platforms (IMO for all the platforms) ... also preventing a possible failure is not necessarily a good thing to do, the system call could fail for any reason. I am not in favour of trying to poke the file system before to use any system call. |
64136bf
to
325a3e4
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code looks good to me, but the comment should die or be updated.
325a3e4
to
b4ec87c
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, spotted two other things...
b4ec87c
to
bc7edfb
Compare
@@ -562,7 +563,8 @@ void File::close() noexcept | |||
|
|||
if (m_fd < 0) | |||
return; | |||
unlock(); | |||
if (m_have_lock) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
great! So that's what was the issue all along it seems.... We just don't need to lock at all for mentioned usecases in bug reports
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, but bear in mind that is very likely that since the system call for unlocking the file fails on certain circumstances, the same system call will eventually fail also when locking the file. So an exception will be thrown either way.
@@ -1098,7 +1100,16 @@ static void _unlock(int m_fd) | |||
do { | |||
r = flock(m_fd, LOCK_UN); | |||
} while (r != 0 && errno == EINTR); | |||
REALM_ASSERT_RELEASE_EX(r == 0 && "File::unlock()", r, errno); | |||
if (r) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So almost all good now, i'm not entirely convinced about this bit still.
We've almost misdiagnosed this issues 9th time in a row, do i understand it right? Essentially, we tried to unlock what we didn't lock (most likely from bugreports) since it wasn't needed for Realm::convert (Realm.writeCopyTo in java/kotlin sdks).
And since the assumption was that unlock is noop if file is not locked, we called it unconditionally every time and it was fine until new storage restrictions in Android hit and this syscall started to fail. So we were crashing apps for no reason for few years already.
Under #5107 and realm-java#6893 it was already mentioned that users activated needed permissions, and it was still crashing. To me this case already looks irrelevant, since we're not going to hit exact same code path now. The message may still be relevant for some realm opening scenarios though. @cmelchior could you confirm this?
Also, it seems that sqlite3 essentially ignored the result of unlock call failure (although logs it still internally) on close at least. The same seems to be true for windows where in most cases the return result is ignored, and it never asserts or propages further.
Exception in this case not much better that assertion. @finnschiermer shouldn't we just dump the error into logger, but essentially ignore it? Why interrupt any flow here?
@nicola-cab please, it's been a long issue if we account for very first bug reports, could you justify why do you think it is still needed here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to throw an exception for 2 reasons.
a) it is just a much better user experience, image that you are developing your app and your app crashes without any apparent reason, what would you do? ... most probably open an issue in order to try to understand what's going on.
b) this is a limitation of some SDKs, but impacts also us, they don't easily print error messages that are coming from our ASSERTIONS. Yes, there are some ways for the developer to check the system logs, but I would not rely on that, and surely we can't grab those logs from the device ourselves.
Ignoring the error can be a viable option, but I don't think it is correct. IMO we need to merge this PR in our code.
Further check is need what can be supported on external android storage.
What, How & Why?
Mitigate issues like this: #6912
☑️ ToDos