canon

package
v0.13.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 21, 2026 License: Apache-2.0 Imports: 6 Imported by: 0

Documentation

Overview

Package canon defines a canonical, engine-independent encoding for the result of evaluating a ClassAd attribute. Both evaluation engines under test (the native Go implementation and the reference C++ libclassad, reached via cgo) encode their results into this format so the differential fuzzer can compare them without being fooled by cosmetic formatting differences (e.g. Go prints reals as "0.5" while libclassad prints "5.000...E-01", and lists as "[1 2 3]" vs "{ 1,2,3 }").

The encoding is a single self-delimiting line. Strings and composite values are length/count prefixed so no escaping is required and parsing is unambiguous:

U                      undefined
E                      error
B0 | B1                boolean
I<int64>;              integer (decimal)
R<%.17g>;              real (round-trippable double)
G<%.17g>;              relative time, seconds
A<%.17g>,<offset>;     absolute time: epoch seconds, tz offset seconds
S<len>,<bytes>         string: byte length then raw bytes
L<count>,<elem>...     list: element count then encoded elements
C<count>,<klen>,<key><val>...  classad: entry count then (keylen,key,value),
                                entries sorted by attribute name

The C++ shim (fuzz/oracle/cgo/shim.cc) emits byte-identical output for the scalar cases, so the common path is a plain string compare. When strings differ, callers re-parse both sides into a Value tree and compare with a float tolerance to suppress last-ULP noise from transcendental functions.

Index

Constants

This section is empty.

Variables

View Source
var DefaultTolerance = FloatTolerance{Rel: 1e-12, Abs: 1e-12}

DefaultTolerance is intentionally tight: we want to catch real arithmetic divergences, only forgiving sub-ULP rounding.

Functions

func Describe

func Describe(v Value) string

Describe renders a value as a short human-readable string for divergence reports (distinct from the wire Encode format, which is for machines).

func Encode

func Encode(v Value) string

Encode serializes v into the canonical line format.

func Equal

func Equal(a, b Value, tol FloatTolerance) bool

Equal reports whether two canonical values are semantically equal under the given float tolerance. Type (Kind) must match exactly: an integer and a real of equal magnitude are NOT equal, because the int-vs-real distinction is a first-class part of ClassAd semantics and a frequent source of divergence.

Types

type Attr

type Attr struct {
	Key string
	Val Value
}

Attr is one attribute of a canonical classad value.

type FloatTolerance

type FloatTolerance struct {
	Rel float64
	Abs float64
}

FloatTolerance controls how reals (and the seconds component of times) are compared. Two engines performing the same IEEE-754 operations usually agree bit-for-bit, but transcendental functions (sqrt, pow, ...) may differ in the last ULP across libm versions. A small relative tolerance suppresses that noise without masking genuine semantic differences.

type Kind

type Kind int

Kind enumerates the canonical value types. The set is the union of what both engines can produce; an engine that cannot represent a kind (e.g. the Go engine historically had no absolute-time value) simply never emits it, which surfaces as a divergence.

const (
	KUndef Kind = iota
	KError
	KBool
	KInt
	KReal
	KReltime
	KAbstime
	KString
	KList
	KClassad
)

func (Kind) String

func (k Kind) String() string

type Value

type Value struct {
	Kind Kind
	B    bool
	I    int64
	R    float64
	Off  int64 // tz offset (seconds) for KAbstime
	S    string
	List []Value
	Map  []Attr // sorted by Key for KClassad
}

Value is the parsed form of a canonical encoding.

func FromGoClassAd

func FromGoClassAd(ad *classad.ClassAd) Value

FromGoClassAd evaluates every top-level attribute of ad (in the ad's own scope) and returns the canonical classad value. This is the entry point used by the differential fuzzer for the Go engine; it mirrors what the C++ shim does in encodeClassAd.

func FromGoValue

func FromGoValue(v classad.Value) Value

FromGoValue converts a value produced by the native Go evaluator into the canonical representation.

Composite values follow a rule applied identically to the C++ side so that any difference is genuine:

  • List elements are encoded in order (the Go evaluator returns them already evaluated).
  • A nested ClassAd value is encoded as its attributes sorted by name, each evaluated within the nested ad's own scope. This is a well-defined, symmetric rule; it does not attempt to resolve references into the parent scope (neither engine does so for a detached sub-ad).

maxDepth guards against pathological self-referential structures.

func Parse

func Parse(s string) (Value, error)

Parse decodes a canonical encoding produced by either engine.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL