Skip to content

Error: ADG build from program failed on lcms #39

@hgarrereyn

Description

@hgarrereyn

Ran into this error at the end of fuzzing (on lcms); I believe its caused by a typedef in the generated harness.

Error:

Caused by:
    Visit VarDecl, but visited Node { id: Id(0x55555667db08), kind: TypedefDecl(TypedefDecl { loc: SourceLocation { spelling_loc: Some(BareSourceLocation { offset: 3530, file: "/root/promptfuzz/output/lcms/succ_seeds/id_000284.cc", line: 98, presumed_file: None, presumed_line: None, col: 32, tok_len: 11, included_from: None, is_macro_arg_expansion: false }), expansion_loc: Some(BareSourceLocation { offset: 3530, file: "/root/promptfuzz/output/lcms/succ_seeds/id_000284.cc", line: 98, presumed_file: None, presumed_line: None, col: 32, tok_len: 11, included_from: None, is_macro_arg_expansion: false }) }, range: SourceRange { begin: SourceLocation { spelling_loc: Some(BareSourceLocation { offset: 3503, file: "/root/promptfuzz/output/lcms/succ_seeds/id_000284.cc", line: 98, presumed_file: None, presumed_line: None, col: 5, tok_len: 7, included_from: None, is_macro_arg_expansion: false }), expansion_loc: Some(BareSourceLocation { offset: 3503, file: "/root/promptfuzz/output/lcms/succ_seeds/id_000284.cc", line: 98, presumed_file: None, presumed_line: None, col: 5, tok_len: 7, included_from: None, is_macro_arg_expansion: false }) }, end: SourceLocation { spelling_loc: Some(BareSourceLocation { offset: 3633, file: "/root/promptfuzz/output/lcms/succ_seeds/id_000284.cc", line: 98, presumed_file: None, presumed_line: None, col: 135, tok_len: 1, included_from: None, is_macro_arg_expansion: false }), expansion_loc: Some(BareSourceLocation { offset: 3633, file: "/root/promptfuzz/output/lcms/succ_seeds/id_000284.cc", line: 98, presumed_file: None, presumed_line: None, col: 135, tok_len: 1, included_from: None, is_macro_arg_expansion: false }) } }, is_implicit: false, is_referenced: false, previous_decl: None, name: "CIE2000Func", type: Type { qual_type: "cmsFloat64Number (*)(const cmsCIELab *, const cmsCIELab *, cmsFloat64Number, cmsFloat64Number, cmsFloat64Number)", desugared_qual_type: None, type_alias_decl_id: None } }), inner: [Node { id: Id(0x55555667da80), kind: PointerType(PointerType { type: Type { qual_type: "cmsFloat64Number (*)(const cmsCIELab *, const cmsCIELab *, cmsFloat64Number, cmsFloat64Number, cmsFloat64Number)", desugared_qual_type: None, type_alias_decl_id: None } }), inner: [Node { id: Id(0x55555667da20), kind: Other, inner: [Node { id: Id(0x55555578c110), kind: Other, inner: [Node { id: Id(0x55555577fb10), kind: ElaboratedType(ElaboratedType { type: Type { qual_type: "cmsFloat64Number", desugared_qual_type: None, type_alias_decl_id: None }, owned_tag_decl: None }), inner: [Node { id: Id(0x55555577fae0), kind: Other, inner: [Node { id: Id(0x555555641d70), kind: Other, inner: [] }] }] }, Node { id: Id(0x555555789ac0), kind: PointerType(PointerType { type: Type { qual_type: "const cmsCIELab *", desugared_qual_type: None, type_alias_decl_id: None } }), inner: [Node { id: Id(0x555555789671), kind: QualType(QualType { type: Type { qual_type: "const cmsCIELab", desugared_qual_type: None, type_alias_decl_id: Some(Id(0x555555780318)) }, qualifiers: "const" }), inner: [Node { id: Id(0x555555789670), kind: ElaboratedType(ElaboratedType { type: Type { qual_type: "cmsCIELab", desugared_qual_type: None, type_alias_decl_id: None }, owned_tag_decl: None }), inner: [Node { id: Id(0x555555789640), kind: Other, inner: [Node { id: Id(0x5555557802c0), kind: ElaboratedType(ElaboratedType { type: Type { qual_type: "struct cmsCIELab", desugared_qual_type: None, type_alias_decl_id: None }, owned_tag_decl: Some(Decl { id: Id(0x555555780068), kind: CXXRecordDecl, name: Some(""), type: None }) }), inner: [Node { id: Id(0x555555780100), kind: RecordType(RecordType { type: Type { qual_type: "cmsCIELab", desugared_qual_type: None, type_alias_decl_id: None }, decl: Decl { id: Id(0x555555780068), kind: CXXRecordDecl, name: Some(""), type: None } }), inner: [] }] }] }] }] }] }, Node { id: Id(0x555555789ac0), kind: PointerType(PointerType { type: Type { qual_type: "const cmsCIELab *", desugared_qual_type: None, type_alias_decl_id: None } }), inner: [Node { id: Id(0x555555789671), kind: QualType(QualType { type: Type { qual_type: "const cmsCIELab", desugared_qual_type: None, type_alias_decl_id: Some(Id(0x555555780318)) }, qualifiers: "const" }), inner: [Node { id: Id(0x555555789670), kind: ElaboratedType(ElaboratedType { type: Type { qual_type: "cmsCIELab", desugared_qual_type: None, type_alias_decl_id: None }, owned_tag_decl: None }), inner: [Node { id: Id(0x555555789640), kind: Other, inner: [Node { id: Id(0x5555557802c0), kind: ElaboratedType(ElaboratedType { type: Type { qual_type: "struct cmsCIELab", desugared_qual_type: None, type_alias_decl_id: None }, owned_tag_decl: Some(Decl { id: Id(0x555555780068), kind: CXXRecordDecl, name: Some(""), type: None }) }), inner: [Node { id: Id(0x555555780100), kind: RecordType(RecordType { type: Type { qual_type: "cmsCIELab", desugared_qual_type: None, type_alias_decl_id: None }, decl: Decl { id: Id(0x555555780068), kind: CXXRecordDecl, name: Some(""), type: None } }), inner: [] }] }] }] }] }] }, Node { id: Id(0x55555577fb10), kind: ElaboratedType(ElaboratedType { type: Type { qual_type: "cmsFloat64Number", desugared_qual_type: None, type_alias_decl_id: None }, owned_tag_decl: None }), inner: [Node { id: Id(0x55555577fae0), kind: Other, inner: [Node { id: Id(0x555555641d70), kind: Other, inner: [] }] }] }, Node { id: Id(0x55555577fb10), kind: ElaboratedType(ElaboratedType { type: Type { qual_type: "cmsFloat64Number", desugared_qual_type: None, type_alias_decl_id: None }, owned_tag_decl: None }), inner: [Node { id: Id(0x55555577fae0), kind: Other, inner: [Node { id: Id(0x555555641d70), kind: Other, inner: [] }] }] }, Node { id: Id(0x55555577fb10), kind: ElaboratedType(ElaboratedType { type: Type { qual_type: "cmsFloat64Number", desugared_qual_type: None, type_alias_decl_id: None }, owned_tag_decl: None }), inner: [Node { id: Id(0x55555577fae0), kind: Other, inner: [Node { id: Id(0x555555641d70), kind: Other, inner: [] }] }] }] }] }] }] }

