Dlaczego mój program odnosi się do pamięci do której nie powinien?

1

Cześć!
Robię takie zadanko https://codeforces.com/contest/1572/problem/A
i taki kod do niego:

#include <bits/stdc++.h>
    
using namespace std;

int read = 0;
    
void dfs(int v, vector<vector<int>>& graph, vector<int>& need, vector<bool>& seen, set<int>& que_now){
    seen[v] = true;
    read++;
    for (auto& child : graph[v]){
        need[child]--;
        if (need[child] == 0 && child > v && seen[child] == false)
            dfs(child, graph, need, seen, que_now);
        else if (need[child] == 0 && seen[child] == false && child < v)
            que_now.insert(child);
    }
}
    
void solve(){
    int n;
    cin >> n;
    vector<vector<int>> graph(n+1);
    vector<int> need(n+1);
    vector<bool> seen(n+1);
    set<int> que, que_now;

    
    for (int i = 1;  i <= n; i++){
        int num;
        cin >> need[i];
        for (int j = 0; j < need[i]; j++){
            cin >> num;
            graph[num].push_back(i);
        }
    }
    
    for (int i = 1; i <= n; i++)
        if (need[i] == 0 && seen[i] == false)
            que.insert(i);
    
    read = 0;
    int times = 0;
    while (que.size()){
        for (auto& v : que){
            if (seen[v] == false)
                dfs(v, graph, need, seen, que_now);
        }
        que = que_now;
        que_now.clear();
        times++;
    }
    
    if (read != n){
        cout << -1 << '\n';
        return;
    }
    
    cout << times << '\n';
}
    
int main(){
    ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    int t;
    cin >> t;
    while (t){
        solve();
        t--;
    }
    return 0;
}

Gdy kompiluje go u siebie wszystko działa tak jak powinno, gdy wysyłam program do sprawdzenia dostaje Runtime error i Exit code is 2147483647. Odpaliłem address sanitizer

wojtek@Linux:~/project$ ./lol
ASAN:DEADLYSIGNAL
=================================================================
==5719==ERROR: AddressSanitizer: SEGV on unknown address 0x56241fca4380 (pc 0x56241fca4380 bp 0x000000001fff sp 0x7fffc1608948 T0)
==5719==The signal is caused by a READ memory access.
    #0 0x56241fca437f  (/home/wojtek/project/lol+0x20937f)

AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV (/home/wojtek/project/lol+0x20937f) 
==5719==ABORTING

po samej próbie odpalenia programu jest jakiś błąd. Dlaczego?

EDIT:
Nazwanie zmiennej globalnej "read" nie było dobrym pomysłem. Po zmienieiu nazwy, wszytsko działa.

1

@Suchy702: A próbowałeś użyć debuggera?

7

Jeszcze jeden przypadek potwierdzający tezę, że nie należy używać zmiennych globalnych.
https://codeforces.com/blog/entry/95574

1

ja to miałem w ogóle problemy to odpalić poprawnie na
https://www.onlinegdb.com/online_c++_compiler

musiałem po każdym std::cout dodać std::flush(oprócz twoich dodawałem swoje). A tak powinno być z std::cout;

3
Suchy702 napisał(a):

EDIT:
Nazwanie zmiennej globalnej "read" nie było dobrym pomysłem. Po zmienieniu nazwy, wszystko działa.

Dziwne, że linker nie zgłosił duplicated symbol, ale masz kolizję z tym symbolem:
https://man7.org/linux/man-pages/man2/read.2.html

Ogólnie używanie zmiennych globalnych to zły pomysł, szczególnie jeśli jest ryzyko konfliktu z innymi symbolami.

0

Jakbyś skompilował z flagą -g to address sanitizer by ładnie powiedział w jakim miejscu kodu masz ten błędny dostęp.

0

Heh, moja wersja asana wypisuje dodatkowo

==2810==The signal is caused by a READ memory access.
==2810==Hint: PC is at a non-executable region. Maybe a wild jump?

całkiem w sumie pomocna rada

0

@MarekR22: syscalle (np. ten read) ZTCW wywoływane są przez GLIBCowy wrapper. Jeżeli dostarczysz symbol o tej samej nazwie co jakiś z shared objectu zanim libka zostanie zalinkowana to ten symbol po prostu zostanie podmieniony na ten pierwszy znaleziony, a ten z so - zignorowany. Nie wiem jak jest u OP, ale stawiam, że przez taką a nie inną nazwę zmienna była traktowana jak funkcja co kończyło się crashem.

EDIT coby gołosłownym nie być:

nm a.out | grep read

0000000000410b40 B read
ASAN:
==10645==Hint: PC is at a non-executable region. Maybe a wild jump?
#0 0x410b40 in read (/home/alagner/odr_test/a.out+0x410b40)

I output z gdb (wcześniej read ustawiłem na niezerową wartość):

(gdb) catch signal SIGSEGV 
Catchpoint 1 (signal SIGSEGV)
(gdb) r
Starting program: /home/alagner/odr_test/a.out 
Missing separate debuginfos, use: zypper install glibc-debuginfo-2.33-9.1.x86_64
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".

Catchpoint 1 (signal SIGSEGV), 0x00000000004101a0 in read ()
Missing separate debuginfos, use: zypper install libasan6-debuginfo-11.2.1+git610-1.5.x86_64 libgcc_s1-debuginfo-11.2.1+git610-1.5.x86_64 libstdc++6-debuginfo-11.2.1+git610-1.5.x86_64
(gdb) bt
#0  0x00000000004101a0 in read ()
#1  0x00007ffff7492f5f in std::__basic_file<char>::xsgetn(char*, long) () from /lib64/libstdc++.so.6
#2  0x00007ffff74cfa90 in std::basic_filebuf<char, std::char_traits<char> >::underflow() () from /lib64/libstdc++.so.6
#3  0x00007ffff74dcacf in std::istream::sentry::sentry(std::istream&, bool) () from /lib64/libstdc++.so.6
#4  0x00007ffff74dcd23 in std::istream::operator>>(int&) () from /lib64/libstdc++.so.6
#5  0x0000000000403b79 in main () at test.cc:79
(gdb) p (int)read
$1 = 666

EDIT2: winna (tzn. ujawnia ona problem) jest ta linijka: ios_base::sync_with_stdio(0);

To jest do sprawdzenia potem, ale
jak jest sync z stdio czytanie leci przez API FILE*, czyli SO GLIBC, on tam ma swój read() zdefiniowany (w binarce).
Podejrzewam, że bez tego templatki rozwijają się do gołego read'a i kolidują z nazwą zmiennej.

EDIT3: swoją drogą ciekawe, czy linker by krzyknął przy statycznym stdlibie, obstawiam, że może już tak. IMHO tutaj nie miał jak zareagować, bo po prostu symbol się „rozwiązał”, wiec nawet nie szukał.

@Suchy702 generalnie jak musisz trzaskać te globale to rób je static albo zamykaj w anonimowym namespace’ie. Jak piszesz w jednym pliku te zadania to nic Ci to nie zmieni, a unikniesz takich kolizji jak tu.

1 użytkowników online, w tym zalogowanych: 0, gości: 1