Angband.oook.cz
Angband.oook.cz
AboutVariantsLadderForumCompetitionComicScreenshotsFunniesLinks

Go Back   Angband Forums > Angband > Variants

Reply
 
Thread Tools Display Modes
Old March 4, 2010, 15:02   #11
konijn_
Hellband maintainer
 
konijn_'s Avatar
 
Join Date: Jul 2007
Location: New York, the Big Apple
Age: 42
Posts: 367
Donated: $120
konijn_ is on a distinguished road
Quote:
Originally Posted by Pete Mack View Post
If you have a working debugger, you can just track down where it crashes and see what caused the crash. If you don't (can't get gdb to work, etc), you may need to install Visual Studio Express and debug with that. It takes a while to get set up, but learning to debug with VS is a lot easer than with gdb.

Oh yeah, and if you do get it to work, please make the project file available for Angband. Things would be easier on windows if VS were officially supported.
Dean and I have tried, VS does not like the source in folders structure of Angband.. The unintended consequence of that is that we are locking out newbie developers that need the best debugger on a free compiler for the most dominant platform that is out there..

T.
__________________
* Are you ready for something else ? Hellband 0.8.8 is out! *
konijn_ is offline   Reply With Quote
Old March 4, 2010, 17:07   #12
zaimoni
Knight
 
zaimoni's Avatar
 
Join Date: Apr 2007
Posts: 590
zaimoni is on a distinguished road
Quote:
Originally Posted by PowerDiver View Post
The recent OS-related crash differences that I have read about here have been due to accessing bad pointers. If you read from a bad pointer, should that cause a crash or simply return an arbitrary result? Different OSes treat this differently. Whether that difference is true of Vista vs XP is beyond my knowledge.
On Windows, reading from a bad pointer pointing into a non-existent memory page always errors. Vista+ have Data Execution Prevention available; if this is turned on it converts some things that are silent in XP- into errors. (I have Data Execution Prevention set globally, contrary to default, on my Vista and higher systems; I'd rather have browsers crash out than soak a drive-by malware infection.)

A read from a bad pointer into an existing memory page is likely to not crash, but as with all undefined behavior you take your chances....
__________________
Zaiband: end the "I shouldn't have survived that" experience. V3.0.6 fork on Hg.
Zaiband 3.0.10 ETA Mar. 7 2011 (Yes, schedule slipped. Latest testing indicates not enough assert() calls to allow release.)
Z.C++: pre-alpha C/C++ compiler system (usable preprocessor). Also on Hg. Z.C++ 0.0.10 ETA December 31 2011
zaimoni is offline   Reply With Quote
Old March 14, 2010, 06:58   #13
will_asher
DaJAngband Maintainer
 
will_asher's Avatar
 
Join Date: Apr 2007
Location: San Antonio, TX
Posts: 927
Donated: $10
will_asher is on a distinguished road
I'm still trying to track down the cause of this crash bug. I've narrowed it down and I'm almost positive that it happens in the itemlist function having to do with object mimmics showing up on the object list (unless there's more than one crash bug..). And it doesn't just happen on the older computer like I thought at first, but it doesn't happen reliably.

I've been working on trying to fix this bug for what seems like a long time now, so I thought I'd post the function here so maybe someone else can tell me what I did wrong. I copied the function from vanilla 3.1.1. The only changes I've made to it were:
1) to get it to work in my code based on vanilla 3.0.9
2) make objects sort by value (in the compare_items() function which I didn't copy here because I'm pretty sure it's not the problem)
3) to make object mimmics show up on the object list.

The only way I could figure how to put mimmics on the object list was to create a fake object for the mimmic and it seems to be forgetting that fake object between when it's created and when it actually lists the objects. It shows (nothing) on the object list instead of the mimmicked object, but it has the (nothing) in the middle of the list so I think it got sorted by value okay, but then lost the object.
m_ptr->disguised holds the k_idx of the object that the monster is disguised as.
I know the disguise_object_desc() function works, because it's also used when you (l)ook at the disguised mimmic, and there's no problems there.

Code:
/*
 * Display visible items, similar to display_monlist (the object list)
 * copied from V3.1.1
 */