Location:
    src/analysis/dfa.rs:194:9

id_000284.cc:

#include <lcms2.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <vector>
#include <fstream>
#include <iostream>
#include <sstream>
//<ID> 284
//<Prompt> []
/*<Combination>: [
*/
//<score> 0, nr_unique_branch: 0
//<Quality> {"density":0,"unique_branches":{},"library_calls":[],"critical_calls":[],"visited":0}
/*Certainly! Let’s devise an event using those APIs and your byte-stream input, then implement the `LLVMFuzzerTestOneInput` for you.

---

### **Step 1: Event Description**

Given a byte-stream of lcms "output data" (which could be an IT8 text table, or encoded color patches, etc.), we can:

1. **Use a Plugin** (cmsPluginTHR) to optionally extend/modify lcms behavior.
2. **Create an sRGB profile** (cmsCreate_sRGBProfile).
3. **Create a custom RGB profile** with decoded white point, primaries, and tone curves (cmsCreateRGBProfile).
4. **Open the input as an IT8 table** using the IT8 parser (simulated by using a handle: see related APIs such as cmsIT8LoadFromFile, but here, we use the patch querying function).
5. **Attempt to read a patch from the IT8 handle by name** (cmsIT8GetPatchByName).
6. **Build two Lab color values from input, calculate their difference using CIE2000DeltaE** (cmsCIE2000DeltaE).

---

### **Step 2: Implementation Plan**

- Use the input as both profile creation parameter and plugin data.
- Use part of input as a "patch name" when querying IT8.
- Use part of input as Lab values.
- **Resource cleanup:** Profiles, IT8 handle, tone curves.

---

### **Step 3: C++ Fuzzer Implementation**

*/


// Helper to extract floating point value from data, advances offset safely
static double extract_double(const uint8_t *data, size_t size, size_t &offset) {
    if (offset + sizeof(double) > size) return 0.0;
    double val;
    memcpy(&val, data + offset, sizeof(double));
    offset += sizeof(double);
    return val;
}

