I have singleton class, intended to for use in one thread (GUI thread), to protected from wrong usage I add assert
//header file
class ImageCache final {
public:
ImageCache(const ImageCache &) = delete;
ImageCache &operator=(const ImageCache &) = delete;
static ImageCache &instance()
{
static ImageCache cache;
return cache;
}
void f();
private:
QThread *create_context_ = nullptr;
ImageCache();
};
//cpp
ImageCache::ImageCache()
{
create_context_ = QThread::currentThread();
qInfo("begin, cur thread %p\n", create_context_);
}
void ImageCache::f()
{
assert(create_context_ == QThread::currentThread());
}
all works fine, but on one machine there is assertion failure in ImageCache::f
, I have no direct access to that machine (hence this question).
The interesting thing, that according to log ImageCache::ImageCache
was not called at all, and assert failed because of
assert(0 == QThread::currentThread());
I move implementation of ImageCache::instance
from header file to .cpp
file, send updated source code to user of these machine (on my all works fine), he rebuilds and all start works as expected.
I ask him for compiled binaries (with assert failure and without) the only difference between them is place of ImageCache::instance
implementation,
and compare assembler.
there is no difference between calls of ImageInstance::instance().f()
at all, and there is one difference in disassembler of ImageInstance::instance
,
the failure one looks like this:
static ImageCache &instance()
4938f: 55 push %rbp
49390: 48 89 e5 mov %rsp,%rbp
49393: 41 54 push %r12
49395: 53 push %rbx
{
static ImageCache cache;
49396: 48 8b 05 bb db 23 00 mov 0x23dbbb(%rip),%rax # 286f58 <_ZGVZN10ImageCache8instanceEvE5cache@@Base-0x2150>
4939d: 0f b6 00 movzbl (%rax),%eax
493a0: 84 c0 test %al,%al
493a2: 0f 94 c0 sete %al
493a5: 84 c0 test %al,%al
493a7: 74 5c je 49405 <_ZN10ImageCache8instanceEv+0x76>
493a9: 48 8b 05 a8 db 23 00 mov 0x23dba8(%rip),%rax # 286f58 <_ZGVZN10ImageCache8instanceEvE5cache@@Base-0x2150>
493b0: 48 89 c7 mov %rax,%rdi
493b3: e8 08 b7 fe ff callq 34ac0 <__cxa_guard_acquire@plt>
the good one is looks like this:
ImageCache &ImageCache::instance()
{
50c12: 55 push %rbp
50c13: 48 89 e5 mov %rsp,%rbp
50c16: 41 54 push %r12
50c18: 53 push %rbx
static ImageCache cache;
50c19: 0f b6 05 98 94 23 00 movzbl 0x239498(%rip),%eax # 28a0b8 <_ZGVZN10ImageCache8instanceEvE5cache>
50c20: 84 c0 test %al,%al
50c22: 0f 94 c0 sete %al
50c25: 84 c0 test %al,%al
50c27: 74 50 je 50c79 <_ZN10ImageCache8instanceEv+0x67>
50c29: 48 8d 3d 88 94 23 00 lea 0x239488(%rip),%rdi # 28a0b8 <_ZGVZN10ImageCache8instanceEvE5cache>
50c30: e8 cb 3d fe ff callq 34a00 <__cxa_guard_acquire@plt>
The difference is
//bad
mov 0x23dbbb(%rip),%rax
movzbl (%rax),%eax
//good
movzbl 0x239498(%rip),%eax
I interpret this, that for some reason %eax
register from the first one variant got wrong value, and because of this got decision that global object was initialized while it is not initialized. In the second case all works as expected.
So is it compiler failure (gcc (Ubuntu 7.3.0-27ubuntu1~18.04) 7.3.0 / amd64 / linux
) or I should use ImageCache::instance inside .cpp
for some reason, or some other reason that cause difference code generation, like some compiler falgs may cause this failure? Code was compiled with -O0 -std=c++11
Aucun commentaire:
Enregistrer un commentaire