musl 1.2.6 fixes positioned writes on append files
musl 1.2.6 uses Linux support to correct pwrite on O_APPEND files. Older kernels receive an explicit failure instead of a write at the wrong position.
The musl 1.2.6 announcement, published on March 20, describes a correction to pwrite on files opened with O_APPEND. The implementation uses the RWF_NOAPPEND flag added in Linux 6.9. When the kernel cannot support the required operation, musl reports an error instead of silently producing the wrong behavior. For systems code, that change in the failure mode deserves attention even when the function declaration stays the same.
I have worked with C for thirty years, and its role in defining interfaces between systems remains a large part of its importance to me. A library wrapper around an operating system call can look straightforward until the operating system behavior differs from the library contract. This release gives a concrete example of the work a C library performs to reconcile those differences. The application needs a reliable account of what success means, especially when a successful call modifies persistent data.
A positioned write has a specified destination
The POSIX definition of pwrite describes an operation equivalent to write with an explicit position. It does not change the file offset, regardless of whether O_APPEND is set. An ordinary append write and a positioned write therefore express different destination requirements. The former writes at the end, while the latter supplies the position as an argument.
Consider a hypothetical application that opens a file for append activity and also needs to update a fixed record through pwrite. If the positioned operation appends the record instead, the application has changed the wrong part of the file even though the call can report transferred bytes. This example does not require a crash to expose the problem. The file contents themselves would disagree with the operation the source code requested.
The standard also specifies that a successful return gives the number of bytes actually written, which can be less than the requested count. Correct placement and complete transfer are separate properties. A caller that checks only for a negative result has not established that it wrote the whole requested record. A review of this release should retain the ordinary short-write handling while adding coverage for the destination of the bytes.
The wrapper attempts the stronger kernel operation
The release version of pwrite.c shows the compatibility logic. It first attempts pwritev2 with a single vector and RWF_NOAPPEND. The function returns that result unless the attempt reports EOPNOTSUPP or ENOSYS. Those two errors lead to a fallback decision, so the implementation does not treat every failed write as evidence that it should try a different operation.
The fallback checks the descriptor flags with fcntl and F_GETFL. If O_APPEND is present, the wrapper returns EOPNOTSUPP. Otherwise, it uses the older positioned-write system call. This is the implementation detail behind the release announcement. musl can retain the older path when append behavior does not conflict with the requested operation, while refusing to report success through a path known to have incorrect append semantics.
I find that distinction useful when reviewing compatibility code. A fallback needs to preserve the meaning of the operation, as well as provide a route that runs on an older kernel. Here the release accepts a new observable error for an unsupported case. That gives the caller an opportunity to choose a different file-opening policy or reject the operation before treating the update as complete.
I would avoid responding to the new error with an unconditional ordinary write. Such a retry would need its own argument for why appending satisfies the application request. The original operation supplied a position, so the intended destination should remain part of the review. An error handler that discards that requirement could reintroduce the same data-placement problem at a different layer.
Tests should inspect the resulting file
For an application using this combination, I would test both append and positioned operations against a disposable file. The test should start with known contents and request a positioned update whose destination differs from the end. Its assertion should check the complete resulting contents, including the file length. That would distinguish a correctly placed update from an append that happens to report the same byte count.
A second case should exercise the application response when the positioned operation is unsupported. The release announcement explicitly calls out older kernels, so testing only against a new development kernel would leave that behavior unexamined. I would make the expected application policy explicit in the test description. An unsupported operation might be a legitimate reported failure, but the application must not describe that failure as a completed update.
This is a case where testing only the wrapper return value would be too weak. The defect concerns a mismatch between the requested file position and the resulting state. I would use that state as the observable result in a regression test. The same reasoning applies to reviewing a patch that changes which descriptor the application uses for positioned updates.
The release also carries an earlier security fix
musl 1.2.6 incorporates the fix for CVE-2025-26519 in iconv. The announcement says the correction had previously been available as patches. That history matters when identifying affected installations. The release version alone does not tell an operator whether an earlier packaged build already carried the patch, and I would check the package maintenance record before drawing that conclusion.
The announcement also adds the POSIX-2024 posix_getdents interface and the Linux-specific renameat2 interface. It lists a semaphore wake-event race among the other corrections. These items have different adoption implications from the positioned-write change. A new interface matters when an application chooses to call it, while an existing function can change observable behavior without a source change.
For an upgrade assessment, I would therefore identify current uses of pwrite on append descriptors before considering new interfaces. The relevant evidence would include the descriptor-opening flags and the error path at each call. The release source makes the fallback decision inspectable, so the application review can state which kernels support the requested operation and what the application reports when they do not.