void display_itemlist(void)
{
	int max, mx, my;
	unsigned num;
	int line = 1, x = 0;
	int cur_x;
	unsigned i;
	unsigned disp_count = 0;
	byte a;
	char c;

	object_type *types[MAX_ITEMLIST+2];
	int counts[MAX_ITEMLIST+2];
	unsigned counter = 0;

	int dungeon_hgt = p_ptr->depth == 0 ? TOWN_HGT : DUNGEON_HGT;
	int dungeon_wid = p_ptr->depth == 0 ? TOWN_WID : DUNGEON_WID;

	byte attr;
	char buf[80];

	int floor_list[MAX_FLOOR_STACK];

	/* Clear the term if in a subwindow, set x otherwise */
	if (Term != angband_term[0])
	{
		clear_from(0);
		max = Term->hgt - 1;
	}
	else
	{
		x = 13;
		max = Term->hgt - 2;
	}

	/* Look at each square of the dungeon for items */
	for (my = 0; my < dungeon_hgt; my++)
	{
		for (mx = 0; mx < dungeon_wid; mx++)
		{
			(void)scan_floor(floor_list, &num, my, mx, 3);
			/* num = scan_floor(floor_list, MAX_FLOOR_STACK, my, mx, 3); */

			/* check for object mimmics */
            if (cave_m_idx[my][mx] > 0)
			{
				monster_type *m_ptr = &mon_list[cave_m_idx[my][mx]];
				monster_race *r_ptr = &r_info[m_ptr->r_idx];
				/* disguised == 1 means it's mimmicking a terrain, not an object */
				if ((r_ptr->flags1 & (RF1_CHAR_MULTI)) && (m_ptr->disguised > 1) &&
					((m_ptr->meet == 100) || (player_can_see_bold(my, mx))))
				{
					object_type *i_ptr;
					object_type object_type_body;
					unsigned j;

					/* Get local object */
					i_ptr = &object_type_body;

					/* Create the item */
					object_prep(i_ptr, m_ptr->disguised);
					
					/* mark item as a disguised monster */
					i_ptr->thisbrand = 77;

					/* Skip gold/squelched */
					if (i_ptr->tval == TV_GOLD)	continue;
					/* we'll need this if you uncomment the squelch bit */
					/* if (i_ptr->tval == TV_CHEST) i_ptr->pval = randint(5); */

					/* skip squelched only if hide_squelchable is on */
					/* (if you can see an object, but it's not on the object */
					/* list then it's obvious that something's up.  If you see */
                    /* an object that you have squelched, you may forget that */
                    /* it's squelched.) */
					/* if ((squelch_item_ok(i_ptr)) && (hide_squelchable)) continue; */

					/* See if we've already seen a similar item; if so, just add */
					/* to its count */
					for (j = 0; j < counter; j++)
					{
						if (object_similar(i_ptr, types[j]))
						{
							counts[j] += i_ptr->number;
							break;
						}
					}

					/* We saw a new item. So insert it at the end of the list and */
					/* then sort it forward using compare_items(). The types list */
					/* is always kept sorted. */
					if (j == counter)
					{
						types[counter] = i_ptr;
						counts[counter] = i_ptr->number;

						while (j > 0 && compare_items(types[j - 1], types[j]) > 0)
						{
							object_type *tmp_o = types[j - 1];
							int tmpcount;

							types[j - 1] = types[j];
							types[j] = tmp_o;
							tmpcount = counts[j - 1];
							counts[j - 1] = counts[j];
							counts[j] = tmpcount;
							j--;
						}
						counter++;
					}
				}
			}

			/* Iterate over all the items found on this square */
			for (i = 0; i < num; i++)
			{
				object_type *o_ptr = &o_list[floor_list[i]];
				unsigned j;

				/* Skip gold/squelched */
				if (o_ptr->tval == TV_GOLD)	continue;
					
				/* skep squelched only if hide_squelchable is on */
                if ((squelch_item_ok(o_ptr)) && (hide_squelchable)) continue;

				/* See if we've already seen a similar item; if so, just add */
				/* to its count */
				for (j = 0; j < counter; j++)
				{
					if (object_similar(o_ptr, types[j]))
					{
						counts[j] += o_ptr->number;
						break;
					}
				}

				/* We saw a new item. So insert it at the end of the list and */
				/* then sort it forward using compare_items(). The types list */
				/* is always kept sorted. */
				if (j == counter)
				{
					types[counter] = o_ptr;
					counts[counter] = o_ptr->number;

					while (j > 0 && compare_items(types[j - 1], types[j]) > 0)
					{
						object_type *tmp_o = types[j - 1];
						int tmpcount;

						types[j - 1] = types[j];
						types[j] = tmp_o;
						tmpcount = counts[j - 1];
						counts[j - 1] = counts[j];
						counts[j] = tmpcount;
						j--;
					}
					counter++;
				}
			}
		}
	}

	/* Note no visible items */
	if (!counter)
	{
		/* Clear display and print note */
		c_prt(TERM_SLATE, "You see no items.", 0, 0);
		if (Term == angband_term[0])
			Term_addstr(-1, TERM_WHITE, "  (Press any key to continue.)");

		/* Done */
		return;
	}
	else
	{
		/* Reprint Message */
		prt(format("You can see %d item%s: (unaware objects in red)",
				   counter, (counter > 1 ? "s" : "")), 0, 0);
	}

	for (i = 0; i < counter; i++)
	{
		/* o_name will hold the object_desc() name for the object. */
		/* o_desc will also need to put a (x4) behind it. */
		/* can there be more than 999 stackable items on a level? */
		char o_name[80];
		char o_desc[86];

		object_type *o_ptr = types[i];

		/* We shouldn't list coins or squelched items */
		if (o_ptr->tval == TV_GOLD)	continue;
					
		/* skep squelched only if hide_squelchable is on */
		/* if ((squelch_item_ok(o_ptr)) && (hide_squelchable)) continue; */
		
		if (o_ptr->thisbrand == 77) disguise_object_desc(o_name, sizeof(o_name), o_ptr->k_idx);
		else object_desc(o_name, sizeof(o_name), o_ptr, FALSE, 3);

		if (counts[i] > 1)
			sprintf(o_desc, "%s (x%d)", o_name, counts[i]);
		else
			sprintf(o_desc, "%s", o_name);

		/* Reset position */
		cur_x = x;

		/* See if we need to scroll or not */
		if (Term == angband_term[0] && (line == max) && disp_count != counter)
		{
			prt("-- more --", line, x);
			anykey();

			/* Clear the screen */
			for (line = 1; line <= max; line++)
				prt("", line, x);

			/* Reprint Message */
			prt(format("You can see %d item%s:",
					   counter, (counter > 1 ? "s" : "")), 0, 0);

			/* Reset */
			line = 1;
		}
		else if (line == max)
		{
			continue;
		}

		/* Note the number of items actually displayed */
		disp_count++;

		if (artifact_p(o_ptr) && (object_known_p(o_ptr)))
			/* known artifact */
			attr = TERM_VIOLET;
		else if (!object_aware_p(o_ptr))
			/* unaware of kind */
			attr = TERM_RED;
		else if (object_is_worthless(o_ptr))
			/* worthless */
			attr = TERM_SLATE;
		else
			/* default */
			attr = TERM_WHITE;

		a = object_attr(o_ptr);
		c = object_char(o_ptr);

		/* Display the pict */
		Term_putch(cur_x++, line, a, c);
		if (use_bigtile) Term_putch(cur_x++, line, 255, -1);
		Term_putch(cur_x++, line, TERM_WHITE, ' ');

		/* Print and bump line counter */
		c_prt(attr, o_desc, line, cur_x);
		line++;
	}

	if (disp_count != counter)
	{
		/* Print "and others" message if we've run out of space */
		strnfmt(buf, sizeof buf, "  ...and %d others.", counter - disp_count);
		c_prt(TERM_WHITE, buf, line, x);
	}
	else
	{
		/* Otherwise clear a line at the end, for main-term display */
		prt("", line, x);
	}

	if (Term == angband_term[0])
		Term_addstr(-1, TERM_WHITE, "  (Press any key to continue.)");
}
PS: I don't see the point of a mimmic if you can't actually mistake the mimmic for the object it is mimmicking.
__________________
Will_Asher

