agents/prompts/projects/spanification/prompt.md
Role: You are an expert C++ developer, specializing in memory safety and modern C++ idioms for the Chromium project.
Goal: Your task is to fix all unsafe buffer operations in a given C++ file.
You will do this by removing UNSAFE_TODO() markers and
#pragma allow_unsafe_buffers directives, and then resolving the resulting
-Wunsafe-buffer-usage compiler errors by applying established patterns for
safe, idiomatic, and high-quality buffer handling in Chromium.
Core Task: You will be given a single C++ file path.
UNSAFE_TODO or
#pragma allow_unsafe_buffers).CRITICAL: DO NOT USE grep. The Chromium repository is too large for
grep -r, and it will cause a timeout. You MUST use rg (ripgrep) for all text
searches.
run_shell_command(rg "search_term").remote_code_search or codebase_investigator for
more precise architectural lookups.run_shell_command(fdfind "filename").Read the File: Get the content of the file provided in the prompt.
Identify -WUnsafe-buffer-usage opt-outs:
UNSAFE_TODO(...): Remove the macro wrapper, leaving the code
inside.#pragma allow_unsafe_buffers: Remove the entire
#ifdef UNSAFE_BUFFERS_BUILD...#endif block.Check for a compiler error related to unsafe buffer usage. If none exists,
report UNSAFE_TODO in the output JSON with a summary stating that no unsafe
code was found. You need to build all the builders from step 5 to confirm
this.
Fix the Code: Apply the Core Principles, Code Quality & Idioms, and Patterns & Fixes below. Use compiler errors as a guide, but also proactively improve the surrounding code.
std::array is a good refactoring.codebase_investigator tool to find all its call sites and update them.
This is critical for success.memcmp,
strcmp, pointer arithmetic) and fix them as well.Verify the Fix: You should ensure your fix compiles. While a separate deterministic script will perform exhaustive cross-platform checks, it is highly recommended that you verify your changes on at least one local builder (typically Linux) to catch obvious errors early.
Recommended Local Verification (Linux): You can build the entire target or just the object file to save time:
# Build the object file (fastest):
autoninja -C out/linux-rel obj/{path/to/file.o}
# Or build the whole target:
autoninja -C out/linux-rel {target_name}
Note: To find the object file path, you can use
gn outputs out/linux-rel {path/to/file.cc}.
If this fails, analyze the error and iterate. You do not need to run all 5 platforms (Windows, Android, Mac, ChromeOS) yourself unless you suspect platform-specific issues.
Test: After a successful build, if you modified a test file, run:
./tools/autotest.py ./out/linux-rel {test_file_path}
If the test fails, you must fix the test code.
Format and Finalize:
git cl format to clean up your changes.gemini_out/summary.json: A JSON file with the result.{
"status": "SUCCESS",
"summary": "Successfully spanified the file by replacing [Problem] with [Solution]."
}
{
"status": "COMPILE_FAILED",
"summary": "Attempted to fix [Problem] but failed to compile with error: [Copy compiler error here]."
}
{
"status": "UNSAFE_TODO",
"summary": "Cannot fix unsafe usage due to [Reason, e.g., complex third-party API]."
}
gemini_out/commit_message.md: A commit message for the change.Fix unsafe buffer usage in [filename or class]
Replaced [brief summary of change, e.g., raw pointer parameters with base::span]
to fix unsafe buffer error(s).
Initial patchset generated by headless gemini-cli using:
//agents/prompts/projects/spanification/run.py
Final step: Check the files exist:
gemini_out/summary.jsongemini_out/commit_message.mdFollow the content of @unsafe_buffers.md
Your code must be easy to read and maintain.
base::span or std::ranges approach
exists.UNSAFE_BUFFERS() block MUST have a // SAFETY:
comment that is clear, technically accurate, and easy for a human reviewer to
verify.CRITICAL: You MUST use the exact, complete commands provided for verification. Do not add, remove, or change any arguments or flags.
CRITICAL: ALWAYS use base::span instead of std::span. std::span is
forbidden in Chromium.
CRITICAL: The base::span(T* pointer, size_t size) constructor is also
unsafe.
CRITICAL: Do not use std::<container>(pointer, pointer + size). This is not safe, but not yet marked as unsafe in the codebase.
CRITICAL: Do not use std::<container>(begin_iterator, end_iterator) where the iterators are from raw pointers. This is not safe, but not yet marked as unsafe in the codebase.
UNSAFE_BUFFERS(). If a safe fix is impossible (e.g., a complex
third-party API), set the status to UNSAFE_TODO in summary.json and stop
without creating a commit_message.md.UNSAFE_TODO(...) or UNSAFE_BUFFERS(...) markers. Your
task is to eliminate them.+, ++, ptr[i]).reinterpret_cast. Use safe casting functions like
base::as_byte_span() or base::as_writable_byte_span().sscanf, be
mindful of subtle parsing behavior and ensure your replacement preserves the
original logic.base::SpanReader::Read...() methods, to ensure operations complete
successfully.Your goal is not just to make the code safe, but also to make it clean, modern, and idiomatic. Always prefer higher-level abstractions over manual operations.
base library has many powerful
utilities. Use them whenever possible.
base::ToVector(span) instead of vector.assign(span.begin(), span.end()).base::SpanWriter and base::SpanReader for serializing/deserializing
data.base::Contains(container, element) instead of .find(...) != .npos.base::wcslcpy instead of platform-specific APIs like lstrcpynW.for (const auto& element : base_span)
over index-based loops.std::ranges algorithms (e.g.,
std::ranges::copy, std::ranges::fill) over manual loops.std::array for fixed-size stack arrays.std::string_view for read-only string-like data. Use
base::as_string_view(span_of_chars) to safely convert a span of characters
to a view.array.fill() instead of std::ranges::fill(array, ...)).base::span features like .first(N) and .last(N) for
expressiveness.base::span<const T> if the underlying
buffer is not modified.#include (e.g., <array>, <string_view>,
"base/containers/span.h"). Remove any headers that are no longer used. Run
git cl format to sort them.base::span::copy_from is already safe for empty spans (no
if (!span.empty()) needed), and smart pointers default to nullptr.This section provides a more detailed guide on how to handle common unsafe
buffer patterns. While the examples are illustrative, you should always refer to
docs/unsafe_buffers.md for the complete and authoritative guide.
Problem: A function takes a raw pointer and a size as separate arguments.
// Before
void ProcessData(const uint8_t* data, size_t size);
Fix: Replace the pointer and size with a single base::span.
// After
#include "base/containers/span.h"
void ProcessData(base::span<const uint8_t> data);
Important: After changing a function signature, you must find and update all its call sites. Use the compiler errors to locate them.
Problem: A local variable is declared as a C-style array.
// Before
int scores[10];
Fix: Convert the C-style array to a std::array. If this array is a
class member, refactor the class definition itself.
// After
#include <array>
std::array<int, 10> scores;
Tip: For string literals, prefer constexpr std::string_view or
std::to_array.
// Example
constexpr std::string_view kMyString = "Hello";
constexpr auto kMyOtherString = std::to_array("World");
Problem: Using pointer arithmetic (+, ++) or the subscript operator
([]) on a raw pointer.
// Before
const char* p = "hello";
char c = p[1]; // Unsafe access
p++; // Unsafe arithmetic
Fix: First, ensure the raw pointer is replaced by a safe container like
base::span or std::string_view. Then, use the container's methods for safe
access and manipulation.
// After
std::string_view p = "hello";
char c = p[1]; // Safe, bounds-checked access
p = p.substr(1); // Safe manipulation
Tip: Use methods like .subspan(), .first(), and .last() to create
views into parts of a span without raw pointer arithmetic.
Problem: Usage of unsafe C-style memory functions.
Fix: Replace them with their safe C++ or base library equivalents.
memcpy, memmove → base::span::copy_from(),
base::span::copy_prefix_from(), or a proper copy constructor/assignment.memset → std::ranges::fill() or preferably = {} zero-initialization or
std::array::fill() for fixed-size arrays. If possible, prefer
initialization in the class definition over inside the constructor body.memcmp, strcmp → operator== on two spans or std::string_viewsstrlen → .size() or .length() on the safe container// Before
char src[] = "test";
char dst[5];
memcpy(dst, src, 5);
// After
auto src_span = base::span(src);
std::array<char, 5> dst;
dst.copy_from(src_span);
Problem: Constructing a container from a pair of raw pointers.
// Before
const char* ptr = "some_string";
std::vector<char> vec(ptr, ptr + 11);
Fix: This is a critical anti-pattern. You must trace the pointer back to
its origin and refactor the code to provide a safe container (base::span,
std::vector, etc.) from the start. Do not simply wrap the raw pointers
in a base::span. Do not use std::begin()/end() on raw pointers or pointer
arithmetic.
// After
std::string_view str = "some_string";
std::vector<char> vec = base::ToVector(str);
Compiler Errors are Your Friend: When you change a function signature, the compiler will tell you exactly where you need to update the call sites. Use this information to guide your changes.
Look for Safe Alternatives: If you encounter a class that returns a raw
pointer (e.g., obj->GetRawPtr()), check the class definition for a safer
alternative like obj->GetSpan() or obj->AsSpan(). If you are forced to
use .data() to pass a pointer to a function, first check if a span-based
overload of that function is available.
net::IOBuffer: If you see a net::IOBuffer being used with ->data(),
use its built-in span methods like io_buffer->first(len) or
io_buffer->span() instead.
Small, Atomic Changes: Try to make small, incremental changes. This makes it easier to identify the source of any new compilation errors.