[m-rev.] diff: fix HTML character escapes in deep profiler

Julien Fischer juliensf at cs.mu.OZ.AU
Wed Jun 22 17:21:29 AEST 2005


Estimated hours taken: 3
Branches: main, release

Workaround a problem where the deep profiling tool wasn't
escaping HTML special characters in procedure and file names.

deep_profiler/html_format.m:
deep_profiler/query.m:
	When generating HTML make sure to escape special
	characters, like '<', correctly.

	Use state variable notation for the IO state
	throughout these files.

Julien.

Index: html_format.m
===================================================================
RCS file: /home/mercury1/repository/mercury/deep_profiler/html_format.m,v
retrieving revision 1.5
diff -u -r1.5 html_format.m
--- html_format.m	25 Apr 2005 07:55:54 -0000	1.5
+++ html_format.m	21 Jun 2005 07:05:04 -0000
@@ -121,6 +121,11 @@
 :- func deep_cmd_pref_to_url(preferences, deep, cmd) = string.

 :- func plural(int) = string.
+
+	% Convert any special characters in a string into appropriate
+	% HTML escapes.
+	%
+:- func escape_html_string(string) = string.

 %-----------------------------------------------------------------------------%

@@ -1840,18 +1845,18 @@
 	deep_lookup_proc_statics(Deep, PSPtr, PS),
 	ProcName = PS ^ ps_refined_id,
 	HTML = string__format("<A HREF=""%s"">%s</A>",
-		[s(URL), s(ProcName)]).
+		[s(URL), s(escape_html_string(ProcName))]).

 module_name_to_html_ref(Pref, Deep, ModuleName) = HTML :-
 	URL = deep_cmd_pref_to_url(Pref, Deep, module(ModuleName)),
 	HTML = string__format("<A HREF=""%s"">%s</A>",
-		[s(URL), s(ModuleName)]).
+		[s(URL), s(escape_html_string(ModuleName))]).

 clique_ptr_to_html_ref(Pref, Deep, ProcName, CliquePtr) = HTML :-
 	CliquePtr = clique_ptr(CliqueNum),
 	URL = deep_cmd_pref_to_url(Pref, Deep, clique(CliqueNum)),
 	HTML = string__format("<A HREF=""%s"">%s</A>",
-		[s(URL), s(ProcName)]).
+		[s(URL), s(escape_html_string(ProcName))]).

 deep_cmd_pref_to_url(Pref, Deep, Cmd) =
 	machine_datafile_cmd_pref_to_url(Deep ^ server_name,
@@ -1866,4 +1871,45 @@
 		Plural = "s"
 	).

+%-----------------------------------------------------------------------------%
+
+% This code was pretty much taken directly from extras/cgi/html.m.
+
+escape_html_string(String) = EscapedString :-
+	string.to_char_list(String, Chars),
+	escape_html_chars(Chars, EscapedChars, []),
+	string.from_char_list(EscapedChars, EscapedString).
+
+:- pred escape_html_chars(list(char)::in, list(char)::out, list(char)::in)
+	is det.
+
+escape_html_chars([]) --> [].
+escape_html_chars([Char | Chars]) -->
+	escape_html_char(Char),
+	escape_html_chars(Chars).
+
+:- pred escape_html_char(char::in, list(char)::out, list(char)::in) is det.
+
+escape_html_char(Char) -->
+	( { special_html_char(Char, String) } ->
+		{ string.to_char_list(String, Chars) },
+		insert(Chars)
+	;
+		[Char]
+	).
+
+:- pred special_html_char(char::in, string::out) is semidet.
+
+special_html_char('&', "&").
+special_html_char('<', "<").
+special_html_char('>', ">").
+
+:- pred insert(list(T), list(T), list(T)).
+:- mode insert(in, out, in) is det.
+
+insert(NewChars, Chars, Chars0) :-
+	list__append(NewChars, Chars0, Chars).
+
+%-----------------------------------------------------------------------------%
+:- end_module html_format.
 %-----------------------------------------------------------------------------%