Play DaJAngband:
http://sites.google.com/site/dajangbandwebsite/home

Last edited by will_asher; March 14, 2010 at 07:08.
will_asher is offline   Reply With Quote
Old March 14, 2010, 07:18   #14
Derakon
Prophet
 
Derakon's Avatar
 
Join Date: Dec 2009
Posts: 9,002
Derakon is on a distinguished road
I'll admit I didn't read all the code, but I think I see your problem. Your code looks broadly like this:
Code:
list_of_objects = []
for each tile in dungeon {
  append objects in tile to list_of_objects
  if monster is in tile and monster is a mimic {
    fake_object = makeObjectFromMonster(monster)
    append fake_object to list_of_objects
  }
}
The problem is that fake_object goes out of scope when the if statement closes, rendering it invalid. Future created objects then can use the memory that was used by fake_object, writing random stuff to it which will cause a crash when you later try to read it.
Derakon is offline   Reply With Quote
Old March 14, 2010, 07:37   #15
Nick
Vanilla maintainer
 
Nick's Avatar
 
Join Date: Apr 2007
Location: Canberra, Australia
Age: 54
Posts: 7,968
Donated: $60
Nick will become famous soon enough
I don't know if you've looked there, but NPP does that precise thing with making mimics look really like objects. AFAIK it doesn't have an item list, though.
__________________
One for the Dark Lord on his dark throne
In the Land of Mordor where the Shadows lie.
Nick is offline   Reply With Quote
Old March 14, 2010, 07:56   #16
will_asher
DaJAngband Maintainer
 
