29 Aug, 2009, Kline wrote in the 1st comment:
Votes: 0
So I'm writing a program to convert areas (yay, another one!) and using it as a chance to teach myself some of the C++ routines to read from files. I've tried to model it around the original routine I'm trying to convert areas from, making small improvements where I can without breaking compatibility with the horrible file format.

Anyhow, I can read the header of an area fine, but once I start to iterate through rooms and doors/extra descrs within them, I keep hitting an infinite loop and I'm not sure why. I'm guessing that my file pointer isn't where I seem to think it is, so I'm probably accessing something wrong, but I'm pretty stumped on it right now.

Here's the offending function, and below it is a sample of the data I'm trying to read. Some rooms seem to work fine, as I can watch my log output truck along through a few of them, but then it just chokes.

void read_ack431_room( ifstream &file )
{
string tmp;
room_data *room;
int vnum = 0;
char delim = '~';
char c;

for( ;; )
{
c = file.get();
cout << " c = " << c;
if( c == '#' )
getline(file,tmp); vnum = str2int(tmp);

if( vnum == 0 ) /* reached the end */
break;
cout << " tmp = " << tmp << endl;
room = new room_data;
room->vnum = vnum;
getline(file,room->name,delim);
getline(file,room->description,delim);
getline(file,tmp,' '); room->int_flags_in = str2int(tmp);
getline(file,tmp); room->sector = str2int(tmp);

for( ;; )
{
c = file.get();

if( c == 'S' ) /* stop */
{
cout << "got S" << endl;
break;
}
if( c == 'D' ) /* door */
{
cout << "got D" << endl;
exit_data *exit = new exit_data;
getline(file,tmp);
room->exit[str2int(tmp)] = exit;
getline(file,exit->description,delim);
getline(file,exit->keyword,delim);
getline(file,tmp,' '); /* locks */
getline(file,tmp,' '); exit->key = str2int(tmp);
getline(file,tmp); exit->vnum = str2int(tmp);
}
if( c == 'E' ) /* extra descrip */
{
extra_data *extra = new extra_data;
getline(file,extra->keyword,delim);
getline(file,extra->description,delim);
}
}
cout << "ended loop" << endl;
room_list.push_back(room);
}

return;
}


#3305
Moribund~
You are in a clearing within the whispy smoke of Maribund.
^M~
9228 11
D0
Moribund.
^M~
~
0 -1 3303
D1
Moribund.
^M~
~
0 -1 3303
D2
Moribund.
^M~
~
0 -1 3306
D3
Moribund.
^M~
~
0 -1 3303
D4
Moribund.
^M~
~
0 -1 3302
D5
Moribund.
^M~
~
0 -1 3303
S
29 Aug, 2009, Barm wrote in the 2nd comment:
Votes: 0
Shouldn't it be:
file.get©;


not
c = file.get();


Although it's been a LONG time since I worked with C++.
29 Aug, 2009, Kline wrote in the 3rd comment:
Votes: 0
I pulled that usage from the example provided here: http://www.cplusplus.com/reference/iostr...
31 Aug, 2009, David Haley wrote in the 4th comment:
Votes: 0
Where does it start looping?

