Jump to content

Classic bug: Rejected mail leaks into output

From Galactic Empire wiki
Bug ID GE-BUG-054
Affected versions Classic 3.2e and published classic source; residual path in ge-next through 0.3.2
Status Verified in source
Fixed in ge-next 0.3.3 (remaining print-buffer leak); ge-next 0.2 removed Zygor's ordinary starvation update
Primary source GEPLANET.C: multiply(); GEFUNCS.C: mailit() and sendit(); GEMAIN.C: plarti()/plartia()

Summary

Classic can leave a formatted planetary distress message in the shared print buffer when its intended recipient is a special, non-player owner. sendit() deliberately refuses to create mail for an owner whose name starts with *, but returns without clearing the text already assembled by mailit(). A later output operation can display that orphaned text on a user's screen. It is not mail delivered to Zygor: Zygor has no user mailbox.

Background: Zygor's 2.2e restock

Classic initially creates Zygor with 32,000 men but no food. Its ordinary planetary update therefore makes one eighth of those men starve. A change identified in the source as a GE 2.2e patch restocks every Zygor item category, including men and food, to 1,032,000 on each scheduled update. That largely prevents continuing starvation, although it also makes colony supplies purchasable at Zygor rather than only at Tahanian Station. The earlier risk of a persistently dwindling Zygor population is historical background, not the defect documented here. See Zygor for the market consequences.

The first update still runs multiply() before that restock. A newly created Zygor therefore enters it with 32,000 men and no food, loses 4,000 men, and formats a MESG07 civilian-starvation notice addressed to its configured owner (normally *EMPIRE* in classic). The subsequent restock restores the population and food, but it cannot retract the already generated message.

Cause of the output leak

mailit() clears the print buffer, appends the mail header and starvation text with prfmsg(), then calls sendit(). Classic sendit() begins with the equivalent of:

if (mail.userid[0] == '*')
    return FALSE;

This intentionally prevents sending mail to special owners such as *EMPIRE*, but the return occurs before prf2tx() converts and clears the buffered text. mailit() does not clear it on return either. The next output flush can consequently carry the abandoned mail text into an unrelated user display. No message record or user account for Zygor is needed, and sendit() does not itself call a console-status printer. Whether the leak is visibly printed, and exactly when, depends on later output activity.

Other non-player planets

The remaining path is not limited to Zygor. After a revolt, the ordinary planet record can retain men and troops while its owner changes to **Free**. That planet continues through multiply() on later scheduled updates. If it then has insufficient food for at least 100 men or 100 troops, a starvation notice is formatted for **Free**; sendit() rejects that address and, before the 0.3.3 fix, leaves the same text behind. This is conditional, not an event caused by every revolt: a free planet with adequate food generates no starvation mail. Other mail paths aimed at an asterisk-prefixed owner could expose the same early-return flaw.

Correction in ge-next

ge-next 0.2 introduced dedicated update paths for Zygor and the other central planets. Zygor is restocked without first running ordinary population, food, production, tax, and revolt processing, so the classic first-update starvation notice is not generated there. This removed the familiar Zygor trigger but did not change sendit(); ordinary **Free** planets could still reach it.

ge-next 0.3.3 fixes the underlying leak in both 16-bit and 32-bit builds. If the recipient begins with *, sendit() now clears the already formatted print buffer before returning FALSE. It still does not create a mailbox message for a non-player owner. Normal mail delivery and planetary starvation calculations are unchanged.

See also