浏览代码

* Added an integer overflow check on literal values in the script parser. (Hercules 8351881, 86602bb, 3d19c2d, 184ad8a)
- When attempting to use a value greater than INT_MAX or smaller than INT_MIN (about +/- 2 billions), a warning message will be shown and the values capped to INT_MAX or INT_MIN.
- Corrected some scripts that were attempting to use such values.
- Fixed some possible issues when using literal negative values in scripts.
* Added a note to @job documentation.

Signed-off-by: Euphy <euphy@rathena.org>

Euphy 11 年之前
父节点
当前提交
fe95610ba8

+ 4 - 2
doc/atcommands.txt

@@ -3,7 +3,7 @@
 //===== By: ==================================================
 //===== By: ==================================================
 //= rAthena Dev Team
 //= rAthena Dev Team
 //===== Current Version: =====================================
 //===== Current Version: =====================================
-//= 20130817
+//= 20130827
 //===== Description: =========================================
 //===== Description: =========================================
 //= List of available atcommands and their functions.
 //= List of available atcommands and their functions.
 //============================================================
 //============================================================
@@ -866,9 +866,11 @@ Resets a Star Gladiator's marked maps.
 
 
 ---------------------------------------
 ---------------------------------------
 
 
-@jobchange <job name/ID>
+@jobchange <job name>
+@jobchange <job ID> {<upper>}
 
 
 Changes your job.
 Changes your job.
+An 'upper' value can be specified with a job ID to produce its normal (0), advanced (1), or baby (2) version.
 If no job is given, a list of all available jobs will be returned.
 If no job is given, a list of all available jobs will be returned.
 Note that jobs 22 (Wedding), 26 (Summer), 27 (Christmas), and 28 (Hanbok) are not available via @job.
 Note that jobs 22 (Wedding), 26 (Summer), 27 (Christmas), and 28 (Hanbok) are not available via @job.
 
 

+ 3 - 1
doc/script_commands.txt

@@ -398,7 +398,9 @@ identical. Writing a number like '0x<hex digits>' will make it recognized as a
 hexadecimal value. Notice that 0x10 is equal to 16. Also notice that if you try 
 hexadecimal value. Notice that 0x10 is equal to 16. Also notice that if you try 
 to 'mes 0x10' it will print '16'.
 to 'mes 0x10' it will print '16'.
 
 
-This is not used much, but it pays to know about it.
+Number values can't exceed the limits of an integer variable: Any number
+greater than INT_MAX (2147483647) or smaller than INT_MIN (-2147483648) will
+be capped to those values and will cause a warning to be reported.
 
 
 Variables
 Variables
 ---------
 ---------

+ 1 - 1
npc/pre-re/guides/guides_lighthalzen.txt

@@ -80,7 +80,7 @@ lighthalzen,207,310,5	script	Guide#lhz::LhzGuide	852,{
 					mes "activity, or if you have any";
 					mes "activity, or if you have any";
 					mes "problems whatsoever.";
 					mes "problems whatsoever.";
 					if (.@compass_check)
 					if (.@compass_check)
-						viewpoint 1,236,276,4,0x99FFFFF;
+						viewpoint 1,236,276,4,0x99FFFF;
 					break;
 					break;
 				case 4:
 				case 4:
 					mes "[Lighthalzen Guide]";
 					mes "[Lighthalzen Guide]";

+ 4 - 4
npc/quests/quests_lighthalzen.txt

@@ -4435,10 +4435,10 @@ lighthalzen,346,263,3	script	Elder#lhz	846,{
 				mes "you must search should";
 				mes "you must search should";
 				mes "be clear to you now! Don't";
 				mes "be clear to you now! Don't";
 				mes "forget these placemarks!";
 				mes "forget these placemarks!";