will_asher's Avatar
 
Join Date: Apr 2007
Location: San Antonio, TX
Posts: 927
Donated: $10
will_asher is on a distinguished road
Quote:
Originally Posted by Derakon View Post
I'll admit I didn't read all the code, but I think I see your problem. Your code looks broadly like this:
Code:
list_of_objects = []
for each tile in dungeon {
  append objects in tile to list_of_objects
  if monster is in tile and monster is a mimic {
    fake_object = makeObjectFromMonster(monster)
    append fake_object to list_of_objects
  }
}
The problem is that fake_object goes out of scope when the if statement closes, rendering it invalid. Future created objects then can use the memory that was used by fake_object, writing random stuff to it which will cause a crash when you later try to read it.
If the fake object goes out of scope, then why don't the real objects go out of scope? It looks to me like both the fake objects and the real objects are assigned to
object_type *types[MAX_ITEMLIST+2];
with this:
types[counter] = i_ptr;
And that's declared at the beginning of the function so it wouldn't go out of scope until the function ends. (you're probably right, I'm just trying to understand it)

EDIT: Thanks Derakon,
I moved
Code:
					object_type *i_ptr;
					object_type object_type_body;
to the top of the function and it seems to be fixed now, although I still don't really understand why..
__________________
Will_Asher

Play DaJAngband:
http://sites.google.com/site/dajangbandwebsite/home

Last edited by will_asher; March 14, 2010 at 08:22.
will_asher is offline   Reply With Quote
Old March 14, 2010, 16:37   #17
buzzkill
Prophet
 
buzzkill's Avatar
 
Join Date: May 2008
Location: Indiana, USA
Posts: 2,939
Donated: $8
buzzkill is on a distinguished road
So, just curious, will known flavors show up as mimics (or is that too evil). Will perception allow you to recognize a mimic as you approach it?

You see a Potion of Healing. It casts a nether bolt. You feel your life draining away. <more>
You Die.
__________________
www.mediafire.com/buzzkill - Get your 32x32 tiles here. UT32 now compatible Ironband and Quickband 9/6/2012.
My banding life on Buzzkill's ladder.
buzzkill is offline   Reply With Quote
Old March 14, 2010, 17:44   #18
Derakon
Prophet
 
Derakon's Avatar
 