Index: query.m
===================================================================
RCS file: /home/mercury1/repository/mercury/deep_profiler/query.m,v
retrieving revision 1.6
diff -u -r1.6 query.m
--- query.m	24 Mar 2005 01:10:28 -0000	1.6
+++ query.m	22 Jun 2005 07:10:08 -0000
@@ -22,6 +22,7 @@
 	io::di, io::uo) is cc_multi.

 %-----------------------------------------------------------------------------%
+%-----------------------------------------------------------------------------%

 :- implementation.

@@ -46,8 +47,8 @@

 %-----------------------------------------------------------------------------%

-try_exec(Cmd, Pref, Deep, HTML, IO0, IO) :-
-	try_io(exec(Cmd, Pref, Deep), Result, IO0, IO),
+try_exec(Cmd, Pref, Deep, HTML, !IO) :-
+	try_io(exec(Cmd, Pref, Deep), Result, !IO),
 	(
 		Result = succeeded(HTML)
 	;
@@ -68,20 +69,20 @@
 :- pred exec(cmd::in, preferences::in, deep::in, string::out,
 	io::di, io::uo) is det.

-exec(restart, _Pref, _Deep, _HTML, IO, IO) :-
+exec(restart, _Pref, _Deep, _HTML, !IO) :-
 	% Our caller is supposed to filter out restart commands.
 	error("exec: found restart command").
-exec(quit, _Pref, Deep, HTML, IO, IO) :-
+exec(quit, _Pref, Deep, HTML, !IO) :-
 	HTML = string__format(
 		"<H3>Shutting down deep profile server for %s.</H3>\n",
 		[s(Deep ^ data_file_name)]).
-exec(timeout(TimeOut), _Pref, _Deep, HTML, IO, IO) :-
+exec(timeout(TimeOut), _Pref, _Deep, HTML, !IO) :-
 	HTML = string__format("<H3>Timeout set to %d minutes</H3>\n",
 		[i(TimeOut)]).
-exec(Cmd, Pref, Deep, HTML, IO, IO) :-
+exec(Cmd, Pref, Deep, HTML, !IO) :-
 	Cmd = menu,
 	HTML = generate_menu_page(Cmd, Pref, Deep).
-exec(Cmd, Pref, Deep, HTML, IO, IO) :-
+exec(Cmd, Pref, Deep, HTML, !IO) :-
 	Cmd = root(MaybePercent),
 	deep_lookup_clique_index(Deep, Deep ^ root, RootCliquePtr),
 	RootCliquePtr = clique_ptr(RootCliqueNum),
@@ -94,7 +95,7 @@
 		generate_clique_page(Cmd, RootCliqueNum, Pref, Deep, HTML,
 			100, _)
 	).
-exec(Cmd, Pref, Deep, HTML, IO, IO) :-
+exec(Cmd, Pref, Deep, HTML, !IO) :-
 	Cmd = clique(CliqueNum),
 	CliquePtr = clique_ptr(CliqueNum),
 	( valid_clique_ptr(Deep, CliquePtr) ->
@@ -105,7 +106,7 @@
 			"There is no clique with that number.\n" ++
 			page_footer(Cmd, Pref, Deep)
 	).
-exec(Cmd, Pref, Deep, HTML, IO, IO) :-
+exec(Cmd, Pref, Deep, HTML, !IO) :-
 	Cmd = proc(PSI),
 	PSPtr = proc_static_ptr(PSI),
 	( valid_proc_static_ptr(Deep, PSPtr) ->
@@ -116,23 +117,22 @@
 			"There is no procedure with that number.\n" ++
 			page_footer(Cmd, Pref, Deep)
 	).