-				viewpoint 1,104,282,1,0xFF99FF33;
-				viewpoint 1,105,282,2,0xFF99FF33;
-				viewpoint 1,104,281,3,0xFF99FF33;
-				viewpoint 1,105,281,4,0xFF99FF33;
+				viewpoint 1,104,282,1,0x99FF33;
+				viewpoint 1,105,282,2,0x99FF33;
+				viewpoint 1,104,281,3,0x99FF33;
+				viewpoint 1,105,281,4,0x99FF33;
 				next;
 				next;
 				mes "[Elder]";
 				mes "[Elder]";
 				mes "Good luck, youngster.";
 				mes "Good luck, youngster.";

+ 8 - 8
npc/quests/quests_moscovia.txt

@@ -10990,20 +10990,20 @@ treasure01,24,39,0	script	Old Bed#rus38	111,{
 		mes "...?! What is this?";
 		mes "...?! What is this?";
 		next;
 		next;
 		mes "- There is a scar on the sheet that seems to have the location !! -";
 		mes "- There is a scar on the sheet that seems to have the location !! -";
-		viewpoint 1,165,58,1,0xFFFF0000;
-		viewpoint 1,61,183,2,0xFFFF0000;
-		viewpoint 1,98,118,3,0xFFFF0000;
-		viewpoint 1,27,115,4,0xFFFF0000;
+		viewpoint 1,165,58,1,0xFF0000;
+		viewpoint 1,61,183,2,0xFF0000;
+		viewpoint 1,98,118,3,0xFF0000;
+		viewpoint 1,27,115,4,0xFF0000;
 		next;
 		next;
 		mes "["+ strcharinfo(0) +"]";
 		mes "["+ strcharinfo(0) +"]";
 		mes "...This may be?!";
 		mes "...This may be?!";
 		next;
 		next;
 		mes "[Voice unidentified]";
 		mes "[Voice unidentified]";
 		mes "Who is there!?";
 		mes "Who is there!?";
-		viewpoint 2,165,58,1,0xFF00FF00;
-		viewpoint 2,61,183,2,0xFF00FF00;
-		viewpoint 2,98,118,3,0xFF00FF00;
-		viewpoint 2,27,115,4,0xFF00FF00;
+		viewpoint 2,165,58,1,0x00FF00;
+		viewpoint 2,61,183,2,0x00FF00;
+		viewpoint 2,98,118,3,0x00FF00;
+		viewpoint 2,27,115,4,0x00FF00;
 		emotion e_omg,1;
 		emotion e_omg,1;
 		next;
 		next;
 		mes "["+ strcharinfo(0) +"]";
 		mes "["+ strcharinfo(0) +"]";

+ 1 - 0
src/common/cbasetypes.h

@@ -241,6 +241,7 @@ typedef uintptr_t uintptr;
 #endif
 #endif
 #if defined(_MSC_VER) && _MSC_VER > 1200
 #if defined(_MSC_VER) && _MSC_VER > 1200
 #define strtoull			_strtoui64
 #define strtoull			_strtoui64
+#define strtoll				_strtoi64
 #endif
 #endif
 
 
 // keyword replacement
 // keyword replacement

+ 53 - 15
src/map/script.c

@@ -258,6 +258,10 @@ static jmp_buf     error_jump;
 static char*       error_msg;
 static char*       error_msg;
 static const char* error_pos;
 static const char* error_pos;
 static int         error_report; // if the error should produce output
 static int         error_report; // if the error should produce output
+// Used by disp_warning_message
+static const char* parser_current_src;
+static const char* parser_current_file;
+static int         parser_current_line;
 
 
 // for advanced scripting support ( nested if, switch, while, for, do-while, function, etc )
 // for advanced scripting support ( nested if, switch, while, for, do-while, function, etc )
 // [Eoe / jA 1080, 1081, 1094, 1164]
 // [Eoe / jA 1080, 1081, 1094, 1164]
