[Aptitude-devel] Bug#1148483: aptitude: crash on arm64

Paweł Jasiak pawel at jasiak.dev
Mon Sep 28 22:54:11 BST 2026


The problem here is how errno is handled in cwidget (used by aptitude).

man errno:
> The value of errno is significant only when the return value of the
> call indicated an error.

In cwidget-0.5.18/src/cwidget/toplevel.cc:488 result of select is used
incorrectly. It's allowed to return any value different than -1 on success.
errno can be checked **only** if select returns -1.

Relevant part of code:

pthread_testcancel();
int result = select(1, &selectfds, NULL, NULL, &timeout);
pthread_testcancel();   // Workaround for Linux threads suckage.
                        // See pthread_cancel(3).

if(result != 1)
{
    if(errno != EINTR && errno != 0)
    {
        // Probably means that there was an error reading
        // standard input.  (could also be ENOMEM)
        post_event(new fatal_input_error(errno));
        break;
    }
}

If errno was not 0 before we are entering a loop it's game over.
fatal_input_error path is triggered and aptitude will die.

How it was found? First observation is that error is:
> Uncaught exception: Unable to read from stdin: Invalid argument

It's a strerror of EINVAL.

Let's run aptitude under strace: strace -f aptitude and search for
EINVAL.

Here is a result in my test env:

1209  madvise(0xaaab14a00000, 2097152, MADV_HUGEPAGE) = -1 EINVAL (Invalid argument)
1210  <... madvise resumed>)            = -1 EINVAL (Invalid argument)
1211  <... madvise resumed>)            = -1 EINVAL (Invalid argument)
1212  <... madvise resumed>)            = -1 EINVAL (Invalid argument)
1209  readlinkat(AT_FDCWD, "/var", 0xffffd3d22040, 1023) = -1 EINVAL (Invalid argument)
1209  readlinkat(AT_FDCWD, "/var/lib", 0xffffd3d22040, 1023) = -1 EINVAL (Invalid argument)
1209  readlinkat(AT_FDCWD, "/var/lib/dpkg", 0xffffd3d22040, 1023) = -1 EINVAL (Invalid argument)
1209  readlinkat(AT_FDCWD, "/var/lib/dpkg/status", 0xffffd3d22040, 1023) = -1 EINVAL (Invalid argument)
1209  madvise(0xffffa4c5f000, 4677632, MADV_HUGEPAGE) = -1 EINVAL (Invalid argument)
1209  madvise(0xffffa4363000, 9420800, MADV_HUGEPAGE) = -1 EINVAL (Invalid argument)
1209  madvise(0xffff92d39000, 25116672, MADV_HUGEPAGE) = -1 EINVAL (Invalid argument)
1209  madvise(0xffff9243d000, 9420800, MADV_HUGEPAGE) = -1 EINVAL (Invalid argument)
1209  madvise(0xffff90c49000, 25116672, MADV_HUGEPAGE) = -1 EINVAL (Invalid argument)
1209  madvise(0xffff90a48000, 2101248, MADV_HUGEPAGE) = -1 EINVAL (Invalid argument)
1209  madvise(0xffff90647000, 4198400, MADV_HUGEPAGE) = -1 EINVAL (Invalid argument)
1209  madvise(0xffff8fe46000, 8392704, MADV_HUGEPAGE) = -1 EINVAL (Invalid argument)
1209  madvise(0xffff8ee45000, 16781312, MADV_HUGEPAGE) = -1 EINVAL (Invalid argument)
1209  madvise(0xffff902ae000, 10072064, MADV_HUGEPAGE) = -1 EINVAL (Invalid argument)
1209  madvise(0xffff8e4aa000, 10072064, MADV_HUGEPAGE) = -1 EINVAL (Invalid argument)
1209  madvise(0xaaab14c00000, 2097152, MADV_HUGEPAGE) = -1 EINVAL (Invalid argument)
1209  madvise(0xaaab14e00000, 10485760, MADV_HUGEPAGE) = -1 EINVAL (Invalid argument)
1209  madvise(0xaaab15800000, 4194304, MADV_HUGEPAGE) = -1 EINVAL (Invalid argument)
1209  madvise(0xaaab15c00000, 4194304, MADV_HUGEPAGE) = -1 EINVAL (Invalid argument)
1209  madvise(0xaaab16000000, 2097152, MADV_HUGEPAGE) = -1 EINVAL (Invalid argument)
1209  madvise(0xaaab16200000, 2097152, MADV_HUGEPAGE) = -1 EINVAL (Invalid argument)
1209  madvise(0xaaab16400000, 6291456, MADV_HUGEPAGE) = -1 EINVAL (Invalid argument)
1209  madvise(0xaaab16a00000, 10485760, MADV_HUGEPAGE) = -1 EINVAL (Invalid argument)
1209  madvise(0xaaab17400000, 2097152, MADV_HUGEPAGE) = -1 EINVAL (Invalid argument)
1209  madvise(0xaaab17600000, 2097152, MADV_HUGEPAGE) = -1 EINVAL (Invalid argument)
1209  madvise(0xaaab17800000, 2097152, MADV_HUGEPAGE) = -1 EINVAL (Invalid argument)
1209  madvise(0xaaab17a00000, 2097152, MADV_HUGEPAGE) = -1 EINVAL (Invalid argument)
1209  madvise(0xaaab17c00000, 2097152, MADV_HUGEPAGE) = -1 EINVAL (Invalid argument)
1209  madvise(0xaaab17e00000, 2097152, MADV_HUGEPAGE) = -1 EINVAL (Invalid argument)
1209  madvise(0xaaab18000000, 2097152, MADV_HUGEPAGE) = -1 EINVAL (Invalid argument)
1209  madvise(0xaaab18200000, 2097152, MADV_HUGEPAGE) = -1 EINVAL (Invalid argument)
1209  madvise(0xaaab18400000, 2097152, MADV_HUGEPAGE) = -1 EINVAL (Invalid argument)
1209  madvise(0xaaab18600000, 2097152, MADV_HUGEPAGE) = -1 EINVAL (Invalid argument)
1209  madvise(0xaaab18800000, 2097152, MADV_HUGEPAGE) = -1 EINVAL (Invalid argument)
1209  madvise(0xaaab18a00000, 2097152, MADV_HUGEPAGE) = -1 EINVAL (Invalid argument)
1209  madvise(0xaaab18c00000, 2097152, MADV_HUGEPAGE) = -1 EINVAL (Invalid argument)
1209  madvise(0xaaab18e00000, 2097152, MADV_HUGEPAGE) = -1 EINVAL (Invalid argument)
1209  madvise(0xaaab19000000, 2097152, MADV_HUGEPAGE) = -1 EINVAL (Invalid argument)
1209  madvise(0xaaab19200000, 2097152, MADV_HUGEPAGE) = -1 EINVAL (Invalid argument)
1209  madvise(0xaaab19400000, 2097152, MADV_HUGEPAGE) = -1 EINVAL (Invalid argument)
1209  madvise(0xaaab19600000, 2097152, MADV_HUGEPAGE) = -1 EINVAL (Invalid argument)
1209  madvise(0xaaab19800000, 2097152, MADV_HUGEPAGE) = -1 EINVAL (Invalid argument)
1209  madvise(0xaaab19a00000, 2097152, MADV_HUGEPAGE) = -1 EINVAL (Invalid argument)
1209  madvise(0xaaab19c00000, 2097152, MADV_HUGEPAGE) = -1 EINVAL (Invalid argument)
1209  madvise(0xaaab19e00000, 2097152, MADV_HUGEPAGE) = -1 EINVAL (Invalid argument)
1209  madvise(0xaaab1a000000, 2097152, MADV_HUGEPAGE) = -1 EINVAL (Invalid argument)
1209  madvise(0xaaab1a200000, 2097152, MADV_HUGEPAGE) = -1 EINVAL (Invalid argument)
1209  madvise(0xaaab1a400000, 2097152, MADV_HUGEPAGE) = -1 EINVAL (Invalid argument)
1209  madvise(0xaaab1a600000, 2097152, MADV_HUGEPAGE) = -1 EINVAL (Invalid argument)
1209  madvise(0xaaab1a800000, 2097152, MADV_HUGEPAGE) = -1 EINVAL (Invalid argument)
1209  madvise(0xaaab1aa00000, 2097152, MADV_HUGEPAGE) = -1 EINVAL (Invalid argument)
1209  madvise(0xaaab1ac00000, 2097152, MADV_HUGEPAGE) = -1 EINVAL (Invalid argument)
1209  madvise(0xaaab1ae00000, 2097152, MADV_HUGEPAGE) = -1 EINVAL (Invalid argument)
1209  madvise(0xaaab1b000000, 2097152, MADV_HUGEPAGE) = -1 EINVAL (Invalid argument)
1209  madvise(0xaaab1b200000, 2097152, MADV_HUGEPAGE) = -1 EINVAL (Invalid argument)
1209  madvise(0xaaab1b400000, 2097152, MADV_HUGEPAGE) = -1 EINVAL (Invalid argument)
1209  madvise(0xaaab1b600000, 2097152, MADV_HUGEPAGE) = -1 EINVAL (Invalid argument)
1209  madvise(0xaaab1b800000, 2097152, MADV_HUGEPAGE) = -1 EINVAL (Invalid argument)