-exec(Cmd, Pref, Deep, HTML, IO0, IO) :-
+exec(Cmd, Pref, Deep, HTML, !IO) :-
 	Cmd = proc_callers(PSI, CallerGroups, BunchNum),
 	PSPtr = proc_static_ptr(PSI),
 	( valid_proc_static_ptr(Deep, PSPtr) ->
 		generate_proc_callers_page(Cmd, PSPtr, CallerGroups, BunchNum,
-			Pref, Deep, HTML, IO0, IO)
+			Pref, Deep, HTML, !IO)
 	;
 		HTML =
 			page_banner(Cmd, Pref) ++
 			"There is no procedure with that number.\n" ++
-			page_footer(Cmd, Pref, Deep),
-		IO = IO0
+			page_footer(Cmd, Pref, Deep)
 	).
-exec(Cmd, Pref, Deep, HTML, IO, IO) :-
+exec(Cmd, Pref, Deep, HTML, !IO) :-
 	Cmd = modules,
 	HTML = generate_modules_page(Cmd, Pref, Deep).
-exec(Cmd, Pref, Deep, HTML, IO, IO) :-
+exec(Cmd, Pref, Deep, HTML, !IO) :-
 	Cmd = module(ModuleName),
 	( map__search(Deep ^ module_data, ModuleName, ModuleData) ->
 		HTML = generate_module_page(Cmd, ModuleName, ModuleData,
@@ -143,19 +143,19 @@
 			"There is no procedure with that number.\n" ++
 			page_footer(Cmd, Pref, Deep)
 	).
-exec(Cmd, Pref, Deep, HTML, IO, IO) :-
+exec(Cmd, Pref, Deep, HTML, !IO) :-
 	Cmd = top_procs(Limit, CostKind, InclDesc, Scope),
 	HTML = generate_top_procs_page(Cmd, Limit, CostKind, InclDesc, Scope,
 		Pref, Deep).
-exec(proc_static(PSI), _Pref, Deep, HTML, IO, IO) :-
+exec(proc_static(PSI), _Pref, Deep, HTML, !IO) :-
 	HTML = generate_proc_static_debug_page(PSI, Deep).
-exec(proc_dynamic(PDI), _Pref, Deep, HTML, IO, IO) :-
+exec(proc_dynamic(PDI), _Pref, Deep, HTML, !IO) :-
 	HTML = generate_proc_dynamic_debug_page(PDI, Deep).
-exec(call_site_static(CSSI), _Pref, Deep, HTML, IO, IO) :-
+exec(call_site_static(CSSI), _Pref, Deep, HTML, !IO) :-
 	HTML = generate_call_site_static_debug_page(CSSI, Deep).
-exec(call_site_dynamic(CSDI), _Pref, Deep, HTML, IO, IO) :-
+exec(call_site_dynamic(CSDI), _Pref, Deep, HTML, !IO) :-
 	HTML = generate_call_site_dynamic_debug_page(CSDI, Deep).
-exec(raw_clique(CI), _Pref, Deep, HTML, IO, IO) :-
+exec(raw_clique(CI), _Pref, Deep, HTML, !IO) :-
 	HTML = generate_clique_debug_page(CI, Deep).

 %-----------------------------------------------------------------------------%
@@ -472,7 +472,7 @@
 		fields_header(Pref, source_proc, totals_meaningful,
 			wrap_clique_links(clique_ptr(CliqueNum),
 				Pref, Deep)) ++
-		CliqueHTML ++
+ 		CliqueHTML ++
 		table_end(Pref) ++
 		page_footer(Cmd, Pref, Deep).

@@ -482,7 +482,7 @@
 generate_proc_page(Cmd, PSPtr, Pref, Deep) =
 	page_banner(Cmd, Pref) ++
 	string__format("<H3>Summary of procedure %s:</H3>\n",
-		[s(proc_static_name(Deep, PSPtr))]) ++
+		[s(escape_html_string(proc_static_name(Deep, PSPtr)))]) ++
 	table_start(Pref) ++
 	fields_header(Pref, source_proc, totals_meaningful,
 		wrap_proc_links(PSPtr, Pref, Deep)) ++