You can also check the various failure bits set on the stream at each point to make sure that the stream is in a valid state. The documentation does not make clear what is returned when the stream is invalid. You could also look at the value of 'c' when the routine starts looping.
31 Aug, 2009, elanthis wrote in the 5th comment:
Votes: 0
You have at least one loop in your code that never terminates unless a particular character is read… so if your file is malformed (or you aren't parsing it right) and the loop hits the end of the file without seeing that character, it's going to loop forever waiting for something that will never happen.

Get rid of those for (;;) loops and replace them with while (!file.eof()) and you will at least be protected against infinite loops. In general, you should never, ever use for (;;) loops or while (true) loops without VERY good cause (which does happen, but it's rare). Your loops should always have termination conditions that protect against infinite looping.
31 Aug, 2009, Kline wrote in the 6th comment:
Votes: 0
elanthis: Thanks, didn't even think to use a while( !eof ), that's done now and I get a segfault instead. Too bad the segfault is someplace within a STL element and gives zero useful info.

DH: I'll go read about streams more, I don't think I realized I could check for values so I'll try to figure some of that out tonight after dinner. In the meantime, here's the log output generated by the code I pasted above, when run on my test file I'm trying to parse.

c = # tmp = 3308
got S
ended loop
c =
tmp = 11
got D
got S
ended loop
c =
tmp = 3306
got D
got D
got D
got D
got D
got D
got S
ended loop
c =
tmp = 3307
got D
got D
got D
got D
got D
got D
got S
ended loop
c =
tmp = 3303
got D
got D
got D
got D
got D
got D
got S
ended loop
c =
tmp = 3304
got D
got D
got D
got D
got D
got D
got S
ended loop
c =
tmp = 3304
got D
got D
got D
got D
got D
got D
got S
ended loop
c =
tmp = 3302
got D
got D
got D
got D
got D
got D
got S
ended loop
c =
tmp = 3301
got S
ended loop
c =
tmp = 11
got S
ended loop
c =
tmp = Pesky Gremlin stands here, looking for someone to hurt.~
got S
ended loop
c =
tmp = strange, flickering light whirls around you.
got S
ended loop
c =
tmp = stands before you, looking downright evil.
ended loop
Segmentation fault
31 Aug, 2009, elanthis wrote in the 7th comment:
Votes: 0
It's not useless at all. Look at the backtrace and see what called into that STL method. If that is indeed not helping, run under Valgrind.
01 Sep, 2009, Kline wrote in the 8th comment:
Votes: 0
GDB said:
Program received signal SIGSEGV, Segmentation fault.
~list (this=0x8051464) at /usr/include/c++/4.3/ext/atomicity.h:69
69 _Atomic_word __result = *__mem;
Current language: auto; currently c++
(gdb) bt
#0 ~list (this=0x8051464) at /usr/include/c++/4.3/ext/atomicity.h:69
#1 0xb7c8abb9 in exit () from /lib/tls/i686/cmov/libc.so.6
#2 0xb7c7277d in __libc_start_main () from /lib/tls/i686/cmov/libc.so.6
#3 0x08049ca1 in _start () at ../sysdeps/i386/elf/start.S:119
(gdb) print *this
$1 = {<std::_List_base<room_data, std::allocator<room_data> >> = {
_M_impl = {<std::allocator<std::_List_node<room_data> >> = {<__gnu_cxx::new_allocator<std::_List_node<room_data> >> = {<No data fields>}, <No data fields>}, _M_node = {_M_next = 0x82df700, _M_prev = 0x82e1f40}}}, <No data fields>}


Ok, so it's a problem in my room_list. Valgrind gave me a few uninitialized things to look into so I'll poke there and come back :).
01 Sep, 2009, Kline wrote in the 9th comment:
Votes: 0
Ok, after fixing the few obvious things, any help to why I would be getting these invalid reads, given the code above (modified simply with elanthis' suggestion for the while loop)? To me it looks like it's trying to delete a *room that hasn't been allocated within the list, but I don't understand why, as I allocate a new room every iteration of the loop and nowhere do I delete them.

Valgrind said:
==16606== Invalid read of size 4
==16606== at 0x40D5375: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string() (in /usr/lib/libstdc++.so.6.0.10)
==16606== by 0x804C40D: room_data::~room_data() (areaconvert.h:88)
==16606== by 0x804C460: __gnu_cxx::new_allocator<room_data>::destroy(room_data*) (new_allocator.h:118)
==16606== by 0x804CB4F: std::_List_base<room_data, std::allocator<room_data> >::_M_clear() (list.tcc:78)
==16606== by 0x804CBBA: std::_List_base<room_data, std::allocator<room_data> >::~_List_base() (stl_list.h:358)
==16606== by 0x804CC0C: std::list<room_data, std::allocator<room_data> >::~list() (stl_list.h:417)
==16606== by 0x4191BB8: exit (in /lib/tls/i686/cmov/libc-2.9.so)
==16606== by 0x417977C: (below main) (in /lib/tls/i686/cmov/libc-2.9.so)
==16606== Address 0x42cbdc4 is 0 bytes after a block of size 12 alloc'd
==16606== at 0x40269EE: operator new(unsigned int) (vg_replace_malloc.c:224)
==16606== by 0x804A2F7: __gnu_cxx::new_allocator<std::_List_node<room_data*> >::allocate(unsigned int, void const*) (new_allocator.h:92)
==16606== by 0x804A31A: std::_List_base<room_data*, std::allocator<room_data*> >::_M_get_node() (stl_list.h:314)
==16606== by 0x804A32F: std::list<room_data*, std::allocator<room_data*> >::_M_create_node(room_data* const&) (stl_list.h:460)
==16606== by 0x804A38F: std::list<room_data*, std::allocator<room_data*> >::_M_insert(std::_List_iterator<room_data*>, room_data* const&) (stl_list.h:1341)
==16606== by 0x804A3DB: std::list<room_data*, std::allocator<room_data*> >::push_back(room_data* const&) (stl_list.h:876)
==16606== by 0x8049ADF: read_ack431_room(std::basic_ifstream<char, std::char_traits<char> >&) (ack431.c:129)
==16606== by 0x8049FE1: read_ack431(std::basic_ifstream<char, std::char_traits<char> >&) (ack431.c:26)
==16606== by 0x804B178: process_infile(std::basic_ifstream<char, std::char_traits<char> >&, int) (areaconvert.c:211)
==16606== by 0x804BC8D: main (areaconvert.c:73)
==16606==
==16606== Invalid read of size 4
==16606== at 0x40D53B3: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string() (in /usr/lib/libstdc++.so.6.0.10)
==16606== by 0x804C40D: room_data::~room_data() (areaconvert.h:88)
==16606== by 0x804C460: __gnu_cxx::new_allocator<room_data>::destroy(room_data*) (new_allocator.h:118)
==16606== by 0x804CB4F: std::_List_base<room_data, std::allocator<room_data> >::_M_clear() (list.tcc:78)
==16606== by 0x804CBBA: std::_List_base<room_data, std::allocator<room_data> >::~_List_base() (stl_list.h:358)
==16606== by 0x804CC0C: std::list<room_data, std::allocator<room_data> >::~list() (stl_list.h:417)
==16606== by 0x4191BB8: exit (in /lib/tls/i686/cmov/libc-2.9.so)
==16606== by 0x417977C: (below main) (in /lib/tls/i686/cmov/libc-2.9.so)
==16606== Address 0xfffffffc is not stack'd, malloc'd or (recently) free'd
01 Sep, 2009, David Haley wrote in the 10th comment:
Votes: 0
It looks like it's getting the invalid read while trying to call 'exit' – it's possible that the bad thing has already happened, and it's in the process of catching an exception or something like that.

Why does your list contain room_data and not room_data*? Since it contains room_data, it will try to destruct each of the entries when the list goes out of scope. I'm guessing that your room structure has some kind of constructor from room_data*, which is why you're able to push room_data pointers onto a list of room_data.
01 Sep, 2009, Kline wrote in the 11th comment:
Votes: 0
My list actually is <room_data *>, and I just checked now and I'm actually receiving a (somewhat mangled) output file at this point, since I've bypassed whatever was holding me to my infinite for( ;; ) loop, and still managing to segfault. Here's what I mean by mangled – the first room written out came out properly, the second, well, you'll see. It only gets progressively worse from there, with data shifting ahead or behind a field or two the further through the file it read/printed.

testfile said:
#ROOM
Vnum 3308
Desc
This feels like an enchanted room. Feelings of peace and happiness
wash over you like waves lapping across a beach. Although you are
unable to see any walls, floor or ceiling to this room, you are
perfectly content to just float here, lost in the amazing feelings
you are currently entertaining. It seems like whoever had enough
~
Flags EOL
Name The Room Of Private Contemplation~
Sect 11
End
#ROOM
Vnum 11
Desc
You are in a small, warm room. Lit by gentle blue light, this room appears
to be welcoming, rather than cold. There are two windows set into the
North wall, looking out over the dark countryside outside, and the stars
above, glittering like a string of diamonds. Inside the room, the floor
seems to consist of a soft, cushioned floor, which is covered in various
pillows and covers. Looks like an interesting place to stay for a while!
To complete the room's gentle mood, soft, ambient music flows through the
room, filling you with an immense inner peace.
~
Flags EOL
Name #3307
The Pleasure Palace~
Sect 11
End
01 Sep, 2009, elanthis wrote in the 12th comment:
Votes: 0
You may have deleted/freed your room info elsewhere before trying to use it. Hard to say without being able to poke at the code.
01 Sep, 2009, Kline wrote in the 13th comment:
Votes: 0
Well there are no deletes anyplace in the program – no need (unless I write a cleanup routine on shutdown), it's supposed to run, process, exit. The full program is available on public SVN here if you'd like to truly poke and laugh :).

edit: Oh, and the file I've been trying to un-successfully parse can be snagged from here. Program is invoked as ./areaconvert moribund.are.
01 Sep, 2009, David Haley wrote in the 14th comment:
Votes: 0
You have deletion because you have a list of objects instead of a list of object pointers.
01 Sep, 2009, Kline wrote in the 15th comment:
Votes: 0
Kline said:
My list actually is <room_data *> …

h/extern.h said:
extern list<room_data *> room_list;


Am I mistaken in my use of my list? I mean I'm writing this whole thing just based on what I know from tinkering with my MUDs, but it's my first program I've done 100% from scratch on my own.

edit: Well indeed I did have a floating non-pointer list at the top of my primary .c file, my mistake good sir :) Must have missed it when I was re-shuffling stuff when I first started writing it. This has solved my segfault, but my shuffling of data incorrectly still remains :(
01 Sep, 2009, Davion wrote in the 16th comment:
Votes: 0
Care to post the updated code?
01 Sep, 2009, Kline wrote in the 17th comment:
Votes: 0
The problem func is the same as in my original post, with the exception of for( ;; ) being replaced with while( !file.eof() ). The list issue was just that I had indeed defined a <room_data> list at the top of my .c file, yet properly had a <room_data *> in my header.
01 Sep, 2009, Davion wrote in the 18th comment:
Votes: 0
Yes, but it's still shuffling stuff, right?
01 Sep, 2009, David Haley wrote in the 19th comment:
Votes: 0
What exactly does "shuffling stuff" mean in this context?

EDIT:
To be clear, I'm asking because a few things seem to have changed, and I'm not sure where we are or what is still happening.
01 Sep, 2009, Davion wrote in the 20th comment:
Votes: 0
I fixed it on icode :P
0.0/22