Skip to content
zit Artifact [67ef611cb0]
Login

Artifact [67ef611cb0]

Artifact 67ef611cb03dfc87060ce5c5f5dda72bfc6f31f2ba161d94545a582004161a50:


Erratum — draft-fossil-sync-protocol-00 §8.1

Document draft-fossil-sync-protocol-00
Section 8.1 — Clone Protocol Version (server handling of a SEQNO that is not digit-only)
Type Compatibility note (no requirement on a conforming implementation changes)
Status Proposed — operator decision pending
Reported 2026-10-11
Submitter Dan Mestas
Found via go-libfossil's sync conformance suite: fossil 2.28 [52445a27f1] answers clone 3 -1 differently on macOS arm64 and Linux x64 builds

1. Summary

§8.1 assigns error invalid clone sequence number only to a digit-only SEQNO whose value is zero, and says the rule "does not assign that fatal outcome to wrong arity, noninteger VERSION, or a SEQNO that fails digit-only recognition". It says nothing about what such a SEQNO does get. In Fossil 2.28 the answer is undefined: the server reads an uninitialized variable. The same request, clone 3 -1, gets clone_seqno 0 from a macOS arm64 build and error invalid clone sequence number from a Linux x64 build.

The draft's grammar (clone-card = "clone" SP decimal SP decimal LF) and its clone loop (§8.2: SEQNO starts at 1 and is replaced only by a decimal clone_seqno) already keep a conforming client from sending such a card, so no requirement changes. The note records that Fossil gives no stable answer, so that neither tests nor implementations treat either observed reply as the reference behavior.

2. Location

3. The divergence

Fossil 2.28, src/xfer.c:1550-1570, in the clone handler:

int seqno, max;                         /* seqno is not initialized */
...
blob_is_int(&xfer.aToken[2], &seqno);   /* return value ignored */
if( seqno<=0 ){
  xfer_fatal_error("invalid clone sequence number");
  ...
}
...
if( seqno>max ) seqno = 0;
@ clone_seqno %d(seqno)

blob_is_int() (src/blob.c:1057-1071) stores a value only when every byte is an ASCII digit; for -1, abc or 1x it returns 0 and leaves seqno as whatever the stack held. A non-positive leftover gives the fatal error and rollback; a positive one greater than the largest RID gives no cfile and clone_seqno 0; a positive one within range would serve artifacts from an arbitrary RID.

Observed on this machine (fossil 2.28 [52445a27f1], Homebrew, macOS arm64), fossil http with an application/x-fossil-debug request, three runs each:

SEQNO Reply
0 error invalid\sclone\ssequence\snumber
-1 clone_seqno 0, push SERVERCODE PROJECTCODE, timestamp
abc same as -1
1x same as -1

The Linux x64 reply (error invalid\sclone\ssequence\snumber for clone 3 -1) is from the go-libfossil suite's run on that platform and was not reproduced here.

4. Impact

None for a conforming client, which cannot send the card. A test that pins either reply for a non-digit SEQNO passes against one Fossil build and fails against another, and a server implementer looking to Fossil for the "compatible" answer finds none.

5. Correction

In §8.1, append to the second paragraph:

    parsing later request cards.  This rule does not assign that fatal
    outcome to wrong arity, noninteger VERSION, or a SEQNO that fails
    digit-only recognition or does not yield that condition.
+   Fossil gives no stable reply to a SEQNO that is not digit-only: it
+   tests an uninitialized value, so builds differ between the fatal
+   error, an empty clone_seqno 0 reply, and serving from an arbitrary
+   RID.  Such a card does not match the clone-card grammar (Appendix B)
+   and is never produced by the client loop of Section 8.2; clients
+   MUST send a positive decimal SEQNO, and neither a client nor a test
+   may rely on any particular reply to another value.

6. Rationale

7. Verification


Prepared against draft-fossil-sync-protocol-00. The RFC remains the oracle; the reference implementation is used only to confirm the observable behavior.