Repository navigation
v3.7.0
A command is words, not a line — and the boundary answers instead of
stopping. A path an editor handed the language server could run a shell
command; closing that gave the library PasProcess.Execute, an audit of the
fix the same afternoon closed six more findings, and a project-wide audit
after it found nine foreign scalars bound at the wrong width and nineteen
routines that stopped a program on a name holding chr(0). Beside that, a
TOML library and the project reader rewritten over it. Minor, because the
library and the command line grew and nothing already accepted changed
meaning; a program that met one of the fixed defects met a trap or a wrong
width, and neither is a behaviour to preserve.
Added
-
PasProcess.Deadline— how long any run of anArgVmay take; on expiry
the child is killed, the pipe is closed so a grandchild cannot hold the
caller either, and the run iserrIO.PasFS.TemporaryDirectory— a
directory of the program's own, overmkdtemp, for a caller that wants
several files by names of its choosing (ADR-0363). -
A command as words, not as a line —
PasProcess.Executeand the four
routines beside it (ExecuteInto,ExecuteBoth,ExecuteLines,
ExecuteToFile), over anArgVbuilt withNewArgs,AddArg,ArgsLen
andDropArgs. The words are carried as words and no shell reads them, so
an argument holding a space, an apostrophe, a semicolon or a backquote is an
argument.Run,CaptureandCaptureLinesare unchanged and remain the
right answer for a pipeline or a redirection; preferExecutewherever any
part of the command came from outside the program (ADR-0362). -
A TOML library —
lib/dialect/pastoml.pas, TOML v1.0.0 whole rather
than a subset: bare, quoted and dotted keys; basic, literal and both
multi-line string forms; decimal, hexadecimal, octal and binary integers with
underscores; floats withinfandnan; all four date-time forms; arrays
over several lines and with a trailing comma; inline tables; tables; and
arrays of tables.TomlParseandTomlParseCharsanswer aTomlResult, and
TomlPositionOfturns the byte a refusal stopped at into a line and a
column.TomlPath(doc, 'server.port')is the dotted lookup a configuration
reader wants;TomlRenderwrites a document back, and parsing that and
rendering again reproduces it byte for byte. A date-time is §6.4.3.4's
ownTimeStampwith a nanosecond and a UTC offset beside it, so a program
hands the result straight toPasTime. An integer isinteger, so a
value outside -maxint..maxint iserrRangeand never a wrapped number.
ADR-0360. -
PasText.RealToStr— the shortest decimal that reads back as a given real,
which wasPasJson's and is now where two formats can reach it. ADR-0359. -
bin/apconfig— the project-file readerpascalcc build,runand
testcall, written in this language overPasTomland installed beside
pascalc.APCONFIGoverrides where the driver looks for it, asPASCALC
does for the compiler. ADR-0361.
Fixed
-
Nineteen library routines stopped the program on a name holding
chr(0)-- every path, name, host or service taken byPasFS,PasDir,
PasEnv,PasIO,PasStreamandPasNetreached ADR-0122's trap. Each
now answers a code (errSyntax,falseornil) through the shared
PasError.HoldsNul, which is ADR-0363's rule applied to the whole library
rather than to the two routines it was written for. -
Nine more foreign scalars bound at the wrong width, and the emitter's own
slice count (ADR-0364):read/write(ssize_t),fflush(a pointer)
and six OpenSSL bindings (longs and pointers) wereint64; nowcsize
orclong. A slice's count crossed every foreign call asi64, on i386
too, wheresize_tis 32 bits -- it is the target's width now. The new
foreign-widthgate holds both, because no behavioural case can: on a
host whose spare register is clean the wrong width gives the right answer. -
PasProcess.SecondsandCpuSecondsanswered garbage on i386:time
andclockwere bound as returningint64, and both arelong, 32 bits
there -- the high word was whatever the register held. Bound asclong
now (AP 6.4.2.7); found by ADR-0363's deadline case, the first to compute
withSeconds, under thetarget32gate on CI. -
Six findings of the security audit over
PasProcess.Execute(ADR-0363),
four of them older than it: a path holdingchr(0)stopped the language
server on one request, and is now refused as a code;ExecuteToFile
followed a symbolic link, and the server's scratch files were composed at
the top ofTMPDIRunder a guessable name —O_NOFOLLOWnow, and a private
mkdtempdirectory removed atexit; noExecutehad a deadline; a child
inherited every open descriptor (FD_CLOEXECon pipes and sockets, mode
eon everyfopen); threeposix_spawnfile-action returns went
unchecked; and a failedfdopendropped the output silently. -
A path the language server was given could run a command (ADR-0362).
lsp/pasls.pasassembled a shell command and wrapped the source path in
apostrophes; a path holding an apostrophe closed the quoting, so a file named
a'; touch PWNED; echo '.pasrantouch PWNEDwhen an editor asked for its
outline — and under MCP the path comes from whatever is driving the model.
The server now spawns the compiler with an argument vector and quotes
nothing.tools/pascalccwas never affected: it is bash and uses arrays.
The newcommand-injectiongate holds both halves — that nothing ran, and
that such a file still compiles. -
afterschool-pascal.tomlis read as TOML. The driver read it with a
declared subset written inawk, which got two kinds of legal document
wrong: a#inside a quoted string ended the value, sooutput = "build/demo#1"silently builtbuild/demo; and an array was split on every
comma, soldflags = ["-Wl,-rpath,/opt/lib"]— one flag — was rejected as
three malformed strings. Both now read as TOML says, a syntax error names a
line and a column, and an unknown key or a value of the wrong shape is
still refused by name. ADR-0361. -
Writing a NaN through
PasJsonstopped the program. The guard against a
value with no decimal spelling askedx <> x, which is false for a NaN on
this processor —<>on reals is ordered not-equal — so the guard never
fired and the scan below it read past the end of whatwritestrhad
written, reportingarray index out of boundsagainst a line of the
library. It asksnot (x = x)now. A program could only reach it by
computing a NaN, this language having no literal for one. ADR-0359.