NetBSD Problem Report #59567

From www@netbsd.org  Thu Jul 31 13:39:09 2025
Return-Path: <www@netbsd.org>
Received: from mail.netbsd.org (mail.netbsd.org [199.233.217.200])
	(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
	 key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256
	 client-signature RSA-PSS (2048 bits) client-digest SHA256)
	(Client CN "mail.NetBSD.org", Issuer "mail.NetBSD.org CA" (not verified))
	by mollari.NetBSD.org (Postfix) with ESMTPS id B785C1A923C
	for <gnats-bugs@gnats.NetBSD.org>; Thu, 31 Jul 2025 13:39:09 +0000 (UTC)
Message-Id: <20250731133908.7914C1A923E@mollari.NetBSD.org>
Date: Thu, 31 Jul 2025 13:39:08 +0000 (UTC)
From: sagawa.aki+nbsd@gmail.com
Reply-To: sagawa.aki+nbsd@gmail.com
To: gnats-bugs@NetBSD.org
Subject: dladdr(3) doesn't work properly especially when main executable is loaded at high memory address
X-Send-Pr-Version: www-1.0

>Number:         59567
>Category:       lib
>Synopsis:       dladdr(3) doesn't work properly especially when main executable is loaded at high memory address
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    riastradh
>State:          closed
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Thu Jul 31 13:40:01 +0000 2025
>Closed-Date:    Sat Jun 27 20:05:53 +0000 2026
>Last-Modified:  Sat Jun 27 20:05:53 +0000 2026
>Originator:     Akihiro Sagawa
>Release:        NetBSD 10.1
>Organization:
>Environment:
NetBSD xiaolan.local 10.1 NetBSD 10.1 (GENERIC) #0: Mon Dec 16 13:08:11 UTC 2024  mkrepro@mkrepro.NetBSD.org:/usr/src/sys/arch/i386/compile/GENERIC i386
>Description:
I'm trying to run Wine on NetBSD/i386. When using ALSA lib (alisa-lib
and alsa-plugins-oss) to play a wav audio file, wine complains with the
following message and no sound is output.
> ALSA lib conf.c:4029:(snd_config_hooks_call) Cannot open shared library (null) (mmap of executable at correct address failed)
> ALSA lib conf.c:4658:(snd_config_update_r) hooks failed, removing configuration

Upon investigating the issue, I found that dladdr(3) appears to be the
source of the problem.

My Investigation:
_rtld_obj_from_addr function, called from dladdr(3), traverses
_rtld_objlist and returns the Obj_Entry object which satisfies
mapbase < addr < (mapbase + mapsize). However, the main executable's
mapsize is currently broken and has too large value. Thus, its result is
the main executable object. As a result, given addr is incorrectly
interpreted as belonging to the main executable rather than another shared library.
>How-To-Repeat:
As the compilation procedure for Wine is highly involved, a simplified
example is presented below.

[demo.c]----------------------------------------------------------------
#include <stdio.h>
#include <dlfcn.h>

int main(int argc, char* argv[])
{
  Dl_info dlinfo;
  int ret;

  ret = dladdr(printf, &dlinfo);
  printf("ret=%d, name=%s\n", ret, dlinfo.dli_fname);

  return 0;
}
------------------------------------------------------------------------

To compile the file, run:
% gcc -fno-plt -g -O -Wl,-Ttext-segment=0x78000000 -o demo demo.c

Expected Result:
% $PWD/demo
ret=1, name=/usr/lib/libc.so.12

Actual Result:
% $PWD/demo
ret=1, name=/home/sagawa/dladdr/demo

Debug procedure:
% gdb ./demo
(gdb) b dladdr
Function "dladdr" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 1 (dladdr) pending.
(gdb) run
Starting program: /home/sagawa/dladdr/demo 

Breakpoint 1, dladdr (addr=0xb138a557 <printf>, info=0xbfb4753c)
    at /usr/src/libexec/ld.elf_so/rtld.c:1339