// Helper to extract null-terminated patch name
static void extract_patch_name(const uint8_t *data, size_t size, size_t &offset, char *out, size_t max_len) {
    size_t remain = size > offset ? size - offset : 0;
    size_t to_copy = remain < max_len-1 ? remain : max_len-1;
    memcpy(out, data + offset, to_copy);
    out[to_copy] = '\0';
    offset += to_copy;
}

// Fuzz driver
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
    if (size < 128) return 0; // Require some minimum input
    
    size_t offset = 0;

    // 1. Use part of input as plugin data
    size_t plugin_len = size > 32 ? 32 : size; // up to 32 bytes
    void *plugin_data = malloc(plugin_len);
    if (!plugin_data) return 0;
    memcpy(plugin_data, data, plugin_len);
    cmsContext ctx = nullptr;
    cmsPluginTHR(ctx, plugin_data);

    offset += plugin_len;

    // 2. Create an sRGB profile from the library
    cmsHPROFILE hSRGB = cmsCreate_sRGBProfile();

    // 3. Prepare Lab values from fuzzer input (6 doubles needed)
    cmsCIELab lab1, lab2;
    lab1.L = extract_double(data, size, offset);
    lab1.a = extract_double(data, size, offset);
    lab1.b = extract_double(data, size, offset);
    lab2.L = extract_double(data, size, offset);
    lab2.a = extract_double(data, size, offset);
    lab2.b = extract_double(data, size, offset);

    // 4. Compute DeltaE 2000 using fuzzer-provided coefficients
    double Kl = extract_double(data, size, offset);
    double Kc = extract_double(data, size, offset);
    double Kh = extract_double(data, size, offset);

    cmsFloat64Number delta_e = 0.0;
    typedef cmsFloat64Number (*CIE2000Func)(const cmsCIELab *, const cmsCIELab *, cmsFloat64Number, cmsFloat64Number, cmsFloat64Number);
    // Use dlsym or manual binding if not directly declared in header
    // For this exercise, we simulate as if it's available in lcms2.h as cmsCIE2000DeltaE
#ifdef cmsCIE2000DeltaE
    delta_e = cmsCIE2000DeltaE(&lab1, &lab2, Kl, Kc, Kh);
#endif
    (void)delta_e; // suppress unused warning

    // 5. Create a custom RGB profile
    cmsCIExyY wp;
    wp.x = extract_double(data, size, offset);
    wp.y = extract_double(data, size, offset);
    wp.Y = extract_double(data, size, offset);

    cmsCIExyYTRIPLE primaries;
    primaries.Red.x   = extract_double(data, size, offset);
    primaries.Red.y   = extract_double(data, size, offset);
    primaries.Red.Y   = extract_double(data, size, offset);
    primaries.Green.x = extract_double(data, size, offset);
    primaries.Green.y = extract_double(data, size, offset);
    primaries.Green.Y = extract_double(data, size, offset);
    primaries.Blue.x  = extract_double(data, size, offset);
    primaries.Blue.y  = extract_double(data, size, offset);
    primaries.Blue.Y  = extract_double(data, size, offset);

    // Tone curves: three curves, use a simple parametric segment
    cmsToneCurve* curves[3] = {nullptr, nullptr, nullptr};
    for (int i = 0; i < 3; ++i) {
        cmsFloat32Number values[2];
        values[0] = static_cast<cmsFloat32Number>(extract_double(data, size, offset));
        values[1] = static_cast<cmsFloat32Number>(extract_double(data, size, offset));
        curves[i] = cmsBuildTabulatedToneCurveFloat(ctx, 2, values);
    }
    cmsHPROFILE hRGB = cmsCreateRGBProfile(&wp, &primaries, curves);

    // Release tone curves
    for (int i = 0; i < 3; ++i)
        if (curves[i]) cmsFreeToneCurve(curves[i]);

    // 6. IT8 table handling: treat input data as possible IT8 table
    FILE *in_file = fmemopen((void*)data, size, "rb");
    cmsHANDLE hIT8 = nullptr;
    if (in_file) {
        hIT8 = cmsIT8LoadFromFile(ctx, "input_file");
        // Actually IT8LoadFromFile expects a file name, but for fuzzing, we assume it may pick up the right path from the fmemopen.
    }

    // 7. From input, extract a patch name and query the IT8 handle
    char patch_name[32];
    extract_patch_name(data, size, offset, patch_name, sizeof(patch_name));
    if (hIT8 && patch_name[0] != '\0') {
        cmsIT8GetPatchByName(hIT8, patch_name);
    }

    // Cleanup
    if (hIT8) cmsIT8Free(hIT8); // If available; not in your list, but must be in the IT8 API
    if (in_file) fclose(in_file);
    if (hRGB) cmsCloseProfile(hRGB);
    if (hSRGB) cmsCloseProfile(hSRGB);
    free(plugin_data);

    return 0;
}

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