Pārlūkot izejas kodu

* Possible fix to ers/status_change crashing. [FlavioJS]
- this patch is untested. Didn't find anyone willing to test it and I can't reproduce the crash so can't test the patch.
symptom:
status_change_entry.timer is being modified after the entry is freed.
ers uses that memory location as a pointer when the entry is freed, it crashes when accessing the contents when it points to an invalid location.
assumption:
status_change_start starts an already existing status.
as a consequence of something called inside status_change_start the status is ended.
when the sce is finally being modified, it's modifying a freed entry.

git-svn-id: https://svn.code.sf.net/p/rathena/svn/trunk@12058 54d463be-8e91-2dee-dedb-b68131a5f0ec

FlavioJS 17 gadi atpakaļ
vecāks
revīzija
a85a22d75a
2 mainītis faili ar 31 papildinājumiem un 10 dzēšanām
  1. 12 0
      Changelog-Trunk.txt
  2. 19 10
      src/map/status.c

+ 12 - 0
Changelog-Trunk.txt

@@ -3,6 +3,18 @@ Date	Added
 AS OF SVN REV. 5091, WE ARE NOW USING TRUNK.  ALL UNTESTED BUGFIXES/FEATURES GO INTO TRUNK.
 IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK.
 
+2008/01/12
+	* Possible fix to ers/status_change crashing. [FlavioJS]
+	- this patch is untested. Didn't find anyone willing to test it and I can't 
+	  reproduce the crash so can't test the patch.
+	  symptom:
+	   status_change_entry.timer is being modified after the entry is freed.
+	   ers uses that memory location as a pointer when the entry is freed, 
+	   it crashes when accessing the contents when it points to an invalid location.
+	  assumption:
+	   status_change_start starts an already existing status.
+	   as a consequence of something called inside status_change_start the status is ended.
+	   when the sce is finally being modified, it's modifying a freed entry.
 2008/01/11
 	* Implemented the extra damage bonus to TK_JUMPKICK when it is used while
 	  running (however what the bonus's equation is has been lost to time, so

+ 19 - 10
src/map/status.c

@@ -5000,15 +5000,18 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
 				if(sce->val1 > val1)
 					return 1; //Return true to not mess up skill animations. [Skotlex
 		}
-		(sc->count)--;
-		if (sce->timer != -1)
-			delete_timer(sce->timer, status_change_timer);
-		sce->timer = -1;
 	}
 	//NOTE: avoiding returning after this point, or if you must return a failure, use this to properly cleanup any existing data. 
-#define sc_start_abort(ret) { \
-	if (sce) { ers_free(sc_data_ers, sce); sc->data[type] = NULL; } \
-	return ret; }
+#define sc_start_abort(ret) \
+	do{ \
+		if((sce=sc->data[type])){ \
+			--(sc->count); \
+			sc->data[type] = NULL; \
+			if( sce->timer != INVALID_TIMER ) delete_timer(sce->timer, status_change_timer); \
+			ers_free(sc_data_ers, sce); \
+			return ret; \
+		} \
+	}while(0)
 
 	vd = status_get_viewdata(bl);
 	calc_flag = StatusChangeFlagTable[type];
@@ -6101,10 +6104,16 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
 	else if (sd) //Send packet to self otherwise (disguised player?)
 		clif_status_load(bl,StatusIconChangeTable[type],1);
 
-	(sc->count)++;
-
-	if (!sce) //Not null when overwriting existing sc.
+	if((sce=sc->data[type]))
+	{// reuse old sc
+		if( sce->timer != INVALID_TIMER )
+			delete_timer(sce->timer, status_change_timer);
+	}
+	else
+	{// new sc
+		++(sc->count);
 		sce = sc->data[type] = ers_alloc(sc_data_ers, struct status_change_entry);
+	}
 	sce->val1 = val1;
 	sce->val2 = val2;
 	sce->val3 = val3;