[fitswcs] WCSLIB 8.7 released {External}
Mark Calabretta
mark at calabretta.id.au
Mon May 11 08:57:04 EDT 2026
Greetings,
WCSLIB 8.7 is now available from
https://www.atnf.csiro.au/computing/software/wcs/wcslib-releases
This release is the result of running WCSLIB through various static
code analysis tools, which mostly resulted in dotting the is and
crossing the ts, as detailed below.
Mark Calabretta
WCSLIB version 8.7 (2026/05/11)
-------------------------------
The changes in this release were prompted almost exclusively by
Anthropic's Claude Code AI static code analysis tool. Rob Seaman ran
it on WCSLIB 8.6 and, under his supervision, Claude produced a detailed
report of WCSLIB's shortcomings and a summary of its historical
development.
In addition to its own analysis, Claude Code relied heavily on three
other static code analysis tools: scan-build and clang-tidy from LLVM
22.1.2, and cppcheck 2.20.0. In fact, clang-tidy made the majority of
change suggestions, which prompted me to install a slightly older
version, LLVM 20.1.2, and run it myself. Curiously, scan-build, which
is said to be the most thorough, produced a clean result. cppcheck
found a few issues that were missed by the others.
Claude Code did a pretty good job of summarising the often tediously
nit-picky output of the static analysers, and also in constructing a
history of WCSLIB's code development.
This exercise resulted in the changes to the C library detailed below.
Mostly they could be described as armour-plating, if not gold-plating.
However, there was one bug and several instances of potential memory-
related issues, mostly in seldom-taken paths through the code such as
error processing.
* C library
- In wcshdo_util(), a static helper function for wcshdo(), fixed a
bug that would have caused the keycomment to be truncated to a
single character when keyvalues exceeded 20 characters.
- Fixed various memory-related issues, such as potential memory leaks
on error return, potentially dereferencing null pointers, incorrect
handling of failed calls to realloc(), etc. in wcsprt(), wcssub(),
wcstrim(), wcspcx(), disset(), discpy(), diswarp(), and various of
the static distortions helper functions.
In wcsprintf(), call va_end() if memory allocation fails in order
to release the memory allocated by va_start().
In wcserr_clear(), ensure that errp is non-NULL before dereferencing
it.
In tabini(), check that the total number of elements in the
coordinate array does not exceed INT_MAX.
- In prj.c and sph.c, removed the hand-coded copysign() macro, which
is now provided by C99.
- In wcsinit(), lininit(), and disinit(), check that the value
provided for naxis is not too large. Negative values also now
return WCSERR_BAD_PARAM rather than WCSERR_MEMORY.
In conjunction with the above, global variables that record various
limits are now declared in a new header file, wcslimits.h. Their
values are set in wcs.c, including a limit of 31 for NAXIS and also
the default limits for the number of PVi_ma, PSi_ma, DPja, and DQia
keywords, which may be changed.
In cylfix(), use the maximum value of NAXIS from wcslimits.h.
- Throughout the C library, replaced use of strcpy() (200 occurrences)
and strcat() (23 occurrences) with strncpy(), and sprintf() (202
occurrences) with snprintf(). These mostly related to in-memory
copying of string constants, etc., which are inherently well-
constrained.
Likewise, in wcsprintf() and wcsfprintf(), replaced use of
vsprintf() with vsnprintf().
Likewise for the test suite.
- In wcsmath.h, parenthesised three macro definitions to ensure the
correct order of precedence when used in arithmetic expressions.
- Addressed, by way of appeasement, a plethora of inconsequential
warnings from clang-tidy relating to putative "bug-prone"
constructs, none of which were bugs, in the following categories:
- bugprone-branch-clone
- bugprone-implicit-widening-of-multiplication-result
- bugprone-integer-division
- bugprone-multi-level-implicit-pointer-conversion
- bugprone-narrowing-conversions
- bugprone-not-null-terminated-result
- bugprone-suspicious-string-compare
- bugprone-switch-missing-default-case
The following categories were disabled:
- bugprone-assignment-in-if-condition [I drew the line here!]
- bugprone-easily-swappable-parameters [can't change API!]
- bugprone-reserved-identifier [only in sundazel]
- In the test suite, replaced the remaining heritage K&R-style
variable declarations with intermingled ANSI-style. Likewise for
the last few surviving K&R-style function prototypes.
* Fortran wrappers
- Replaced a single use of sprintf(), in keyget_(), with snprintf().
* PGSBOX
- In cpgsbox() and cpglbox(), replaced use of strcpy() with strncpy(),
and sprintf() with snprintf().
Likewise for test program cpgtest.
* Utilities
- Replaced use of strcpy() with strncpy(), and sprintf() with
snprintf().
* Installation
- Added rules to invoke clang-tidy (for code development).
* User manual
- Documentation generation moved to Doxygen 1.17.0 (was 1.16.0).
While the Doxygen bug reported in WCSLIB 8.5 has now been fixed,
the makefile patch has been left in place for the time being.
More information about the fitswcs
mailing list