Hi,
On 2026-02-19 11:14, Emanuele Rocca wrote:
> Source: dovecot
> Version: 1:2.4.2+dfsg1-3
> Severity: important
> User: [email protected]
> Usertags: arm64
> X-Debbugs-Cc: [email protected]
>
> Hi,
>
> dovecot fails to build from source on arm64 when using glibc 2.43,
> currently in experimental.
>
> The build gets stuck in a endless loop. The failed assert below was
> logged several million times on the system where I was building the
> package when I noticed the multi-GB build log and killed the build:
>
> make[4]: Entering directory
> '/build/reproducible-path/dovecot-2.4.2+dfsg1/src/lib-ssl-iostream'
> for bin in test-iostream-ssl; do \
> if ! ./$bin; then exit 1; fi; \
> done
> ssl: handshake ....................................................... : ok
> test-iostream-ssl.c:448: Assert failed: o_stream_send(client->output, buf,
> avail) == (ssize_t)avail
> test-iostream-ssl.c:105: Assert failed: i_stream_read_bytes(ep->input,
> &data, &size, 1) > -1 || ep->input->stream_errno == 0
> test-iostream-ssl.c:105: Assert failed: i_stream_read_bytes(ep->input,
> &data, &size, 1) > -1 || ep->input->stream_errno == 0
> test-iostream-ssl.c:105: Assert failed: i_stream_read_bytes(ep->input,
> &data, &size, 1) > -1 || ep->input->stream_errno == 0
> [EMA: SNIP!]
>
> Logs here:
> https://people.debian.org/~ema/glibc-2.43-rebuilds/output-1/dovecot_arm64.build
>
> The issue is triggered by glibc 2.43 on arm64 enabling 2MB THP by
> default:
> https://sourceware.org/git/?p=glibc.git;a=commit;h=321e1fc73f53081d92ba357cdd48c56b79292020
>
> The problem is however not architecture-specific. For example it can be
> reproduced with glibc 2.42 on amd64 by building the package with the
> GLIBC_TUNABLES environment variable set to glibc.malloc.hugetlb=2.
The problems happen in o_stream_file_writev() from
src/lib/ostream-file.c. When an error happens, it calls
p_strdup_vprintf(), which in turns call t_buffer_alloc() which might
indirectly through successive functions call malloc(). In some
conditions, malloc() might change errno even if there is no error. This
means that o_stream_file_writev() might return with the wrong errno
(ENOENT from malloc) while the real errno might be EINTR or EAGAIN,
for which a retry is triggered.
A possible fix might be to save errno around the malloc code, fixing the
issue at the root, as there might be more latent issues than the ones
found by the testsuite:
--- dovecot-2.4.2+dfsg1.orig/src/lib/data-stack.c
+++ dovecot-2.4.2+dfsg1/src/lib/data-stack.c
@@ -367,6 +367,7 @@ static struct stack_block *mem_block_all
{
struct stack_block *block;
size_t prev_size, alloc_size;
+ int saved_errno = errno;
prev_size = current_block == NULL ? 0 : current_block->size;
/* Use INITIAL_STACK_SIZE without growing it to nearest power. */
@@ -392,6 +393,7 @@ static struct stack_block *mem_block_all
#ifdef DEBUG
memset(STACK_BLOCK_DATA(block), CLEAR_CHR, alloc_size);
#endif
+ errno = saved_errno;
return block;
}
Regards
Aurelien
--
Aurelien Jarno GPG: 4096R/1DDD8C9B
[email protected] http://aurel32.net