0

There is this simple Singleton function:

const AppConfig& AppConfig::Singleton()
{
    static AppConfig appConfig{ configPath_ };

    return appConfig;
}

first, it's initialized correctly every time (I have breakpoints for checking it) and it is called multiple times from multiple threads with following ways:

auto& a = utils::AppConfig::Singleton();

or

utils::AppConfig::Singleton().member

Basically, it uses the implementation from this answer: https://stackoverflow.com/a/1008289/1423254, which I personally used many times as well thinking that it is thread-safe and it should be according to :https://stackoverflow.com/a/1661564/1423254.

The code works on production, but not locally on my laptop, quite often with some garbage in the returned config:

incorrect data

What is happening there and how to fix it so I don't get that garbage data?

I even tried putting a lock inside the whole Singleton function body and it didn't help.

We use 64bit GCC 7.5.0 for compilation.

EDIT: I should add that multiple threads call the Singleton function correctly, there is a problem just with 1 individual thread, sometimes returning garbage.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
Lukas Salich
  • 959
  • 2
  • 12
  • 30
  • 1
    You post a bit of code which looks totally safe. Why do you claim that's responsible for the problem? AFAICT, any faulty code could overwrite `appConfig`. You may need a debugger. – MSalters Oct 26 '20 at 12:09
  • Yes, thank you for your clarification that it is safe, I am actually checking what can overwrite the `appConfig`. – Lukas Salich Oct 26 '20 at 12:16
  • 1
    Have you tried putting a memory breakpoint on `&appConfig`, using GDB? – MSalters Oct 26 '20 at 12:25
  • @MSalters I can't find, how to add those so called `data brekpoint`s that only stop when the value is changed. – Lukas Salich Oct 26 '20 at 14:20
  • I think it's just `watch appConfig`. You'll need a regular breakpoint in `Singleton()` to stop at a point where `appConfig` is in scope, though. – MSalters Oct 26 '20 at 14:49
  • @MSalters It fails with `-var-create: unable to create variable object`, I tried to follow https://lldb.llvm.org/use/map.html#watchpoint-commands as well, but it fails with the same message. – Lukas Salich Oct 26 '20 at 14:58
  • GDB as a debugger is indeed frustrating at times, and it's really a shame that in 2020 it's still not as good as Visual Studio 6 was in 1998. These basic things should just work. You'll need to print `&appConfig` and put a breakpoint on that location instead. – MSalters Oct 26 '20 at 15:11
  • @MSalters Sorry, it worked, but I needed to call `-exec watch appConfig`, but then it gives me kind of false positives, because it breaks all the time on some seemingly unrelated code, when I add `-exec watch appConfig.member` then the code doesn't continue and kind of hangs and when I want to be even more specific and use `-exec watch appConfig.member.member`, then it's not hit at all and continues as if the object did not change :( – Lukas Salich Oct 26 '20 at 16:01
  • Why do you think it's "unrelated code"? An out-of-bounds array write would appear unrelated, but could definitely overwrite `appConfig` with the sort of garbage you see. – MSalters Oct 26 '20 at 16:09
  • @MSalters Ok, it can be related, but the call-stack does not help me in any way. I guess I can only find the problem by going back in the commits and finding the 1 that broke it and investigate it. – Lukas Salich Oct 27 '20 at 09:26

0 Answers0