From 429c9b895fabac39fcebd9df40f06c97c86e17f3 Mon Sep 17 00:00:00 2001 From: Dongge Liu Date: Mon, 17 Mar 2025 13:47:58 +1100 Subject: [PATCH 1/4] Create temp --- temp | 1 + 1 file changed, 1 insertion(+) create mode 100644 temp diff --git a/temp b/temp new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/temp @@ -0,0 +1 @@ + From 503321c6950529c25769e35e9d1656c33d7fb911 Mon Sep 17 00:00:00 2001 From: Kartikay Singh pundir <130781246+Kartikayy007@users.noreply.github.com> Date: Tue, 18 Mar 2025 13:07:59 +0530 Subject: [PATCH 2/4] Add syntax highlighting to code blocks in reports and fix and the Outdated section name (#881) This PR enhances the report UI by adding syntax highlighting to both fuzz target code and build script code. and the Outdated section name Reference: GitHub PR #867 Comment CC: @DonggeLiu Features Fuzz Target Code: Applies language-specific highlighting based on the benchmark YAML language field. Build Scripts: Uses Bash syntax highlighting for all build scripts, also added line numbers for build script code. Clean Display: Properly separates build script code from fixer prompts- Fixed Labeling: Corrects misleading "Fixer prompt" section that was previously showing build scripts. Implementation Details Added highlight.js library to base.html. Enhanced Benchmark class with a language field and extraction from YAML files. Updated Target class to separate build script code from fixer prompts. Modified templates to apply appropriate syntax highlighting and correct section labeling. added line numbers to build script code (used the same approach as for the fuzz target code) Bug Fixes Fixes issue where build scripts were incorrectly stored in the fixer_prompt field. Fixes misleading UI section headings by properly labelling build scripts as "Build Script". --- report/common.py | 23 +++++++++++++++++++++-- report/templates/base.html | 23 +++++++++++++++++++++++ report/templates/sample.html | 15 ++++++++++++--- report/web.py | 16 +++++++++++++++- 4 files changed, 71 insertions(+), 6 deletions(-) diff --git a/report/common.py b/report/common.py index 4f445f1d7b..187170df79 100644 --- a/report/common.py +++ b/report/common.py @@ -73,6 +73,7 @@ class Benchmark: signature: str = '' project: str = '' function: str = '' + language: str = '' @dataclasses.dataclass @@ -129,6 +130,7 @@ def run_log(self) -> str: class Target: code: str fixer_prompt: Optional[str] = None + build_script_code: Optional[str] = None @dataclasses.dataclass @@ -411,7 +413,7 @@ def _get_targets_agent(self, benchmark: str, trial: str) -> Target: build_script_code = f.read() # TODO(dongge): Properly show build script code in reports. - return Target(code=fuzz_target_code, fixer_prompt=build_script_code) + return Target(code=fuzz_target_code, fixer_prompt=None, build_script_code=build_script_code) def get_samples(self, results: list[evaluator.Result], targets: list[str]) -> list[Sample]: @@ -638,7 +640,8 @@ def _create_benchmark( function = benchmark_id.split('-')[-1] signature = self._find_benchmark_signature(project, function) or benchmark_id - return Benchmark(benchmark_id, status, result, signature, project, function) + language = self._find_benchmark_language(project, function) + return Benchmark(benchmark_id, status, result, signature, project, function, language) def _find_benchmark_signature(self, project: str, target_function: str) -> str: @@ -670,6 +673,22 @@ def _find_benchmark_signature(self, project: str, return matched_prefix_signature + def _find_benchmark_language(self, project: str, target_function: str) -> str: + """Finds the programming language of the benchmark.""" + if not self._benchmark_dir: + return '' + + project_path = os.path.join(self._benchmark_dir, f'{project}.yaml') + if not FileSystem(project_path).isfile(): + return '' + + try: + with FileSystem(project_path).open() as f: + benchmark_data = yaml.safe_load(f) + return benchmark_data.get('language', '') + except Exception as e: + logging.error('Failed to read benchmark file %s: %s', project_path, e) + return '' def _parse_log_parts(log: str) -> list[LogPart]: """Parse log into parts.""" diff --git a/report/templates/base.html b/report/templates/base.html index 706935d027..0a0820416b 100644 --- a/report/templates/base.html +++ b/report/templates/base.html @@ -100,7 +100,30 @@ line-height: 1.5; white-space: pre; } + +.hljs { + background: transparent; + padding: 0; +} + + + + + + + + + + + + LLM: {{ model }} {% block content %}{% endblock %} diff --git a/report/templates/sample.html b/report/templates/sample.html index c09a26c4af..fb74e61d89 100644 --- a/report/templates/sample.html +++ b/report/templates/sample.html @@ -16,7 +16,7 @@ #}{% extends 'base.html' %} {% block content %} -

{{ benchmark }} / {{ sample.id }}

+

{{ benchmark_id }} / {{ sample.id }}

Bug: {{ sample.result.crashes and not sample.result.is_semantic_error }}
Crash reason: {{ sample.result.semantic_error }} @@ -52,10 +52,19 @@

Final code

{% else %}

Code #{{ loop.index - 1}}

{% endif %} +
-
{% for line in target.code.splitlines() %}{{ loop.index }}{% endfor %}
-
{% for line in target.code.splitlines() %}{{ line }}{% endfor %}
+
{% for line in target.code|remove_trailing_empty_lines|splitlines %}{{ loop.index }}{% endfor %}
+
{{ target.code|remove_trailing_empty_lines }}
+ +{% if target.build_script_code %} +

Build Script

+
+
{% for line in target.build_script_code|remove_trailing_empty_lines|splitlines %}{{ loop.index }}{% endfor %}
+
{{ target.build_script_code|remove_trailing_empty_lines }}
+
+{% endif %} {% endfor %}

Logs

diff --git a/report/web.py b/report/web.py index 19de3dbc20..08c6b69ba8 100644 --- a/report/web.py +++ b/report/web.py @@ -65,6 +65,18 @@ def _cov_report_link(link: str): return link_path + 'index.html' return link_path + 'report.html' + @staticmethod + def _remove_trailing_empty_lines(code: str) -> str: + """Remove trailing empty lines from code.""" + if not code: + return code + + lines = code.splitlines() + while lines and not lines[-1].strip(): + lines.pop() + + return '\n'.join(lines) + def __init__(self, template_globals: Optional[Dict[str, Any]] = None): self._env = jinja2.Environment( loader=jinja2.FileSystemLoader("report/templates"), @@ -73,6 +85,7 @@ def __init__(self, template_globals: Optional[Dict[str, Any]] = None): self._env.filters['urlencode_filter'] = self._urlencode_filter self._env.filters['percent'] = self._percent self._env.filters['cov_report_link'] = self._cov_report_link + self._env.filters['remove_trailing_empty_lines'] = self._remove_trailing_empty_lines if template_globals: for key, val in template_globals.items(): @@ -235,7 +248,8 @@ def _write_benchmark_sample(self, benchmark: Benchmark, sample: Sample, try: rendered = self._jinja.render( 'sample.html', - benchmark=benchmark.id, + benchmark=benchmark, + benchmark_id=benchmark.id, sample=sample, logs=self._results.get_logs(benchmark.id, sample.id), run_logs=self._results.get_run_logs(benchmark.id, sample.id), From 1673500eaa4787d2e8510fcb7f9c99070fb404cf Mon Sep 17 00:00:00 2001 From: Dongge Liu Date: Thu, 20 Mar 2025 16:02:20 +1100 Subject: [PATCH 3/4] Delete temp --- temp | 1 - 1 file changed, 1 deletion(-) delete mode 100644 temp diff --git a/temp b/temp deleted file mode 100644 index 8b13789179..0000000000 --- a/temp +++ /dev/null @@ -1 +0,0 @@ - From 6ce6ac9a7963e7863f4ba5eca6b56fd37309e26b Mon Sep 17 00:00:00 2001 From: Kartikay Singh pundir <130781246+Kartikayy007@users.noreply.github.com> Date: Mon, 31 Mar 2025 12:51:38 +0530 Subject: [PATCH 4/4] Fix exp 881 (#926) # Fix Sample Page Rendering Issues ## Problem mentioned in #883 Sample pages were failing to render with these errors: ![image](https://github.com/user-attachments/assets/fe9bf649-a25c-4047-9104-a5eeef7ecc47) The template was using a filter called `splitlines` which wasn't registered in the Jinja2 environment. Additionally, the template also lacking robustness against undefined variables. ## Files Changed for #883 1. `report/web.py` - Added missing filter and improved error handling 2. `report/templates/sample.html` - Added robustness checks ## Changes Made 1. **Added missing filter:** - Implemented `_splitlines` method in `web.py` - Registered it with Jinja2 environment 2. **Improved template robustness:** - Added `is defined` checks for variables that might be missing - Added default values with `|default()` filter - Made `remove_trailing_empty_lines` filter handle edge cases better 3. **Enhanced error handling:** - Added detailed error logging with full traceback - Created fallback error pages when rendering fails - Provided better default values for missing data These improvements should resolve all the sample page rendering issues. --------- Co-authored-by: Dongge Liu --- report/common.py | 12 ++++-- report/templates/sample.html | 10 +++-- report/web.py | 75 ++++++++++++++++++++++++++++-------- 3 files changed, 72 insertions(+), 25 deletions(-) diff --git a/report/common.py b/report/common.py index 187170df79..52f68b0e6e 100644 --- a/report/common.py +++ b/report/common.py @@ -413,7 +413,9 @@ def _get_targets_agent(self, benchmark: str, trial: str) -> Target: build_script_code = f.read() # TODO(dongge): Properly show build script code in reports. - return Target(code=fuzz_target_code, fixer_prompt=None, build_script_code=build_script_code) + return Target(code=fuzz_target_code, + fixer_prompt=None, + build_script_code=build_script_code) def get_samples(self, results: list[evaluator.Result], targets: list[str]) -> list[Sample]: @@ -641,7 +643,8 @@ def _create_benchmark( signature = self._find_benchmark_signature(project, function) or benchmark_id language = self._find_benchmark_language(project, function) - return Benchmark(benchmark_id, status, result, signature, project, function, language) + return Benchmark(benchmark_id, status, result, signature, project, function, + language) def _find_benchmark_signature(self, project: str, target_function: str) -> str: @@ -677,11 +680,11 @@ def _find_benchmark_language(self, project: str, target_function: str) -> str: """Finds the programming language of the benchmark.""" if not self._benchmark_dir: return '' - + project_path = os.path.join(self._benchmark_dir, f'{project}.yaml') if not FileSystem(project_path).isfile(): return '' - + try: with FileSystem(project_path).open() as f: benchmark_data = yaml.safe_load(f) @@ -690,6 +693,7 @@ def _find_benchmark_language(self, project: str, target_function: str) -> str: logging.error('Failed to read benchmark file %s: %s', project_path, e) return '' + def _parse_log_parts(log: str) -> list[LogPart]: """Parse log into parts.""" parts = [] diff --git a/report/templates/sample.html b/report/templates/sample.html index fb74e61d89..965b75e7b9 100644 --- a/report/templates/sample.html +++ b/report/templates/sample.html @@ -17,9 +17,9 @@ {% block content %}

{{ benchmark_id }} / {{ sample.id }}

-Bug: {{ sample.result.crashes and not sample.result.is_semantic_error }} +Bug: {{ sample.result.crashes|default(false) and not sample.result.is_semantic_error|default(false) }}
-Crash reason: {{ sample.result.semantic_error }} +Crash reason: {{ sample.result.semantic_error|default('') }}

@@ -53,12 +53,14 @@

Final code

Code #{{ loop.index - 1}}

{% endif %} +{% if target.code is defined and target.code %}
{% for line in target.code|remove_trailing_empty_lines|splitlines %}{{ loop.index }}{% endfor %}
-
{{ target.code|remove_trailing_empty_lines }}
+
{{ target.code|remove_trailing_empty_lines }}
+{% endif %} -{% if target.build_script_code %} +{% if target.build_script_code is defined and target.build_script_code %}

Build Script

{% for line in target.build_script_code|remove_trailing_empty_lines|splitlines %}{{ loop.index }}{% endfor %}
diff --git a/report/web.py b/report/web.py index 08c6b69ba8..05784fa3a0 100644 --- a/report/web.py +++ b/report/web.py @@ -21,6 +21,7 @@ import shutil import threading import time +import traceback import urllib.parse from functools import partial from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer @@ -69,13 +70,28 @@ def _cov_report_link(link: str): def _remove_trailing_empty_lines(code: str) -> str: """Remove trailing empty lines from code.""" if not code: - return code - - lines = code.splitlines() - while lines and not lines[-1].strip(): - lines.pop() - - return '\n'.join(lines) + return "" + + try: + lines = code.splitlines() + while lines and not lines[-1].strip(): + lines.pop() + + return '\n'.join(lines) + except Exception as e: + logging.warning("Error in remove_trailing_empty_lines filter: %s", e) + return code # Return original code on error + + @staticmethod + def _splitlines(text: str) -> list: + """Split text into lines, similar to Python's splitlines().""" + if not text: + return [] + try: + return text.splitlines() + except Exception as e: + logging.warning("Error in splitlines filter: %s", e) + return [text] # Return original as single line on error def __init__(self, template_globals: Optional[Dict[str, Any]] = None): self._env = jinja2.Environment( @@ -85,7 +101,9 @@ def __init__(self, template_globals: Optional[Dict[str, Any]] = None): self._env.filters['urlencode_filter'] = self._urlencode_filter self._env.filters['percent'] = self._percent self._env.filters['cov_report_link'] = self._cov_report_link - self._env.filters['remove_trailing_empty_lines'] = self._remove_trailing_empty_lines + self._env.filters[ + 'remove_trailing_empty_lines'] = self._remove_trailing_empty_lines + self._env.filters['splitlines'] = self._splitlines if template_globals: for key, val in template_globals.items(): @@ -246,19 +264,42 @@ def _write_benchmark_sample(self, benchmark: Benchmark, sample: Sample, sample_targets: List[Target]): """Generate the sample page and write to filesystem.""" try: - rendered = self._jinja.render( - 'sample.html', - benchmark=benchmark, - benchmark_id=benchmark.id, - sample=sample, - logs=self._results.get_logs(benchmark.id, sample.id), - run_logs=self._results.get_run_logs(benchmark.id, sample.id), - triage=self._results.get_triage(benchmark.id, sample.id), - targets=sample_targets) + # Ensure all required variables are available + logs = self._results.get_logs(benchmark.id, sample.id) or [] + run_logs = self._results.get_run_logs(benchmark.id, sample.id) or "" + triage = self._results.get_triage(benchmark.id, sample.id) or { + "result": "", + "triager_prompt": "" + } + + rendered = self._jinja.render('sample.html', + benchmark=benchmark, + benchmark_id=benchmark.id, + sample=sample, + logs=logs, + run_logs=run_logs, + triage=triage, + targets=sample_targets) self._write(f'sample/{benchmark.id}/{sample.id}.html', rendered) except Exception as e: logging.error('Failed to write sample/%s/%s:\n%s', benchmark.id, sample.id, e) + logging.error('Exception details: %s', traceback.format_exc()) + # Create a simple error page so users see something + try: + error_html = f""" + + Error rendering {benchmark.id}/{sample.id} + +

Error rendering sample page

+

An error occurred while rendering this page. Please check the logs for details.

+
{str(e)}
+ + + """ + self._write(f'sample/{benchmark.id}/{sample.id}.html', error_html) + except Exception: + pass # Ignore errors in error handling def generate_report(args: argparse.Namespace) -> None: