Блог пользователя oversolver

Автор oversolver, 3 месяца назад, По-английски

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...

  • Проголосовать: нравится
  • +30
  • Проголосовать: не нравится

»
3 месяца назад, # |
Rev. 3   Проголосовать: нравится +17 Проголосовать: не нравится

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 месяца назад, # |
  Проголосовать: нравится +8 Проголосовать: не нравится

Thanks!

»
3 месяца назад, # |
Rev. 2   Проголосовать: нравится +18 Проголосовать: не нравится

I recommend -fsanitize=undefined.

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

  • »
    »
    3 месяца назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится

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

    • »
      »
      »
      3 месяца назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится

      What happened when it ran? Sanitizers work at runtime.

      • »
        »
        »
        »
        3 месяца назад, # ^ |
        Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится

        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;
        }
        
    • »
      »
      »
      2 месяца назад, # ^ |
        Проголосовать: нравится -8 Проголосовать: не нравится

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