Niezrozumiały SIGSEGV przy zbyt prostym programie

0
using namespace std;

int main()
{
  int nmax = 1000000;
  int costs[nmax];
  
  int n; n=4;
  for(int i = 0; i < n; i++)
    costs[i]=i+1;
  
  int Nmax = nmax+1;
  long long int costsums[Nmax];
  costsums[0]=0;
}

SIGSEGV leci przy costsums[0]=0.
Program jest tak prosty, że naprawdę nie wiem, gdzie mogłem zrobić błąd.

Valgrind wypisuje jakieś niezrozumiałe teorie na temat rzekomych zamian stosu:

==25909== Memcheck, a memory error detector
==25909== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==25909== Using Valgrind-3.10.0.SVN and LibVEX; rerun with -h for copyright info
==25909== Command: ./bazzad
==25909== 
==25909== Warning: client switching stacks?  SP change: 0xffeffff20 --> 0xffec2f610
==25909==          to suppress, use: --max-stackframe=4000016 or greater
==25909== Invalid write of size 4
==25909==    at 0x400593: main (bazzadwtf.cpp:10)
==25909==  Address 0xffec2f610 is on thread 1's stack
==25909== 
==25909== Warning: client switching stacks?  SP change: 0xffec2f610 --> 0xffe48e400
==25909==          to suppress, use: --max-stackframe=8000016 or greater
==25909== Invalid write of size 8
==25909==    at 0x40061A: main (bazzadwtf.cpp:14)
==25909==  Address 0xffe48e400 is on thread 1's stack
==25909== 
==25909== 
==25909== Process terminating with default action of signal 11 (SIGSEGV)
==25909==  Access not within mapped region at address 0xFFE48E400
==25909==    at 0x40061A: main (bazzadwtf.cpp:14)
==25909==  If you believe this happened as a result of a stack
==25909==  overflow in your program's main thread (unlikely but
==25909==  possible), you can try to increase the size of the
==25909==  main thread stack using the --main-stacksize= flag.
==25909==  The main thread stack size used in this run was 8388608.
==25909== 
==25909== Process terminating with default action of signal 11 (SIGSEGV)
==25909==  Access not within mapped region at address 0xFFE48E3F9
==25909==    at 0x4A256B0: _vgnU_freeres (in /usr/lib/valgrind/vgpreload_core-amd64-linux.so)
==25909==  If you believe this happened as a result of a stack
==25909==  overflow in your program's main thread (unlikely but
==25909==  possible), you can try to increase the size of the
==25909==  main thread stack using the --main-stacksize= flag.
==25909==  The main thread stack size used in this run was 8388608.
==25909== 
==25909== HEAP SUMMARY:
==25909==     in use at exit: 0 bytes in 0 blocks
==25909==   total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==25909== 
==25909== All heap blocks were freed -- no leaks are possible
==25909== 
==25909== For counts of detected and suppressed errors, rerun with: -v
==25909== ERROR SUMMARY: 5 errors from 2 contexts (suppressed: 0 from 0)
Segmentation fault

Czy ja jestem już na tyle niewyspany, że nie widzę jakiejś oczywistości?

7

Moge się mylić, ale myśle że za dużo elementów deklarujesz na stosie. Spróbuj alokować pamięć dynamicznie.

0

Na code blocks pod 64 bitowym Linuksem wykonuje się bez problemu, jaki ty masz system?

3

Ten kod jest całkowicie niepoprawny.

Po pierwsze nie można alokować w C++ tablic, które mają automatic storage duration, jeżeli ich rozmiar nie jest stały i znany podczas kompilacji. To można w >=C99. Niektóre kompilatory C++ to dopuszczają (np. w GCC jest to rozszerzenie), ale używanie tego to zły pomysł.

Po drugie, nawet jeżeli kod się skompiluje, alokujesz stanowczo zbyt dużo dla takiej tablicy. Już na start chcesz prawie 4 MiB. A potem jest kolejna tablica. W zależności od systemu operacyjnego to może działać, lub może się wysypać. Jak widać u Ciebie nie działa.

0
Endrju napisał(a):

Po pierwsze nie można alokować w C++ tablic, które mają automatic storage duration, jeżeli ich rozmiar nie jest stały i znany podczas kompilacji. To można w >=C99. Niektóre kompilatory C++ to dopuszczają (np. w GCC jest to rozszerzenie), ale używanie tego to zły pomysł.

int nmax = 1000000; - to chyba jest znane i stałe w czasie kompilacji?
...
Dobra, zamieniłem int nmax na const int nmax. To samo z Nmax. Nadal SIGSEGV.

Endrju napisał(a):

Po drugie, nawet jeżeli kod się skompiluje, alokujesz stanowczo zbyt dużo dla takiej tablicy. Już na start chcesz prawie 4 MiB. A potem jest kolejna tablica. W zależności od systemu operacyjnego to może działać, lub może się wysypać. Jak widać u Ciebie nie działa.

Cały problem w tym, że o ile pamiętam jak robiłem zadania na uva.onlinejudge.org, to deklaracje typu int tab[1000000] przechodziły bez problemu. Miliard intów już nie przechodził, ale milion - o ile pamiętam, tak. I ja swoje rozwiązania zawsze byłem w stanie bez problemu uruchomić na swoim komputerze, nie tylko na uva.onlinejudge.org. Czyli, teraz nie działa coś, co pamiętam, że kiedyś działało - i to mnie denerwuje.

Ale możliwe, że źle pamiętam, ja te zadania na uva.onlinejudge.org robiłem w gimnazjum (solidnych kilka lat temu), więc mogło mi się już zamazać w pamięci. Kurczę za młody jestem na sklerozę ;P

1

A może robiłeś statyczne tablice na przykład? ;]

0
kmph napisał(a):

int nmax = 1000000; - to chyba jest znane i stałe w czasie kompilacji?

Nie jest. To nie jest constant expression.

kmph napisał(a):

Dobra, zamieniłem int nmax na const int nmax. To samo z Nmax. Nadal SIGSEGV.

Segmentation fault nie ma niczego z tym wspólnego, przekraczasz rozmiar stosu. Dodanie const do Nmax dalej nie robi z tego constant expression.

kmph napisał(a):

Cały problem w tym, że o ile pamiętam jak robiłem zadania na uva.onlinejudge.org, to deklaracje typu int tab[1000000] przechodziły bez problemu.

Każda implementacja może określać sobie rozmiar stosu inaczej.

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