Why that happens? Looks like since libc 2.43 in arm64 version of Debian
libc tries to be smart about hugepages and set hints.

Here is a snippet from glibc malloc.c:

static inline void
madvise_thp (void *p, INTERNAL_SIZE_T size)
{
#ifdef MADV_HUGEPAGE

  /* Only use __madvise if the system is using 'madvise' mode and the size
     is at least a huge page, otherwise the call is wasteful. */
  if (mp_.thp_mode != thp_mode_madvise || size < mp_.thp_pagesize)
    return;

  /* Linux requires the input address to be page-aligned, and unaligned
     inputs happens only for initial data segment.  */
  if (__glibc_unlikely (!PTR_IS_ALIGNED (p, GLRO (dl_pagesize))))
    {
      void *q = PTR_ALIGN_UP (p, GLRO (dl_pagesize));
      size -= PTR_DIFF (q, p);
      p = q;
    }

  __madvise (p, size, MADV_HUGEPAGE);
#endif
}


This function is called from multiple malloc paths and both return code
and errno after madvise are ignored and propagated - but malloc returns
success on this path. We are ending with "leaked" errno.

To trigger this issue in cwidget libc that triggers madvise is needed
and kernel without support for hugepages (rpi kernel).

It's fully reproducible on vm with sid arm64 image and kernel recompiled
without hugepages - for my tests I disabled fs and thp.

Relevant gdb session:

(gdb) b toplevel.cc:485     # line from 1st snippet: pthread_testcancel();
(gdb) r
(gdb) bt
#0  cwidget::toplevel::input_thread::operator() (this=<optimized out>) at ./src/cwidget/toplevel.cc:485
#1  0x0000fffff7b863d8 in cwidget::threads::bootstrap_proxy<cwidget::toplevel::input_thread>::operator() (this=<synthetic pointer>)
    at ../../src/cwidget/generic/threads/threads.h:902
#2  cwidget::threads::thread::bootstrap<cwidget::threads::bootstrap_proxy<cwidget::toplevel::input_thread> > (p=<optimized out>)
    at ../../src/cwidget/generic/threads/threads.h:118
#3  0x0000fffff7279988 in start_thread (arg=0xfffff66a3f20) at ./nptl/pthread_create.c:454
#4  0x0000fffff72e1f1c in thread_start () at ../sysdeps/unix/sysv/linux/aarch64/clone3.S:75
(gdb) p result
$3 = 0
(gdb) p errno
$4 = 22

>From this point there is only one path that ends with
post_event(new fatal_input_error(errno));


-- 

Paweł Jasiak



More information about the Aptitude-devel mailing list