oversolver's blog

By oversolver, 3 months ago, In English

I am using -Werror=uninitialized locally in g++ args. It prevents me from bugs like this

int x;
++x;

But today I realized that my typical code of dfs on tree passes this check

vector<int> tin(n);
int tn;
function<void(int, int)> go = [&](int v, int p) {
    tin[v] = tn++;
    ...
};

So after playing with lines of code I came to this successfully compiled code

int n = 100;
vector<vector<int>> g(n);
int tn;
++tn; //HELLO WHERE IS MY CE???
function<void()> f = [&] {
    cout << tn << endl;
};
f();

What interesting is that commenting vector g will result a compilation error. Replacing std::function to lambda will result a compilation error. Moving g under ++tn will result a compilation error...

I am very tilted now. Mike please add g++14 with "deducing this" support...

  • Vote: I like it
  • +30
  • Vote: I do not like it

»
3 months ago, # |
Rev. 3   Vote: I like it +17 Vote: I do not like it

Another reason why opaque abstractions like std::function are bad if used without a reason. However I don't think C++23 will be added any time soon (I've been petitioning for deducing this for quite long).

By the way, to avoid these bugs I never declare variables without initializing them. If you still want to do this, -ftrivial-auto-var-init=pattern makes them more visible (via a WA instead of uninitialized variables). Relevant documentation: https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html#index-ftrivial-auto-var-init

As far as the original issue goes, I think it's because of GCC not reasoning correctly about proper initialization (or some weird memory clobbering/laundering happening under the hood with std::function).

»
3 months ago, # |
  Vote: I like it +8 Vote: I do not like it

Thanks!

»
3 months ago, # |
Rev. 2   Vote: I like it +18 Vote: I do not like it

I recommend -fsanitize=undefined.

Also you can report this as a bug, if it or something similar hasn't been reported yet.

  • »
    »
    3 months ago, # ^ |
      Vote: I like it 0 Vote: I do not like it

    in my example it does nothing: no warnings, compiled successful (arch, g++14.2.1)

    • »
      »
      »
      3 months ago, # ^ |
        Vote: I like it 0 Vote: I do not like it

      What happened when it ran? Sanitizers work at runtime.

      • »
        »
        »
        »
        3 months ago, # ^ |
        Rev. 2   Vote: I like it 0 Vote: I do not like it

        it just print garbage from tn, but not random. without fsanitize value is random each run.

        #include<bits/stdc++.h>
        using namespace std;
        
        int main() {
        	int n, tn;
        	cin >> n;
        	++tn;
        	function<void()> f = [&] {
        		cout << tn << endl;
        	};
        	f();
        	return 0;
        }
        

        UPD. following code compiles with fsanitize and fails without.

        #include<bits/stdc++.h>
        using namespace std;
        
        int main() {
        	int tn;
        	function<void()> f = [&] {
        		cout << tn << endl;
        	};
        	f();
        	return 0;
        }
        
    • »
      »
      »
      3 months ago, # ^ |
        Vote: I like it -8 Vote: I do not like it

      If something shouldn't succeed and it succeeds, that's still a bug.