1339    {
(gdb) info proc mappings 
process 7029
Mapped address spaces:

        Start Addr   End Addr       Size     Offset   Flags   File
        0x78000000 0x78001000     0x1000        0x0  r-x C-PD /home/sagawa/dladdr/demo
        0x78001000 0x78002000     0x1000        0x0  rw- C-PD
(*snip*)
(gdb) p/x _rtld_objlist->mapsize
$1 = 0x78001000
mapsize should be 0x1000 at this point as shown in gdb's "info proc mapping" Size column.
>Fix:
Here is the proposed patch for NetBSD-current which fixes the main executable's mapsize in _rtld_objlist.
Otherwise, the value of obj->vaddrbase is zero when the line "size =
roundup(vaddr + ph->p_memsz) - obj->vaddrbase;" is executed at the first time.

Index: ld.elf_so/headers.c
===================================================================
RCS file: /cvsroot/src/libexec/ld.elf_so/headers.c,v
retrieving revision 1.75
diff -u -r1.75 headers.c
--- ld.elf_so/headers.c	2 May 2025 23:03:16 -0000	1.75
+++ ld.elf_so/headers.c	31 Jul 2025 12:33:07 -0000
@@ -551,14 +551,15 @@
 			break;

 		case PT_LOAD:
-			size = round_up(vaddr + ph->p_memsz) - obj->vaddrbase;
 			if (first_seg) {	/* First load segment */
 				obj->vaddrbase = round_down(vaddr);
 				obj->mapbase = (caddr_t)(uintptr_t)obj->vaddrbase;
+				size = round_up(vaddr + ph->p_memsz) - obj->vaddrbase;
 				obj->textsize = size;
 				obj->mapsize = size;
 				first_seg = false;
 			} else {		/* Last load segment */
+				size = round_up(vaddr + ph->p_memsz) - obj->vaddrbase;
 				obj->mapsize = MAX(obj->mapsize, size);
 			}
 			dbg(("headers: %s %p phsize %" PRImemsz,

>Release-Note:

>Audit-Trail:

State-Changed-From-To: open->analyzed
State-Changed-By: riastradh@NetBSD.org
State-Changed-When: Sun, 03 Aug 2025 19:58:28 +0000
State-Changed-Why:
Problem has been analyzed.  Patch has been provided.

Need:
[x] automatic test to exercise the bug
[x] fix in HEAD once testbed confirms test xfails
[ ] pullup-9, [ ] pullup-10, [ ] pullup-11

We appear to have absolutely no direct tests of dladdr(3).  Closest
we have is tests of libexecinfo's backtrace_symbols_fmt, which calls
dladdr(3), in tests/lib/libexecinfo.  We could add a variant
libexecinfo test with -fno-plt -Ttext-segment=<high> to trigger this,
but we should also have some direct tests of dladdr(3).

Rather than relying on -fno-plt -Ttext-segment=<high> and using
dladdr's search as a proxy, I wonder if obj->mapsize or obj->textsize
is exposed more directly anywhere else like dlinfo(3) RTLD_DI_LINKMAP
which we could compare to the PT_LOAD segment obtained by
dl_iterate_phdr(3).

(Writing down all the analogous linker arguments for each
architecture, and verifying they exercise the bug, sounds like a
pain!)


From: "Taylor R Campbell" <riastradh@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc: 
Subject: PR/59567 CVS commit: src
Date: Sun, 14 Dec 2025 23:26:12 +0000

 Module Name:	src
 Committed By:	riastradh
 Date:		Sun Dec 14 23:26:12 UTC 2025

 Modified Files:
 	src/distrib/sets/lists/debug: mi
 	src/distrib/sets/lists/tests: mi
 	src/tests/libexec/ld.elf_so: Makefile
 Added Files:
 	src/tests/libexec/ld.elf_so: t_dladdr.c

 Log Message:
 dl_addr(3): Add some automatic tests.

 XXX Should also test the libc stubs, maybe move this into
 tests/lib/libc/dlfcn and test both static and (for MKPIC=yes)
 dynamic, but this'll do for now.

 PR lib/59567: dladdr(3) doesn't work properly especially when main
 executable is loaded at high memory address


 To generate a diff of this commit:
 cvs rdiff -u -r1.492 -r1.493 src/distrib/sets/lists/debug/mi
 cvs rdiff -u -r1.1403 -r1.1404 src/distrib/sets/lists/tests/mi
 cvs rdiff -u -r1.30 -r1.31 src/tests/libexec/ld.elf_so/Makefile
 cvs rdiff -u -r0 -r1.1 src/tests/libexec/ld.elf_so/t_dladdr.c

 Please note that diffs are not public domain; they are subject to the
 copyright notices on the relevant files.

Responsible-Changed-From-To: lib-bug-people->riastradh
Responsible-Changed-By: riastradh@NetBSD.org
Responsible-Changed-When: Sun, 14 Dec 2025 23:44:24 +0000
Responsible-Changed-Why:
I'll take it


From: "Taylor R Campbell" <riastradh@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc: 
Subject: PR/59567 CVS commit: src
Date: Mon, 15 Dec 2025 02:36:47 +0000

 Module Name:	src
 Committed By:	riastradh
 Date:		Mon Dec 15 02:36:47 UTC 2025

 Modified Files:
 	src/libexec/ld.elf_so: headers.c
 	src/tests/libexec/ld.elf_so: t_dladdr.c

 Log Message:
 dladdr(3): Fix determination of object address intervals.

 This appears to have been broken in rev. 1.62 back in 2017 with a
 change to compute the largest distance from the first LOAD segment's
 starting address to the maximum address of any LOAD segment -- we
 started by finding the distance from _zero_ to the maximum address of
 the first LOAD segment because we subtracted obj->vaddrbase which
 wasn't initialized yet, so we would overshoot obj->mapsize and
 obj->textsize by whatever the value of obj->vaddrbase turned out to
 be.

 XXX The commit message for 1.62 suggests we are dropping the
 assumption that the LOAD segments appear in order.  But it looks to
 me like we still assume the _first_ load segment has the lowest
 virtual address, because we keep it as obj->vaddrbase/obj->mapbase
 and use it as a reference point for measuring the size of an object
 by subtracting it from each load segment's maximum address.  Is the
 original assumption that LOAD segments appear in order valid after
 all, or do we need to do extra work here to handle objects whose LOAD
 segments are so much out of order that the first LOAD segment isn't
 lowest in virtual address space?  Unclear!

 Might help with wine.

 Based on a patch by Akihiro Sagawa, thanks!

 PR lib/59567: dladdr(3) doesn't work properly especially when main
 executable is loaded at high memory address


 To generate a diff of this commit:
 cvs rdiff -u -r1.75 -r1.76 src/libexec/ld.elf_so/headers.c
 cvs rdiff -u -r1.1 -r1.2 src/tests/libexec/ld.elf_so/t_dladdr.c

 Please note that diffs are not public domain; they are subject to the
 copyright notices on the relevant files.

State-Changed-From-To: analyzed->needs-pullups
State-Changed-By: riastradh@NetBSD.org
State-Changed-When: Mon, 15 Dec 2025 02:41:35 +0000
State-Changed-Why:
needs pullup-9, pullup-10, pullup-11


From: "Martin Husemann" <martin@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc: 
Subject: PR/59567 CVS commit: [netbsd-11] src
Date: Thu, 18 Dec 2025 18:17:32 +0000

 Module Name:	src
 Committed By:	martin
 Date:		Thu Dec 18 18:17:32 UTC 2025

 Modified Files:
 	src/distrib/sets/lists/debug [netbsd-11]: mi
 	src/distrib/sets/lists/tests [netbsd-11]: mi
 	src/libexec/ld.elf_so [netbsd-11]: headers.c
 	src/tests/libexec/ld.elf_so [netbsd-11]: Makefile
 Added Files:
 	src/tests/libexec/ld.elf_so [netbsd-11]: t_dladdr.c

 Log Message:
 Pull up following revision(s) (requested by riastradh in ticket #129):

 	distrib/sets/lists/tests/mi: revision 1.1404
 	libexec/ld.elf_so/headers.c: revision 1.76
 	tests/libexec/ld.elf_so/t_dladdr.c: revision 1.1
 	tests/libexec/ld.elf_so/t_dladdr.c: revision 1.2
 	tests/libexec/ld.elf_so/Makefile: revision 1.31

 	distrib/sets/lists/debug/mi: revision 1.493

 dl_addr(3): Add some automatic tests.

 XXX Should also test the libc stubs, maybe move this into
 tests/lib/libc/dlfcn and test both static and (for MKPIC=yes)
 dynamic, but this'll do for now.

 PR lib/59567: dladdr(3) doesn't work properly especially when main
 executable is loaded at high memory address

 dladdr(3): Fix determination of object address intervals.

 This appears to have been broken in rev. 1.62 back in 2017 with a
 change to compute the largest distance from the first LOAD segment's
 starting address to the maximum address of any LOAD segment -- we
 started by finding the distance from _zero_ to the maximum address of
 the first LOAD segment because we subtracted obj->vaddrbase which
 wasn't initialized yet, so we would overshoot obj->mapsize and
 obj->textsize by whatever the value of obj->vaddrbase turned out to
 be.

 XXX The commit message for 1.62 suggests we are dropping the
 assumption that the LOAD segments appear in order.  But it looks to
 me like we still assume the _first_ load segment has the lowest
 virtual address, because we keep it as obj->vaddrbase/obj->mapbase
 and use it as a reference point for measuring the size of an object
 by subtracting it from each load segment's maximum address.  Is the
 original assumption that LOAD segments appear in order valid after
 all, or do we need to do extra work here to handle objects whose LOAD
 segments are so much out of order that the first LOAD segment isn't
 lowest in virtual address space?  Unclear!

 Might help with wine.
 Based on a patch by Akihiro Sagawa, thanks!

 PR lib/59567: dladdr(3) doesn't work properly especially when main
 executable is loaded at high memory address


 To generate a diff of this commit:
 cvs rdiff -u -r1.485.2.5 -r1.485.2.6 src/distrib/sets/lists/debug/mi
 cvs rdiff -u -r1.1387.2.4 -r1.1387.2.5 src/distrib/sets/lists/tests/mi
 cvs rdiff -u -r1.75 -r1.75.2.1 src/libexec/ld.elf_so/headers.c
 cvs rdiff -u -r1.28.2.2 -r1.28.2.3 src/tests/libexec/ld.elf_so/Makefile
 cvs rdiff -u -r0 -r1.2.2.2 src/tests/libexec/ld.elf_so/t_dladdr.c

 Please note that diffs are not public domain; they are subject to the
 copyright notices on the relevant files.

State-Changed-From-To: needs-pullups->pending-pullups
State-Changed-By: riastradh@NetBSD.org
State-Changed-When: Fri, 26 Jun 2026 18:41:58 +0000
State-Changed-Why:
fixed in HEAD
pullup-11 #129 https://releng.netbsd.org/cgi-bin/req-11.cgi?show=129
pullup-10 #1291 https://releng.netbsd.org/cgi-bin/req-10.cgi?show=1291
pullup-9 #2021 https://releng.netbsd.org/cgi-bin/req-9.cgi?show=2021


From: "Martin Husemann" <martin@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc: 
Subject: PR/59567 CVS commit: [netbsd-10] src
Date: Sat, 27 Jun 2026 19:55:35 +0000

 Module Name:	src
 Committed By:	martin
 Date:		Sat Jun 27 19:55:35 UTC 2026

 Modified Files:
 	src/distrib/sets/lists/debug [netbsd-10]: mi
 	src/distrib/sets/lists/tests [netbsd-10]: mi
 	src/libexec/ld.elf_so [netbsd-10]: headers.c
 	src/tests/libexec/ld.elf_so [netbsd-10]: Makefile
 Added Files:
 	src/tests/libexec/ld.elf_so [netbsd-10]: t_dladdr.c

 Log Message:
 Pull up following revision(s) (requested by riastradh in ticket #1291):

 	distrib/sets/lists/tests/mi: revision 1.1404
 	libexec/ld.elf_so/headers.c: revision 1.76
 	tests/libexec/ld.elf_so/t_dladdr.c: revision 1.1
 	tests/libexec/ld.elf_so/t_dladdr.c: revision 1.2
 	tests/libexec/ld.elf_so/Makefile: revision 1.31
 	distrib/sets/lists/debug/mi: revision 1.493

 dl_addr(3): Add some automatic tests.

 XXX Should also test the libc stubs, maybe move this into
 tests/lib/libc/dlfcn and test both static and (for MKPIC=yes)
 dynamic, but this'll do for now.
 PR lib/59567: dladdr(3) doesn't work properly especially when main
 executable is loaded at high memory address

 dladdr(3): Fix determination of object address intervals.

 This appears to have been broken in rev. 1.62 back in 2017 with a
 change to compute the largest distance from the first LOAD segment's
 starting address to the maximum address of any LOAD segment -- we
 started by finding the distance from _zero_ to the maximum address of
 the first LOAD segment because we subtracted obj->vaddrbase which
 wasn't initialized yet, so we would overshoot obj->mapsize and
 obj->textsize by whatever the value of obj->vaddrbase turned out to
 be.

 XXX The commit message for 1.62 suggests we are dropping the
 assumption that the LOAD segments appear in order.  But it looks to
 me like we still assume the _first_ load segment has the lowest
 virtual address, because we keep it as obj->vaddrbase/obj->mapbase
 and use it as a reference point for measuring the size of an object
 by subtracting it from each load segment's maximum address.  Is the
 original assumption that LOAD segments appear in order valid after
 all, or do we need to do extra work here to handle objects whose LOAD
 segments are so much out of order that the first LOAD segment isn't
 lowest in virtual address space?  Unclear!

 Might help with wine.

 Based on a patch by Akihiro Sagawa, thanks!
 PR lib/59567: dladdr(3) doesn't work properly especially when main
 executable is loaded at high memory address


 To generate a diff of this commit:
 cvs rdiff -u -r1.394.2.17 -r1.394.2.18 src/distrib/sets/lists/debug/mi
 cvs rdiff -u -r1.1238.2.21 -r1.1238.2.22 src/distrib/sets/lists/tests/mi
 cvs rdiff -u -r1.70.2.1 -r1.70.2.2 src/libexec/ld.elf_so/headers.c
 cvs rdiff -u -r1.12.4.2 -r1.12.4.3 src/tests/libexec/ld.elf_so/Makefile
 cvs rdiff -u -r0 -r1.2.4.2 src/tests/libexec/ld.elf_so/t_dladdr.c

 Please note that diffs are not public domain; they are subject to the
 copyright notices on the relevant files.

From: "Martin Husemann" <martin@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc: 
Subject: PR/59567 CVS commit: [netbsd-9] src
Date: Sat, 27 Jun 2026 20:01:09 +0000

 Module Name:	src
 Committed By:	martin
 Date:		Sat Jun 27 20:01:09 UTC 2026

 Modified Files:
 	src/distrib/sets/lists/debug [netbsd-9]: mi
 	src/distrib/sets/lists/tests [netbsd-9]: mi
 	src/libexec/ld.elf_so [netbsd-9]: headers.c
 	src/tests/libexec/ld.elf_so [netbsd-9]: Makefile
 Added Files:
 	src/tests/libexec/ld.elf_so [netbsd-9]: t_dladdr.c

 Log Message:
 Pull up following revision(s) (requested by riastradh in ticket #2021):

 	distrib/sets/lists/tests/mi: revision 1.1404
 	libexec/ld.elf_so/headers.c: revision 1.76
 	tests/libexec/ld.elf_so/t_dladdr.c: revision 1.1
 	tests/libexec/ld.elf_so/t_dladdr.c: revision 1.2
 	tests/libexec/ld.elf_so/Makefile: revision 1.31
 	distrib/sets/lists/debug/mi: revision 1.493

 dl_addr(3): Add some automatic tests.

 XXX Should also test the libc stubs, maybe move this into
 tests/lib/libc/dlfcn and test both static and (for MKPIC=yes)
 dynamic, but this'll do for now.
 PR lib/59567: dladdr(3) doesn't work properly especially when main
 executable is loaded at high memory address

 dladdr(3): Fix determination of object address intervals.

 This appears to have been broken in rev. 1.62 back in 2017 with a
 change to compute the largest distance from the first LOAD segment's
 starting address to the maximum address of any LOAD segment -- we
 started by finding the distance from _zero_ to the maximum address of
 the first LOAD segment because we subtracted obj->vaddrbase which
 wasn't initialized yet, so we would overshoot obj->mapsize and
 obj->textsize by whatever the value of obj->vaddrbase turned out to
 be.

 XXX The commit message for 1.62 suggests we are dropping the
 assumption that the LOAD segments appear in order.  But it looks to
 me like we still assume the _first_ load segment has the lowest
 virtual address, because we keep it as obj->vaddrbase/obj->mapbase
 and use it as a reference point for measuring the size of an object
 by subtracting it from each load segment's maximum address.  Is the
 original assumption that LOAD segments appear in order valid after
 all, or do we need to do extra work here to handle objects whose LOAD
 segments are so much out of order that the first LOAD segment isn't
 lowest in virtual address space?  Unclear!

 Might help with wine.

 Based on a patch by Akihiro Sagawa, thanks!
 PR lib/59567: dladdr(3) doesn't work properly especially when main
 executable is loaded at high memory address


 To generate a diff of this commit:
 cvs rdiff -u -r1.285.2.11 -r1.285.2.12 src/distrib/sets/lists/debug/mi
 cvs rdiff -u -r1.818.2.9 -r1.818.2.10 src/distrib/sets/lists/tests/mi
 cvs rdiff -u -r1.65.2.2 -r1.65.2.3 src/libexec/ld.elf_so/headers.c
 cvs rdiff -u -r1.10.2.2 -r1.10.2.3 src/tests/libexec/ld.elf_so/Makefile
 cvs rdiff -u -r0 -r1.2.6.2 src/tests/libexec/ld.elf_so/t_dladdr.c

 Please note that diffs are not public domain; they are subject to the
 copyright notices on the relevant files.

State-Changed-From-To: pending-pullups->closed
State-Changed-By: riastradh@NetBSD.org
State-Changed-When: Sat, 27 Jun 2026 20:05:53 +0000
State-Changed-Why:
fixed in HEAD, pulled up to 11, 10, and 9


>Unformatted:

NetBSD Home
NetBSD PR Database Search

(Contact us) $NetBSD: query-full-pr,v 1.51 2026/08/10 02:28:17 riastradh Exp $
$NetBSD: gnats_config.sh,v 1.10 2026/05/13 22:00:09 riastradh Exp $
Copyright © 1994-2026 The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.