Jelajahi Sumber

* 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 tahun lalu
induk
melakukan
fe95610ba8

+ 4 - 2
doc/atcommands.txt

@@ -3,7 +3,7 @@
 //===== By: ==================================================
 //= rAthena Dev Team
 //===== Current Version: =====================================
-//= 20130817
+//= 20130827
 //===== Description: =========================================
 //= 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.
+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.
 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 
 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
 ---------

+ 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 "problems whatsoever.";
 					if (.@compass_check)
-						viewpoint 1,236,276,4,0x99FFFFF;
+						viewpoint 1,236,276,4,0x99FFFF;
 					break;
 				case 4:
 					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 "be clear to you now! Don't";
 				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;
 				mes "[Elder]";
 				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?";
 		next;
 		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;
 		mes "["+ strcharinfo(0) +"]";
 		mes "...This may be?!";
 		next;
 		mes "[Voice unidentified]";
 		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;
 		next;
 		mes "["+ strcharinfo(0) +"]";

+ 1 - 0
src/common/cbasetypes.h

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

+ 53 - 15
src/map/script.c

@@ -258,6 +258,10 @@ static jmp_buf     error_jump;
 static char*       error_msg;
 static const char* error_pos;
 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 )
 // [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)
 
+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
 static void check_event(struct script_state *st, const char *evt)
 {
@@ -892,8 +900,10 @@ const char* skip_space(const char* p)
 			p += 2;
 			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] == '/' )
 				{// end of block comment
 					p += 2;
@@ -1225,7 +1235,7 @@ const char* parse_variable(const char* p) {
  *------------------------------------------*/
 const char* parse_simpleexpr(const char *p)
 {
-	int i;
+	long long i;
 	p=skip_space(p);
 
 	if(*p==';' || *p==',')
@@ -1250,8 +1260,15 @@ const char* parse_simpleexpr(const char *p)
 	} else if(ISDIGIT(*p) || ((*p=='-' || *p=='+') && ISDIGIT(p[1]))){
 		char *np;
 		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;
 	} else if(*p=='"'){
 		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);
 }
 
-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
 	int j;
 	int line = start_line;
 	const char *p;
 	const char *linestart[5] = { NULL, NULL, NULL, NULL, NULL };
-	StringBuf buf;
 
 	for(p=src;p && *p;line++){
 		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;
 	}
 
-	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++ ) {
-		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++) {
-		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));
 	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
  *------------------------------------------*/
@@ -2302,6 +2336,10 @@ struct script_code* parse_script(const char *src,const char *file,int line,int o
 	char end;
 	bool unresolved_names = false;
 
+	parser_current_src = src;
+	parser_current_file = file;
+	parser_current_line = line;
+
 	if( src == NULL )
 		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);
 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);
 void run_script_sub(struct script_code *rootscript,int pos,int rid,int oid, char* file, int lineno);