Skip to content

synthesize_manifest uses subslice offsets to index the full manifest #314

Description

@yu7400ki

Description

When a crate has no concrete license value—for example, when the field is absent or uses license.workspace = truecargo-about synthesizes a license field into a copy of the manifest so diagnostics can point to the detected expression.

Since 0.9.0, the insertion offset is calculated relative to a subslice but used to index the full manifest:

let mut start = 0;
let s = &existing[pkg + 5..];

for l in memchr::memchr_iter(b'\n', s.as_bytes()) {
    let line = &s[start..l];

    if line.trim().is_empty() || line.starts_with('[') {
        existing.insert_str(start, "license = \"");
        let offset = start + 11;
        existing.insert_str(offset, expression.as_ref());
        existing.insert_str(offset + expression.as_ref().len(), "\"\n");
        return (existing, offset);
    }

    start = l + 1;
}

start and l are offsets into s, so the insertion occurs pkg + 5 bytes too early. This can either panic when the index falls inside a UTF-8 character or corrupt an unrelated value and produce diagnostics against a manifest that never existed.

This regression was introduced by #299. Version 0.8.4 is not affected.

Reproduction

On Windows, create a crate with CRLF line endings and this Cargo.toml:

[package]
name = "repro"
version = "0.1.0"
edition = "2021"
description = "日本語の説明"

[dependencies]

Add a detectable MIT LICENSE file, an empty src/lib.rs, any about.hbs, and:

accepted = ["MIT"]

Run:

cargo about generate about.hbs -o out.txt

Observed result:

thread 'main' panicked at src\licenses\resolution.rs:86:26:
assertion failed: self.is_char_boundary(idx)

With LF line endings and no description field, the same bug silently corrupts the manifest, for example:

edition = "2license = "(MIT)"

Expected behavior

The synthesized field should be inserted at the end of the [package] table, and the returned offset should point to the expression for both LF and CRLF manifests.

Suggested fix

Add the subslice base before indexing existing:

let base = pkg + 5;
let s = &existing[base..];
let insert = base + start;
existing.insert_str(insert, "license = \"");
let offset = insert + 11;

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions