Hugozys / life

classic game of life simulator
0 stars 0 forks source link

Program segfaults at start #1

Closed z-rui closed 5 years ago

z-rui commented 5 years ago

Compiled with ncurses-6.1 and glog-0.3.4, the program segfaults at program start.

Stack traceback provided by Valgrind is pasted below.

Invalid read of size 8
   at 0x509B658: new_menu_sp (in /usr/lib64/libmenu.so.6.1)
   by 0x10F87E: Menu::Menu() (menu.hpp:27)
   by 0x10FA59: Board::Board() (board.hpp:34)
   by 0x10F3D4: main (life.cc:23)
 Address 0x90 is not stack'd, malloc'd or (recently) free'd

Seems like a problem with the menu library, any idea?

Hugozys commented 5 years ago

I tried to reproduce the SegFaults error but failed to do so.

Here is the ncurses version information I found on Linux system on which it was developed:

ii  libncurses5:amd64      6.1-1ubuntu1.18.04 amd64        shared libraries for terminal handling
ii  libncurses5-dev:amd64  6.1-1ubuntu1.18.04 amd64        developer's libraries for ncurses
ii  libncursesw5:amd64     6.1-1ubuntu1.18.04 amd64        shared libraries for terminal handling (wide character support)
ii  libncursesw5-dev:amd64 6.1-1ubuntu1.18.04 amd64        developer's libraries for ncursesw
ii  ncurses-base           6.1-1ubuntu1.18.04 all          basic terminal type definitions
ii  ncurses-bin            6.1-1ubuntu1.18.04 amd64        terminal-related programs and man pages
ii  ncurses-doc            6.1-1ubuntu1.18.04 all          developer's guide and documentation for ncurses

I compiled the program under this Linux environment and run it with Valgrind. The program run normally and here is the information emitted by Valgrind after simulation finished:

==28577== Memcheck, a memory error detector
==28577== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==28577== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==28577== Command: ./life
==28577== 
==28577== 
==28577== HEAP SUMMARY:
==28577==     in use at exit: 145,558 bytes in 565 blocks
==28577==   total heap usage: 900 allocs, 335 frees, 407,170 bytes allocated
==28577== 
==28577== LEAK SUMMARY:
==28577==    definitely lost: 96 bytes in 1 blocks
==28577==    indirectly lost: 495 bytes in 6 blocks
==28577==      possibly lost: 0 bytes in 0 blocks
==28577==    still reachable: 144,967 bytes in 558 blocks
==28577==         suppressed: 0 bytes in 0 blocks
==28577== Rerun with --leak-check=full to see details of leaked memory
==28577== 
==28577== For counts of detected and suppressed errors, rerun with: -v
==28577== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

I cloned the repo. onto another virtual machine which has Ubuntu 16.04 installed. I installed ncurses and glog library by typing:

sudo apt install libncurses5-dev
sudo apt install google-glog-dev

The version information is:

ubuntu 16.04
libgoogle-glog-dev  0.3.4-0.1
libncurses5 6.0+20160213

The program run successfully and the valgrind gave same information.

==14040== Memcheck, a memory error detector
==14040== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==14040== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==14040== Command: ./life
==14040== 
==14040== 
==14040== HEAP SUMMARY:
==14040==     in use at exit: 209,765 bytes in 375 blocks
==14040==   total heap usage: 529 allocs, 154 frees, 261,118 bytes allocated
==14040== 
==14040== LEAK SUMMARY:
==14040==    definitely lost: 0 bytes in 0 blocks
==14040==    indirectly lost: 0 bytes in 0 blocks
==14040==      possibly lost: 0 bytes in 0 blocks
==14040==    still reachable: 209,765 bytes in 375 blocks
==14040==         suppressed: 0 bytes in 0 blocks
==14040== Rerun with --leak-check=full to see details of leaked memory
==14040== 
==14040== For counts of detected and suppressed errors, rerun with: -v
==14040== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

So far I don't have idea what the problem might be.

Hugozys commented 5 years ago

Also the definitely lost and indefinitely lost happened when invoking new_item function. It seems that the ITEMobject didn't get freed correctly, even if I wrapped it inside unique_ptr. Attempting to debug this, I explicitly invoked free_item on every ITEM * in Menu destructor and the return value of free_item function is either -2 or -4. If I used perror after I invoked free_item, it prints "Unknown Error".

z-rui commented 5 years ago

After some debugging, the problem seems to be that your call to new_menu (called by Menu::Menu by Board::Board) happened before the call to initscr (called by Board::SetEnv).

Before initscr is called, the global CURRENT_SCREEN variable in ncurses is NULL, which is in turn used by new_menu and then caused the segfault.

The problem can be solved by calling initscr before new_menu. The following patch works for me:

diff --git a/board.cc b/board.cc
index e53461d..a62c73e 100644
--- a/board.cc
+++ b/board.cc
@@ -99,7 +99,6 @@ void Board::Update(){
 }

 void Board::SetEnv(){
-  initscr();
   curs_set(0);
   window_ = std::unique_ptr<WINDOW, decltype(&delwin)>(newwin(LINES - 2, COLS - 4, 1,2),&delwin);
   getbegyx(window_.get(),min_y_,min_x_);
diff --git a/life.cc b/life.cc
index 23e0d39..ea561aa 100644
--- a/life.cc
+++ b/life.cc
@@ -20,6 +20,7 @@ int main(int argc, char ** argv){
     return (EXIT_SUCCESS);
   }
   try{
+    initscr();
     Board bd;
     bd.SetEnv();
     bd.Run();

though you might want to figure out a more elegant solution.

Hugozys commented 5 years ago

Just curious about why the SegFault disappears on both of the two machines I experimented on. Does this indicate the behaviour of doing new_menu() before initscr() is nondeterministic?

I appreciate the patch and correction anyway. I will try to come with a more elegant solution.

z-rui commented 5 years ago

According to Menus Library documentation, you should initialize ncurses before creating any menus/items. The behavior is quite deterministic, as it always segfaults on my machine.

z-rui commented 5 years ago

I suggest that you fix the same problem in the other game your wrote. :)