@@ -1049,7 +1049,11 @@
 	sum_line_group_measurements(SubLines, Own, Desc),
 	SummaryHTML =
 		string__format("<TD CLASS=id>%s:%d</TD>\n",
-			[s(FileName), i(LineNumber)]) ++
+			[s(escape_html_string(FileName)), i(LineNumber)]) ++
+		%
+		% NOTE: we don't escape HTML special characters for
+		% 'CallSiteName' because it has already been done.
+		%
 		string__format("<TD CLASS=id>%s</TD>\n",
 			[s(CallSiteName)]),
 	(
@@ -1086,7 +1090,8 @@
 			FileName, LineNumber, Kind,
 			CallerPSPtr, CallSiteCallList)
 	),
-	CSSContext = string__format("%s:%d", [s(FileName), i(LineNumber)]),
+	CSSContext = string__format("%s:%d",
+		[s(escape_html_string(FileName)), i(LineNumber)]),
 	LineGroup = add_context(CSSContext, LineGroup0).

 :- func normal_call_site_summary_to_html(preferences, deep, string, int,
@@ -1134,6 +1139,10 @@
 		FileName, LineNumber, RawCallSiteName, CallerPSPtr),
 		CallSiteCallList),
 	sum_line_group_measurements(SubLines, Own, Desc),
+	%
+	% NOTE: we don't escape HTML special characters for
+	% 'CallSiteName' because it has already been done.
+	%
 	SummaryHTML =
 		string__format("<TD CLASS=id>%s</TD>\n",
 			[s(CallSiteName)]),
@@ -1256,11 +1265,12 @@
 	deep_lookup_csd_desc(Deep, CSDPtr, CallSiteDesc),
 	deep_lookup_clique_index(Deep, CalleePDPtr, CalleeCliquePtr),
 	call_site_dynamic_context(Deep, CSDPtr, FileName, LineNumber),
-	Context = string__format("%s:%d", [s(FileName), i(LineNumber)]),
+	Context = string__format("%s:%d", [s(escape_html_string(FileName)),
+		i(LineNumber)]),
 	HTML = call_to_html(Pref, Deep, CallSiteDisplay, Context,
 		CallerPDPtr, CalleePDPtr,
 		MaybeCallerCliquePtr, CalleeCliquePtr),
-	ProcName = proc_dynamic_name(Deep, CalleePDPtr),
+	ProcName = escape_html_string(proc_dynamic_name(Deep, CalleePDPtr)),
 	LineGroup = line_group(FileName, LineNumber, ProcName,
 		CallSiteOwn, CallSiteDesc, HTML, unit).

@@ -1354,7 +1364,7 @@
 	ChosenCliquePtr = clique_ptr(ChosenCliqueNum),
 	WrappedProcName = string__format("<A HREF=""%s"">%s</A>",
 		[s(deep_cmd_pref_to_url(Pref, Deep, clique(ChosenCliqueNum))),
-		s(ProcName)]),
+		s(escape_html_string(ProcName))]),
 	(
 		CallSiteDisplay ^ display_wrap = always,
 		UsedProcName0 = WrappedProcName
@@ -1365,7 +1375,7 @@
 			( CallerCliquePtr \= CalleeCliquePtr ->
 				UsedProcName0 = WrappedProcName
 			;
-				UsedProcName0 = ProcName
+				UsedProcName0 = escape_html_string(ProcName)
 			)
 		;
 			MaybeCallerCliquePtr = no,
@@ -1374,12 +1384,12 @@
 				UsedProcName0 = WrappedProcName
 			;
 				Assume = assume_within_clique,
-				UsedProcName0 = ProcName
+				UsedProcName0 = escape_html_string(ProcName)
 			)
 		)
 	;
 		CallSiteDisplay ^ display_wrap = never,
