[r13010]
( HEAD)
by
mikeaubury
Make bin/aubit POSIX sh, so it no longer depends on bash
The wrapper could not be parsed by a POSIX shell at all - dash stopped at line
39 on "function dummy ()". It coped by re-execing itself:
if [ -z "$BASH_VERSION" ]; then
exec bash "$0" "$@"
fi
which only works where bash exists. That is not everywhere we claim to build:
Alpine/musl images frequently have no bash, and FreeBSD keeps it in
/usr/local/bin. It also cannot help the case that matters most - incl/Makefile-
common sets SH=sh, so the makefiles run "${SH} .../bin/aubit fcompile ..." and
a shebang would be ignored there anyway. On any system where /bin/sh is dash,
those rules were relying on that exec finding a bash.
The script turned out to be very close to POSIX already - no [[ ]], no arrays,
no ${x//y}, no +=, no <<<, no brace expansion. What it used:
118 function NAME () -> NAME ()
44 let X=X+1 -> X=$((X+1))
6 echo -e -> printf '%b\n' (dash's echo expands escapes
itself and would have printed a literal "-e")
4 source F -> . F
4 declare X=Y -> local X=Y (matching the comment above them)
With those gone the re-exec is unnecessary and is removed, and the file gets a
real "#!/bin/sh" on line 1 - the one it had was on line 32, where it is just a
comment. The dummy() tripwire stays as a guard for a shell with no function
support at all, but its message no longer tells people to install bash, and it
no longer tries to run itself under a bash it may not have.
Verified rather than assumed: bin/aubit now parses under dash, bash and sh;
"aubit-config", "4glpc", "fcompile" and "amkmessage" all produce correct output
when driven by dash as well as bash; and tools/test builds end to end with
"make SH=/bin/dash SHELL=/bin/dash", which exercises the wrapper for form
compilation and message compilation. Before this change dash could not get past
parsing the file.
A full clean build is unaffected: 724 warnings, exit 0.
|
2026-08-26 07:59:53
|
Tree
|
[r13009]
by
mikeaubury
Stop using "which" to find commands - it is not guaranteed to exist
Follow-on audit after r13008. The flexml failure was one instance of a general
habit: asking the shell whether a command exists in a way that is not portable.
"which" is an external program, not a shell builtin, and Debian dropped it from
debianutils in 13 - so on the newest Debian and Ubuntu it may simply not be
installed. Every `which foo` then produces nothing, and the surrounding code
concludes the tool is absent (or, where the result is used as a path, gets an
empty one). That is the same shape of bug as r13008, just failing the other way
round: there, a missing tool looked present; here, a present tool looks missing.
Converted to "command -v", which is POSIX, is built into every shell, and
prints a path on stdout only when the command exists:
- bin/aubit: 26 call sites - the compiler wrapper's probes for gcc, make,
ldconfig, locate, xdg-open, xmessage, desktop-file-install, 4glc, 4glpc and
the rest. This is the script CLAUDE.md tells everyone to invoke, so it is the
one that matters most.
- Makefile: the check.exe.in.path target, which exists to refuse to install
when Aubit executables are still on PATH. With "which" gone that check
silently passes, which is exactly backwards for a safety check.
- bin/aubitbuild.sh.in: was deriving a script's path by picking field 3 or 4
out of "type" output, with a fallback because the field moves depending on
whether the command is hashed - and the wording differs between shells
anyway. command -v gives the path directly. Patched in the .in template, as
configure generates bin/aubitbuild.sh from it.
Two things found in passing and deliberately left alone, both worth a look:
- bin/aubit line 806 reads x="`command -v $prg >/dev/null 2>&1`" - stdout goes
to /dev/null, so x is always empty and the "Found in PATH" branch below it
has never run. Removing the redirect would switch on a branch that does
rm -rf on what it finds, under A4GL_FORCE_CLEAN, so that is a decision to
make deliberately rather than as part of a mechanical sweep.
- bin/aubit has no shebang: the "#!/bin/sh" in it is on line 32, not line 1.
It also does not parse under dash (bash-isms), so it relies on being started
by a bash-compatible shell. It works today because whatever runs it is bash;
it would break where /bin/sh is dash and something execs it directly.
The one remaining "type" probe is PKG_CONFIG_ROOT_CYGPATH in
incl/Makefile-install.mki, which parses type's output for a Cygwin path.
Cygwin is no longer a supported platform, so it is left as it is.
|
2026-08-26 07:47:15
|
Tree
|
[r13008]
by
mikeaubury
Detect optional build tools with "command -v", not "type"
Reported building r13007 on Ubuntu 26.04: the build stops in
lib/libui/ui_xml/uilib because it tries to run flexml, which is not installed.
It should never have tried. uilib/Makefile already falls back to the
checked-in xml/pregenerated/ copies of triggers.c, triggers_act.c and
triggers.h when flexml is missing:
HASFLEXML:=$(shell type flexml 2> /dev/null)
ifeq "$(HASFLEXML)" ""
TRIGGERS_O=xml/pregenerated/triggers.o xml/pregenerated/triggers_act.o
but the probe is not safe. "type" is a shell builtin whose behaviour for a
missing command differs: bash writes "flexml: not found" to stderr, so the
redirect hides it and HASFLEXML ends up empty, while dash - which is /bin/sh
on Debian and Ubuntu - writes it to stdout, where the redirect does not touch
it. HASFLEXML is then the non-empty string "flexml: not found", the makefile
concludes flexml is available, and make runs it and fails:
$ dash -c 'type flexml 2> /dev/null'
flexml: not found
$ dash -c 'command -v flexml 2>/dev/null'
$
"command -v" is the POSIX way to ask this and prints a path on stdout only
when the command exists, on either shell.
Fixed in all ten probes of this shape, not just the one that bit:
lib/libui/ui_xml/uilib/Makefile and uilib/xml/Makefile (flexml),
lib/libpacker/xml_best, xml_best2 and xml_best_plsql (flexml and a pregenerated
flex), and lib/extra_libs/mantisconnect (soapcpp2). All had the same latent
failure - each would have tried to run a tool that is not there.
Not reproduced end to end here: this box has bash as /bin/sh and GNU Make 4.3,
where the old probe happens to come back empty and the pregenerated files are
used, which is why the tree built fine for me at r13006. What is demonstrated
is the probe itself being unsafe under dash, and that both shells now select
xml/pregenerated/. The exact combination on the reporter's machine (dash plus a
newer make) is inferred.
The warnings quoted alongside the failure - comms.c sign-compare and unused
'p', uilib.c type-limits, attr.c redundant xml_yylex - are untouched; they are
warnings, not the reason the build stopped.
|
2026-08-25 16:10:04
|
Tree
|
|
|
2026-08-25 14:17:26
|
Tree
|
[r13006]
by
mikeaubury
Build haru.c against libharu 2.4 as well as 2.3
Reported against r13001 on Ubuntu 26.04, once the libcurl failure was out of the
way: lib/libpdf/haru.c does not compile against the libharu in /usr/local.
libharu 2.4 changed two things this file relies on:
- HPDF_Page_SetDash() takes its pattern as const HPDF_REAL * and its phase as
HPDF_REAL. Up to 2.3 those were const HPDF_UINT16 * and HPDF_UINT, and the
dash_mode arrays here are declared HPDF_UINT16 - a hard error under GCC 14+,
which is what the reporter hit at haru.c:3940 and :4012.
- HPDF_PROJECTING_SCUARE_END was corrected to HPDF_PROJECTING_SQUARE_END, so
haru.c:4069 no longer names anything that exists.
Rather than move to the new spelling and break older installations, pick both
from the version macros in hpdf_version.h (which hpdf.h includes): the dash
arrays use A4GL_HPDF_DASH, HPDF_REAL from 2.4 onwards and HPDF_UINT16 before
that, and the code now uses the corrected SQUARE spelling with a #define
mapping it back to SCUARE on older headers. A build with neither macro defined
gets the old API, which is what it would have had anyway.
Note that on 2.4 the dash lengths stop being truncated to whole points, since
the pattern is now float either side of the call.
Verified both ways: compiles clean against the 2.3.0 headers on this box (the
old branch, including the SCUARE remap), and the preprocessor picks HPDF_REAL
plus the corrected spelling when the version macros say 2.4. I have no 2.4
install here to compile the new branch end to end, so that half is verified at
the preprocessor rather than by building it.
The comment at the old line 4059 ("SCUARE is not a spelling mistake!") now
points at the shim instead - it was true of 2.3 and wrong from 2.4 on.
|
2026-08-25 14:11:53
|
Tree
|
[r13005]
by
mikeaubury
Finish the sprintf conversion in the grammar fragments and lint.c
Follow-on to r13004. -Wformat-overflow goes from 14 to 7, and a full build from
737 to 730 warnings.
GCC only flags the calls whose overflow it can demonstrate; the rest of the raw
sprintf() calls in the same files are exactly as unchecked, they just have
arguments it cannot bound. So rather than convert the seven it named, this
converts every remaining sprintf() in the files that owned them - 44 calls in
compilers/sql/80.reqd, compilers/sqlcmd/80.reqd,
compilers/4glc/rules/sqlpack/infx/sql1.rule and compilers/4glc/lint.c.
Every destination in those files is either a local char buff[N] or the parser's
$<str>$, which is the char str[1024] member of the %union - both arrays, so
sizeof() in the SPRINTFn macro measures the real space and A4GL_sprintf raises
its assertion, naming file and line, when the result will not fit. Which is the
point: we do not need to know in advance whether a 2k buffer can overflow, we
need it to stop loudly on the day it does.
(lint.c has one static char *buff, in local_xml_escape(), which builds its
string by hand and is not a sprintf destination - so no call was converted to a
macro that would silently take the unchecked pointer path.)
The remaining 7 are the two files that cannot use the macro at all, as noted in
r13004: compilers/xgen/x.yacc (5), where bin/xgen is a bootstrap tool linking no
library, and lib/libui/ui_xml/proxy.c (2), which includes only system headers.
|
2026-08-25 13:56:51
|
Tree
|
[r13004]
by
mikeaubury
Use the checked SPRINTFn macros for the sprintf calls GCC flags as overflowing
-Wformat-overflow drops from 159 to 14, and a full build from 882 to 737
warnings. Unlike the previous batch this is not just noise removal: GCC was
right about every one of these.
The SPRINTFn macros in incl/a4gl_libaubit4gl.h were already the house style -
3400-odd calls use them - and they expand to
A4GL_sprintf(__FILE__, __LINE__, dest, sizeof(dest), fmt, ...)
which formats into a scratch buffer of the destination's size and raises an
assertion naming the file and line if the result would not fit, instead of
writing past the end. 132 raw sprintf() calls that GCC could show overflowing
now go through it.
The yacc grammars were the bulk of them, and are the clearest case:
%union { char str[1024]; ... }
sprintf($<str>$, "%s,%s", $<str>1, $<str>3); /* up to 2048 bytes */
sizeof($<str>$) is the union member's 1024, so the macro checks these properly
rather than degrading to the unchecked pointer path.
Where the warned code lives in a build product the fix is in the source it is
assembled from: compilers/4glc/rules/*.rule and sqlpack/infx/*.rule feed the
generated fgl.infx.yacc, and 80.reqd feeds the sql.yacc that compilers/sql and
compilers/sqlcmd each cat together. Both .reqd copies are edited, since each
Makefile builds its own grammar.
Four sites are deliberately left alone:
- compilers/xgen/x.yacc (5): bin/xgen is a bootstrap tool built before
libaubit4gl exists and links no library, so A4GL_sprintf is not available to
it - converting it broke the link.
- lib/libui/ui_xml/proxy.c (2): includes only system headers, so the macro is
not in scope, and pulling a4gl_libaubit4gl.h into a socket proxy to silence
two warnings is a poor trade.
- sql.yacc (6) and lint.c (1): grammar rules spanning several lines, which the
mechanical pass could not map back to their source fragment with confidence.
One trade-off worth recording: A4GL_sprintf is not declared with
__attribute__((format(printf,5,6))), so GCC no longer type-checks the format
strings at these call sites - the runtime length check replaces a compile time
argument check. Adding that attribute to the declaration would get both back
across all 3400 existing uses; I have not measured how many new -Wformat
warnings it would surface.
|
2026-08-25 12:59:07
|
Tree
|
[r13003]
by
mikeaubury
Silence the two noisiest warning categories: sign-compare loops and unused-but-set
A full build goes from 2066 warnings to 882. The two categories dealt with here
were 1409 of those, and neither was telling us anything.
-Wunused-but-set-variable (303, across 66 files) is switched off in
configure.ac, alongside the -Wno-unused-parameter and -Wno-unused-function that
were already there - same reasoning, they are almost all leftovers from removed
debug and trace code. This needs configure regenerating, hence the change to
the checked-in configure as well.
-Wsign-compare (1106) is NOT switched off, because the category is not uniformly
noise. It splits three ways:
880 for (a=0; a<x.x_len; a++) counter is int, length is u_int
178 if/while comparisons
13 A4GL_assertion() bounds checks
35 other
Only the first group is meaningless: the counter starts at zero, so the signed
comparison is what was meant all along. Those are now cast - 829 rewritten
mechanically from the compiler's own diagnostics and verified by rebuilding,
plus 3 by hand in ace.yacc, screen.yacc and helper_funcs.ec, which the script
skipped because a #line directive makes the reported column unreliable.
The other 226 are left visible on purpose. The assertions are the reason:
A4GL_assertion(u->variable_id >= ...->variables.variables_len, "Invalid VARIABLE ID");
a negative variable_id converts to a huge unsigned here, so the assertion fires
and catches it. Casting the length to int would let a negative index through
into the array access. Anything that hides this category hides that too.
Two of the casts change behaviour, both for the better:
lib/libform/form_generic/formwrite2.c:439
lib/liblex/lex_esqlc/compile_c.c:2927
for (a = 0; a < (int)(len - 1); a++)
With len==0 the old code computed 0-1 as unsigned, so an empty list ran the
loop UINT_MAX times instead of not at all. Both loops mean "all but the last
element", and now they do that.
What is left: format-overflow 159 (sprintf in the yacc grammars, worth a proper
look), unused-variable 64, missing-prototypes 61, unused-const-variable 48,
redundant-decls 48, plus the bison grammar warnings and the ~19 real bug
candidates noted previously.
|
2026-08-25 12:29:22
|
Tree
|
[r13002]
by
mikeaubury
Fix clean-build breakage from r13001, two latent pointer bugs, and ~700 warnings
r13001 broke "make cleanall && make": having every generated API .c include
a4gl_API_<x>.h assumed the incl/a4gl_API_*.h naming used by lib/libaubit4gl
and compilers/4glc, but lib/liblogical/processor and lib/liblogical/layout_engine
generate a local API_<x>.h instead, so they failed with "a4gl_API_process.h: No
such file or directory".
- lib/bin/dlmagic, lib/bin/dlmagic_c.awk: drop the api_header include again.
The _lib.h include stays - that is the actual fix for the _self.c files, and
-S is only ever used from the two directories that follow that convention.
Two of these are real bugs rather than cosmetics, both dormant until libcurl
and the ODBC headers were actually in play:
- lib/libsql/odbc/sql.c: SQLLEN was #define'd to int, but the bundled
tools/odbctest/incl headers declare SQLBindCol's StrLen_or_Ind parameter as
SQLINTEGER *, which is long * there - the driver was writing 8 bytes into
4 byte indicator fields on any LP64 platform. Define it as SQLINTEGER.
- lib/liblogical/common/a4gl_lle.c: the HAVE_LIBCURL branch calls url_fopen()
and friends without including a4gl_curl.h, and held the handle in a FILE *
rather than a URL_FILE *. Same bug curl.c had, and equally invisible until
libcurl is installed.
Warning cleanup - a full build goes from 2722 to 2022 warnings on the same
files. Every diagnostic that GCC 14/15 turns into a hard error is now gone
(incompatible-pointer-types 11 -> 0, implicit-function-declaration 5 -> 0,
int-conversion, implicit-int and return-mismatch all 0), so the Ubuntu 26.04
build should get through the whole tree rather than stopping at curl.c.
- compilers/xgen/x.yacc: the generated .xo.c/.xi.c loops compared an int
counter against the XDR _len members, which are u_int. Cast, as the
surrounding generated code already does: common/dataio 220 warnings -> 0.
- incl/Makefile-common.in, lib/libsql/odbc/Makefile: build sqlite3odbc.c,
Christian Werner's ODBC driver vendored from upstream, without our warning
set - same reasoning as the rpcgen output in common/dataio. 318 -> 0. The
-Wno- flags in WARN_THIRDPARTY follow -w deliberately: from GCC 14 those
diagnostics are errors, and -w does not switch an error off.
- lib/libsql/esqlc/Makefile, esql.ec: the ifx_hostvar_t descriptors written by
Informix's own esql preprocessor never initialise the trailing "reserved"
member (119 warnings we cannot fix in our source), and sqgetdbs() is exported
by the ESQL/C library but declared in none of the shipped headers. 124 -> 4.
- incl/a4gl_incl_4glhdr.h: LABEL_USED is now __attribute__((unused)), so the
END_BLOCK_n/CONTINUE_BLOCK_n labels in generated 4GL code stop warning. The
original attempt at this was commented out because it said "used", which is
not valid on a label. 58 -> 0 across every compiled .4gl.
- compilers/fcompile/dump_scr.c: default: break; on five switches over enums
where the unhandled values are deliberately ignored. 63 -> 0.
- tools/adbload2/a4gl_dbload_int.h: prototypes for a4gl_dbload_yyparse() and
yywrap().
Still outstanding, all in hand-written code and needing a decision per site:
sign-compare (1106, mostly dump_form.c, compile_c.c and lint.c),
unused-but-set-variable (303), unused-variable (64), missing-prototypes (61).
|
2026-08-25 11:42:39
|
Tree
|
[r13001]
by
mikeaubury
Fix gzFile/FILE* type error in curl.c and clean up the dlmagic API generator
Reported on Ubuntu 26.04: GCC 15 makes -Wincompatible-pointer-types an
error, so lib/libaubit4gl/curl.c no longer compiled where libcurl is
installed. It only ever built by accident - GCC 13 warned and carried on.
- incl/a4gl_curl.h: the local file in struct fcurl_data was a FILE *, but
curl.c opens and reads it through the A4GL_gz* macros, which are the
zlib functions (working on a gzFile) whenever zlib is enabled. The union
member now follows A4GL_gzPtr, falling back to FILE * if the header is
used without a4gl_libaubit4gl.h.
- incl/a4gl_libaubit4gl.h: A4GL_gzftell/gzfseek/gzrewind existed only in
the no-zlib branch, which is why curl.c had to call gzrewind() directly
and broke the no-zlib build in the other direction. Added the zlib
versions; corrected the no-zlib A4GL_gzftell/gzfseek from tell()/seek()
to ftell()/fseek().
- lib/libaubit4gl/curl.c: gzrewind() -> A4GL_gzrewind().
The generated API_*_self.c files (dlmagic -S, used by the static-link
targets - 4glc compiles API_parse_self.c, mkglobals and fglreload_static
compile API_lex_self.o) called the <LIB_PREFIX> functions with no
prototypes in scope: 47 implicit declarations, all fatal under GCC 15.
The prototypes were always there - dlmagic -H writes them to
a4gl_API_<x>_lib.h - but only API_parse_int.h happened to include it.
- lib/bin/dlmagic, lib/bin/dlmagic_c.awk: self mode now includes the
_lib.h holding the prototypes of what it calls, and both modes include
a4gl_API_<x>.h, declaring what they define. Self mode no longer emits
the dlopen-only declarations (clrcachedptrs, declared static but never
defined; dlclose; the unused currentLib). A MAP entry or a "..."
parameter makes the wrapper call internal_<fname>/the mapped name, which
no header declares - unused today, so the generator now emits a matching
prototype rather than leaving a trap.
- lib/libaubit4gl/Makefile: a4gl_API_%_lib.h needs a rule of its own now
that it is a prerequisite rather than a side effect of the .h rule, and
needs naming as a target (API_LIB_HEADERS, .PRECIOUS) so make does not
delete all 11 headers as intermediate files. $^ -> $< in the _self.c
recipe, or the added prerequisite is passed to dlmagic as <APIName>.
Also fixes parallel builds of the API layer, which never worked: dlmagic
assembled its output in dlm.1/header.dlmagic/clrptr.dlmagic in the current
directory, so concurrent runs overwrote each other and make -j failed.
The scratch files are now named after the pid.
All 26 generated API files (11 dlopen + 11 self, plus 4 in compilers/4glc)
now compile with no errors and no warnings under -Wall -Wextra
-Wredundant-decls -Wmissing-declarations -Wmissing-prototypes
-Wstrict-prototypes and the GCC 15 -Werror set.
|
2026-08-25 11:12:00
|
Tree
|