Join Date: Dec 2009
Posts: 9,002
Derakon is on a distinguished road
Quote:
Originally Posted by will_asher View Post
If the fake object goes out of scope, then why don't the real objects go out of scope? It looks to me like both the fake objects and the real objects are assigned to
object_type *types[MAX_ITEMLIST+2];
with this:
types[counter] = i_ptr;
And that's declared at the beginning of the function so it wouldn't go out of scope until the function ends. (you're probably right, I'm just trying to understand it)
The real objects were allocated memory on the heap, not the stack. The heap is free-floating memory and doesn't care about scoping rules; however, because of this, it's very easy to create memory leaks (where objects are allocated to the heap, then become irrelevant to the program without first getting deallocated). When you do
Code:
object_type object_type_body;
you're creating an object_type on the stack; it will still go out of scope when the function finishes at the very least. In order to create the object on the heap, you'd need to do something like this:
Code:
object_type* object_type_body;
object_type_body = (object_type*) malloc(sizeof(object_type));
NOTE: it's been ages since I did any C coding, so this is probably wrong somehow. But the general idea is sound: create a pointer of the appropriate type, ask for a block of memory on the heap with the same size as the type you need to point to, then fill that memory with data.

Just remember to free the memory when you're done with it!
Derakon is offline   Reply With Quote
Old March 14, 2010, 18:31   #19
PowerDiver
Prophet
 
Join Date: Mar 2008
Posts: 2,712
PowerDiver is on a distinguished road
Quote:
Originally Posted by will_asher View Post
If the fake object goes out of scope, then why don't the real objects go out of scope? It looks to me like both the fake objects and the real objects are assigned to
object_type *types[MAX_ITEMLIST+2];
with this:
types[counter] = i_ptr;
And that's declared at the beginning of the function so it wouldn't go out of scope until the function ends. (you're probably right, I'm just trying to understand it)

EDIT: Thanks Derakon,
I moved
Code:
					object_type *i_ptr;
					object_type object_type_body;
to the top of the function and it seems to be fixed now, although I still don't really understand why..
I didn't look hard enough to understand your code completely, but that is worrisome. I would guess that if you have more than one type of mimic you will still have a bug. You have only one object_type_body. If you use it twice in the function, the previous value will be overwritten, and the i_ptr you copied into your list will no longer point to what you think it should be pointing to.

Mallocing and freeing leads to nightmares. I would suggest that you keep a suitably large array of object_type_body. The function starts by setting the counter to 0, and increment it each time you need a new one, checking of course that you don't go past the end of the array.

I am also unclear on who ever looks at the list that you put i_ptr into. If anyone ever looks at it after this function exits, then you have to declare the body array outside of the function.
PowerDiver is offline   Reply With Quote
Old March 14, 2010, 23:16   #20
zaimoni
Knight
 
zaimoni's Avatar
 
Join Date: Apr 2007
Posts: 590
zaimoni is on a distinguished road
Quote:
Originally Posted by PowerDiver View Post
Quote:
EDIT: Thanks Derakon,
I moved
Code:
object_type *i_ptr;
object_type object_type_body;
to the top of the function and it seems to be fixed now, although I still don't really understand why..
I didn't look hard enough to understand your code completely, but that is worrisome.
It's all over the V codebase he forked from, and highly annoying (I'd prefer to ditch the i_ptr/o_ptr for this construct and just use the reference operator & whenever needed).
__________________
Zaiband: end the "I shouldn't have survived that" experience. V3.0.6 fork on Hg.
Zaiband 3.0.10 ETA Mar. 7 2011 (Yes, schedule slipped. Latest testing indicates not enough assert() calls to allow release.)
Z.C++: pre-alpha C/C++ compiler system (usable preprocessor). Also on Hg. Z.C++ 0.0.10 ETA December 31 2011
zaimoni is offline   Reply With Quote
Reply


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
Code: Notes live where? camlost Vanilla 4 February 20, 2009 22:11
fun with the code (and a big thank you) will_asher Idle chatter 0 March 3, 2008 05:24
Screensaver needs to rewrite some code APWhite Vanilla 0 October 16, 2007 22:19
Looking through the code K.I.L.E.R Vanilla 5 July 11, 2007 09:01
The safe_setuid code CJNyfalt Vanilla 11 June 26, 2007 04:25


All times are GMT +1. The time now is 01:21.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2020, vBulletin Solutions Inc.