-
-
Notifications
You must be signed in to change notification settings - Fork 3.1k
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
wallet: prevent the same wallet file from being opened by multiple processes #3994
Conversation
I had an idea of doing this via advisory locks, which are cleared when a process ends. I'm not sure it can be done cross platform though. If the wallet crashes or gets killed, this lock file doesn't go away. Maybe that's good enough though. |
Advisory locks would certainly be cleaner. We had locking code for the blockchain in monerod before, can just troll thru git history and paste that in here instead. |
@moneromooo-monero @hyc I'm quite unfamiliar with Windows/Linux APIs so I might be using them inappropriately, but it seems to be working as far as I tested with Mac, Ubuntu and Windows. |
src/wallet/wallet2.cpp
Outdated
|
||
m_keys_file_locker.reset(); |
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.
I realized this temporary unlocking was necessary due to Windows (otherwise the file couldn't be loaded).
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.
Maybe add a comment saying so ?
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.
ok
src/common/util.cpp
Outdated
{ | ||
#ifdef WIN32 | ||
m_fd = INVALID_HANDLE_VALUE; | ||
WCHAR wide_path[1000]; |
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.
Is there no PATH_MAX for Windows ?
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.
This was copied from code added in #3313. It seems like Windows also has _PATH_MAX, but the value might change depending on different versions of Windows, and it doesn't seem like the universal way of guaranteeing sufficient length for path names. The current codebase has two places where MultiByteToWideChar
is used:
monero/external/db_drivers/liblmdb/mdb.c
Lines 10942 to 10959 in ffab670
static int utf8_to_utf16(const char *src, int srcsize, wchar_t **dst, int *dstsize) | |
{ | |
int need; | |
wchar_t *result; | |
need = MultiByteToWideChar(CP_UTF8, 0, src, srcsize, NULL, 0); | |
if (need == 0xFFFD) | |
return EILSEQ; | |
if (need == 0) | |
return EINVAL; | |
result = malloc(sizeof(wchar_t) * need); | |
if (!result) | |
return ENOMEM; | |
MultiByteToWideChar(CP_UTF8, 0, src, srcsize, result, need); | |
if (dstsize) | |
*dstsize = need; | |
*dst = result; | |
return 0; | |
} |
monero/tests/gtest/src/gtest.cc
Lines 858 to 869 in ffab670
LPCWSTR String::AnsiToUtf16(const char* ansi) { | |
if (!ansi) return NULL; | |
const int length = strlen(ansi); | |
const int unicode_length = | |
MultiByteToWideChar(CP_ACP, 0, ansi, length, | |
NULL, 0); | |
WCHAR* unicode = new WCHAR[unicode_length + 1]; | |
MultiByteToWideChar(CP_ACP, 0, ansi, length, | |
unicode, unicode_length); | |
unicode[unicode_length] = 0; | |
return unicode; | |
} |
In both cases, the length of the resulting UTF-16 string is obtained by first calling the function with the output location set to NULL, which seems like the right way.
If this way is to be used, I think it makes sense to also replace the corresponding code in file_io_utils. What do you think? CC: @rbrunner7 @hyc
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.
Guilty ... I knew that, but when I wrote that code for #3313 I was on my last legs after working so long on that UTF-8 filename stuff that I simply hacked it in the simplest possible way.
I agree that it should be replaced sooner or later.
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.
Agreed, that's the safe way to do it.
src/common/util.cpp
Outdated
{ | ||
if (flock(m_fd, LOCK_EX | LOCK_NB) == -1) | ||
{ | ||
close(m_fd); |
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.
This could do with a MERROR/MWARNING so weird stuff afterwards can be known to be coming from that.
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.
ok
src/wallet/wallet2.cpp
Outdated
std::string buf; | ||
r = ::serialization::dump_binary(keys_file_data, buf); | ||
r = r && epee::file_io_utils::save_string_to_file(keys_file_name, buf); //and never touch wallet_keys_file again, only read | ||
CHECK_AND_ASSERT_MES(r, false, "failed to generate wallet keys file " << keys_file_name); | ||
m_keys_file_locker.reset(new tools::file_locker(m_keys_file.c_str())); |
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.
This uses c_str, but the ctor uses std::string, so this creates a new temporary string for no reason.
Having the ctor use const char * seems the way to support both without temp object creation.
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.
ok
src/wallet/wallet2.cpp
Outdated
|
||
m_keys_file_locker.reset(); |
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.
Maybe add a comment saying so ?
src/common/util.cpp
Outdated
{ | ||
if (flock(m_fd, LOCK_EX | LOCK_NB) == -1) | ||
{ | ||
MERROR("Failed to lock " << filename); |
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.
Could we get errno please ? :)
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.
ok
07f5b68
to
4686fc4
Compare
Code updated reflecting suggestions |
Maybe this way of trying to lock a file is stupid, but perhaps better than nothing...