@@ -639,6 +643,10 @@ static void disp_error_message2(const char *mes,const char *pos,int report)
 }
 }
 #define disp_error_message(mes,pos) disp_error_message2(mes,pos,1)
 #define disp_error_message(mes,pos) disp_error_message2(mes,pos,1)
 
 
+static void disp_warning_message(const char *mes, const char *pos) {
+	script_warning(parser_current_src,parser_current_file,parser_current_line,mes,pos);
+}
+
 /// Checks event parameter validity
 /// Checks event parameter validity
 static void check_event(struct script_state *st, const char *evt)
 static void check_event(struct script_state *st, const char *evt)
 {
 {
@@ -892,8 +900,10 @@ const char* skip_space(const char* p)
 			p += 2;
 			p += 2;
 			for(;;)
 			for(;;)
 			{
 			{
-				if( *p == '\0' )
-					return p;//disp_error_message("script:skip_space: end of file while parsing block comment. expected "CL_BOLD"*/"CL_NORM, p);
+				if( *p == '\0' ) {
+					disp_warning_message("script:script->skip_space: end of file while parsing block comment. expected "CL_BOLD"*/"CL_NORM, p);
+					return p;
+				}
 				if( *p == '*' && p[1] == '/' )
 				if( *p == '*' && p[1] == '/' )
 				{// end of block comment
 				{// end of block comment
 					p += 2;
 					p += 2;
@@ -1225,7 +1235,7 @@ const char* parse_variable(const char* p) {
  *------------------------------------------*/
  *------------------------------------------*/
 const char* parse_simpleexpr(const char *p)
 const char* parse_simpleexpr(const char *p)
 {
 {
-	int i;
+	long long i;
 	p=skip_space(p);
 	p=skip_space(p);
 
 
 	if(*p==';' || *p==',')
 	if(*p==';' || *p==',')
@@ -1250,8 +1260,15 @@ const char* parse_simpleexpr(const char *p)
 	} else if(ISDIGIT(*p) || ((*p=='-' || *p=='+') && ISDIGIT(p[1]))){
 	} else if(ISDIGIT(*p) || ((*p=='-' || *p=='+') && ISDIGIT(p[1]))){
 		char *np;
 		char *np;
 		while(*p == '0' && ISDIGIT(p[1])) p++;
 		while(*p == '0' && ISDIGIT(p[1])) p++;
-		i=strtoul(p,&np,0);
-		add_scripti(i);
+		i=strtoll(p,&np,0);
+		if( i < INT_MIN ) {
+			i = INT_MIN;
+			disp_warning_message("parse_simpleexpr: underflow detected, capping value to INT_MIN",p);
+		} else if( i > INT_MAX ) {
+			i = INT_MAX;
+			disp_warning_message("parse_simpleexpr: overflow detected, capping value to INT_MAX",p);
+		}
+		add_scripti((int)i);
 		p=np;
 		p=np;
 	} else if(*p=='"'){
 	} else if(*p=='"'){
 		add_scriptc(C_STR);
 		add_scriptc(C_STR);
@@ -2254,14 +2271,12 @@ static const char* script_print_line(StringBuf* buf, const char* p, const char*
 	return p+i+(p[i] == '\n' ? 1 : 0);
 	return p+i+(p[i] == '\n' ? 1 : 0);
 }
 }
 
 
-void script_error(const char* src, const char* file, int start_line, const char* error_msg, const char* error_pos)
-{
+void script_errorwarning_sub(StringBuf *buf, const char* src, const char* file, int start_line, const char* error_msg, const char* error_pos) {
 	// Find the line where the error occurred
 	// Find the line where the error occurred
 	int j;
 	int j;
 	int line = start_line;
 	int line = start_line;
 	const char *p;
 	const char *p;
 	const char *linestart[5] = { NULL, NULL, NULL, NULL, NULL };
 	const char *linestart[5] = { NULL, NULL, NULL, NULL, NULL };
-	StringBuf buf;
 
 
 	for(p=src;p && *p;line++){
 	for(p=src;p && *p;line++){
 		const char *lineend=strchr(p,'\n');
 		const char *lineend=strchr(p,'\n');
@@ -2275,21 +2290,40 @@ void script_error(const char* src, const char* file, int start_line, const char*
 		p=lineend+1;
 		p=lineend+1;
 	}
 	}
 
 
-	StringBuf_Init(&buf);
-	StringBuf_AppendStr(&buf, "\a\n");
-	StringBuf_Printf(&buf, "script error on %s line %d\n", file, line);
-	StringBuf_Printf(&buf, "    %s\n", error_msg);
+	StringBuf_Printf(buf, "script error on %s line %d\n", file, line);
+	StringBuf_Printf(buf, "    %s\n", error_msg);
 	for(j = 0; j < 5; j++ ) {
 	for(j = 0; j < 5; j++ ) {
-		script_print_line(&buf, linestart[j], NULL, line + j - 5);
+		script_print_line(buf, linestart[j], NULL, line + j - 5);
 	}
 	}
-	p = script_print_line(&buf, p, error_pos, -line);
+	p = script_print_line(buf, p, error_pos, -line);
 	for(j = 0; j < 5; j++) {
 	for(j = 0; j < 5; j++) {
-		p = script_print_line(&buf, p, NULL, line + j + 1 );
+		p = script_print_line(buf, p, NULL, line + j + 1 );
 	}
 	}
+}
+
+void script_error(const char* src, const char* file, int start_line, const char* error_msg, const char* error_pos) {
+	StringBuf buf;
+
+	StringBuf_Init(&buf);
+	StringBuf_AppendStr(&buf, "\a\n");
+
+	script_errorwarning_sub(&buf, src, file, start_line, error_msg, error_pos);
+
 	ShowError("%s", StringBuf_Value(&buf));
 	ShowError("%s", StringBuf_Value(&buf));
 	StringBuf_Destroy(&buf);
 	StringBuf_Destroy(&buf);
 }
 }
 
 
+void script_warning(const char* src, const char* file, int start_line, const char* error_msg, const char* error_pos) {
+	StringBuf buf;
+
+	StringBuf_Init(&buf);
+
+	script_errorwarning_sub(&buf, src, file, start_line, error_msg, error_pos);
+
+	ShowWarning("%s", StringBuf_Value(&buf));
+	StringBuf_Destroy(&buf);
+}
+
 /*==========================================
 /*==========================================
  * Analysis of the script
  * Analysis of the script
  *------------------------------------------*/
  *------------------------------------------*/
@@ -2302,6 +2336,10 @@ struct script_code* parse_script(const char *src,const char *file,int line,int o
 	char end;
 	char end;
 	bool unresolved_names = false;
 	bool unresolved_names = false;
 
 
+	parser_current_src = src;
+	parser_current_file = file;
+	parser_current_line = line;
+
 	if( src == NULL )
 	if( src == NULL )
 		return NULL;// empty script
 		return NULL;// empty script
 
 

+ 1 - 0
src/map/script.h

@@ -154,6 +154,7 @@ enum script_parse_options {
 
 
 const char* skip_space(const char* p);
 const char* skip_space(const char* p);
 void script_error(const char* src, const char* file, int start_line, const char* error_msg, const char* error_pos);
 void script_error(const char* src, const char* file, int start_line, const char* error_msg, const char* error_pos);
+void script_warning(const char* src, const char* file, int start_line, const char* error_msg, const char* error_pos);
 
 
 struct script_code* parse_script(const char* src,const char* file,int line,int options);
 struct script_code* parse_script(const char* src,const char* file,int line,int options);
 void run_script_sub(struct script_code *rootscript,int pos,int rid,int oid, char* file, int lineno);
 void run_script_sub(struct script_code *rootscript,int pos,int rid,int oid, char* file, int lineno);