-		UsedProcName0 = ProcName
+		UsedProcName0 = escape_html_string(ProcName)
 	),
 	(
 		UsedProcName0 = WrappedProcName,
@@ -1387,7 +1397,7 @@
 	->
 		UsedProcName = UsedProcName0
 	;
-		UsedProcName = ProcName
+		UsedProcName = escape_html_string(ProcName)
 	),
 	HTML =
 		string__format("<TD CLASS=id>%s</TD>\n", [s(Context)]) ++
@@ -1621,7 +1631,8 @@
 		Parent) = HTML :-
 	Cmd = proc(PSI),
 	WrappedProcName = string__format("<A HREF=""%s"">%s</A>",
-		[s(deep_cmd_pref_to_url(Pref, Deep, Cmd)), s(ProcName)]),
+		[s(deep_cmd_pref_to_url(Pref, Deep, Cmd)),
+			s(escape_html_string(ProcName))]),
 	( NumLines = 0 ->
 		HTML = string__format("<H3>There are no %ss calling %s</H3>",
 			[s(Parent), s(WrappedProcName)])
@@ -1899,7 +1910,7 @@
 	Pref = Pref0 ^ pref_criteria := Criteria,
 	URL = deep_cmd_pref_to_url(Pref, Deep, Cmd),
 	Str = string__format("<A HREF=%s>%s</A>",
-		[s(URL), s(Str0)]).
+		[s(URL), s(escape_html_string(Str0))]).

 :- func wrap_proc_links(proc_static_ptr, preferences, deep, string,
 	order_criteria) = string.
@@ -1910,7 +1921,7 @@
 	Pref = Pref0 ^ pref_criteria := Criteria,
 	URL = deep_cmd_pref_to_url(Pref, Deep, Cmd),
 	Str = string__format("<A HREF=%s>%s</A>",
-		[s(URL), s(Str0)]).
+		[s(URL), s(escape_html_string(Str0))]).

 :- func wrap_proc_callers_links(proc_static_ptr, caller_groups, int,
 	preferences, deep, string, order_criteria) = string.
@@ -1922,7 +1933,7 @@
 	Pref = Pref0 ^ pref_criteria := Criteria,
 	URL = deep_cmd_pref_to_url(Pref, Deep, Cmd),
 	Str = string__format("<A HREF=%s>%s</A>",
-		[s(URL), s(Str0)]).
+		[s(URL), s(escape_html_string(Str0))]).

 :- func wrap_module_links(string, preferences, deep, string,
 	order_criteria) = string.
@@ -1932,7 +1943,7 @@
 	Pref = Pref0 ^ pref_criteria := Criteria,
 	URL = deep_cmd_pref_to_url(Pref, Deep, Cmd),
 	Str = string__format("<A HREF=%s>%s</A>",
-		[s(URL), s(Str0)]).
+		[s(URL), s(escape_html_string(Str0))]).

 :- func wrap_modules_links(preferences, deep, string, order_criteria) = string.

@@ -1941,7 +1952,7 @@
 	Pref = Pref0 ^ pref_criteria := Criteria,
 	URL = deep_cmd_pref_to_url(Pref, Deep, Cmd),
 	Str = string__format("<A HREF=%s>%s</A>",
-		[s(URL), s(Str0)]).
+		[s(URL), s(escape_html_string(Str0))]).

 :- func wrap_top_procs_links(display_limit, preferences, deep, string,
 	order_criteria) = string.
@@ -1958,5 +1969,5 @@
 		Cmd = top_procs(Limit, CostKind, InclDesc, Scope),
 		URL = deep_cmd_pref_to_url(Pref, Deep, Cmd),
 		Str = string__format("<A HREF=%s>%s</A>",
-			[s(URL), s(Str0)])
+			[s(URL), s(escape_html_string(Str0))])
 	).

--------------------------------------------------------------------------
mercury-reviews mailing list
post:  mercury-reviews at cs.mu.oz.au
administrative address: owner-mercury-reviews at cs.mu.oz.au
unsubscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: unsubscribe
subscribe:   Address: mercury-reviews-request at cs.mu.oz.au Message: subscribe
--------------------------------------------------------------------------



More information about the reviews mailing list