diff options
Diffstat (limited to 'lib/libc/stdlib')
| -rw-r--r-- | lib/libc/stdlib/Makefile.inc | 4 | ||||
| -rw-r--r-- | lib/libc/stdlib/Symbol.map | 1 | ||||
| -rw-r--r-- | lib/libc/stdlib/exit.3 | 2 | ||||
| -rw-r--r-- | lib/libc/stdlib/malloc/jemalloc/jemalloc.3 | 200 | ||||
| -rw-r--r-- | lib/libc/stdlib/memalignment.3 | 53 | ||||
| -rw-r--r-- | lib/libc/stdlib/memalignment.c | 28 | ||||
| -rw-r--r-- | lib/libc/stdlib/realpath.3 | 12 | ||||
| -rw-r--r-- | lib/libc/stdlib/realpath.c | 14 | ||||
| -rw-r--r-- | lib/libc/stdlib/strfmon.c | 2 |
9 files changed, 283 insertions, 33 deletions
diff --git a/lib/libc/stdlib/Makefile.inc b/lib/libc/stdlib/Makefile.inc index e7b9955b9646..b878a7625e9f 100644 --- a/lib/libc/stdlib/Makefile.inc +++ b/lib/libc/stdlib/Makefile.inc @@ -7,7 +7,7 @@ MISRCS+=C99_Exit.c a64l.c abort.c abs.c atexit.c atof.c atoi.c atol.c atoll.c \ div.c exit.c getenv.c getopt.c getopt_long.c \ getsubopt.c hcreate.c hcreate_r.c hdestroy_r.c heapsort.c heapsort_b.c \ hsearch_r.c imaxabs.c imaxdiv.c \ - insque.c l64a.c labs.c ldiv.c llabs.c lldiv.c lsearch.c \ + insque.c l64a.c labs.c ldiv.c llabs.c lldiv.c lsearch.c memalignment.c \ merge.c mergesort_b.c ptsname.c qsort.c qsort_r.c qsort_r_compat.c \ qsort_s.c quick_exit.c radixsort.c rand.c \ random.c reallocarray.c reallocf.c realpath.c recallocarray.c remque.c \ @@ -35,7 +35,7 @@ MAN+= a64l.3 abort.3 abs.3 atexit.3 atof.3 \ atoi.3 atol.3 at_quick_exit.3 bsearch.3 \ div.3 exit.3 getenv.3 getopt.3 getopt_long.3 getsubopt.3 \ hcreate.3 imaxabs.3 imaxdiv.3 insque.3 labs.3 ldiv.3 llabs.3 lldiv.3 \ - lsearch.3 memory.3 ptsname.3 qsort.3 \ + lsearch.3 memalignment.3 memory.3 ptsname.3 qsort.3 \ quick_exit.3 \ radixsort.3 rand.3 random.3 reallocarray.3 reallocf.3 realpath.3 \ set_constraint_handler_s.3 \ diff --git a/lib/libc/stdlib/Symbol.map b/lib/libc/stdlib/Symbol.map index 53d71bcafb7d..8b7e97c3cbdc 100644 --- a/lib/libc/stdlib/Symbol.map +++ b/lib/libc/stdlib/Symbol.map @@ -132,6 +132,7 @@ FBSD_1.8 { }; FBSD_1.9 { + memalignment; recallocarray; }; diff --git a/lib/libc/stdlib/exit.3 b/lib/libc/stdlib/exit.3 index bfb14c5c9f83..40010e678e5f 100644 --- a/lib/libc/stdlib/exit.3 +++ b/lib/libc/stdlib/exit.3 @@ -104,7 +104,7 @@ may be used to provide more information to the parent process. .Pp The complete .Fa status -value is avaliable as +value is available as .Va si_status member of the .Vt siginfo_t diff --git a/lib/libc/stdlib/malloc/jemalloc/jemalloc.3 b/lib/libc/stdlib/malloc/jemalloc/jemalloc.3 index a4ea3e1f54a9..1c99352a6ae2 100644 --- a/lib/libc/stdlib/malloc/jemalloc/jemalloc.3 +++ b/lib/libc/stdlib/malloc/jemalloc/jemalloc.3 @@ -1,13 +1,13 @@ '\" t .\" Title: JEMALLOC .\" Author: Jason Evans -.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/> -.\" Date: 11/10/2019 +.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/> +.\" Date: 05/06/2022 .\" Manual: User Manual -.\" Source: jemalloc 5.2.1-0-gea6b3e973b477b8061e0076bb257dbd7f3faa756 +.\" Source: jemalloc 5.3.0-0-g54eaed1d8b56b1aa528be3bdd1877e59c56fa90c .\" Language: English .\" -.TH "JEMALLOC" "3" "11/10/2019" "jemalloc 5.2.1-0-gea6b3e973b47" "User Manual" +.TH "JEMALLOC" "3" "05/06/2022" "jemalloc 5.3.0-0-g54eaed1d8b56" "User Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -31,7 +31,7 @@ jemalloc \- general purpose memory allocation functions .SH "LIBRARY" .PP -This manual describes jemalloc 5\&.2\&.1\-0\-gea6b3e973b477b8061e0076bb257dbd7f3faa756\&. More information can be found at the +This manual describes jemalloc 5\&.3\&.0\-0\-g54eaed1d8b56b1aa528be3bdd1877e59c56fa90c\&. More information can be found at the \m[blue]\fBjemalloc website\fR\m[]\&\s-2\u[1]\d\s+2\&. .PP The following configuration options are enabled in libc\*(Aqs built\-in jemalloc: @@ -603,7 +603,7 @@ T} :T{ 8 KiB T}:T{ -[40 KiB, 48 KiB, 54 KiB, 64 KiB] +[40 KiB, 48 KiB, 56 KiB, 64 KiB] T} :T{ 16 KiB @@ -848,6 +848,11 @@ in these cases\&. This option is disabled by default unless is specified during configuration, in which case it is enabled by default\&. .RE .PP +opt\&.cache_oblivious (\fBbool\fR) r\- +.RS 4 +Enable / Disable cache\-oblivious large allocation alignment, for large requests with no alignment constraints\&. If this feature is disabled, all large allocations are page\-aligned as an implementation artifact, which can severely harm CPU cache utilization\&. However, the cache\-oblivious layout comes at the cost of one extra page per large allocation, which in the most extreme case increases physical memory usage for the 16 KiB size class to 20 KiB\&. This option is enabled by default\&. +.RE +.PP opt\&.metadata_thp (\fBconst char *\fR) r\- .RS 4 Controls whether to allow jemalloc to use transparent huge page (THP) for internal metadata (see @@ -859,6 +864,11 @@ uses no THP initially, but may begin to do so when metadata usage reaches certai \(lqdisabled\(rq\&. .RE .PP +opt\&.trust_madvise (\fBbool\fR) r\- +.RS 4 +If true, do not perform runtime check for MADV_DONTNEED, to check that it actually zeros pages\&. The default is disabled on Linux and enabled elsewhere\&. +.RE +.PP opt\&.retain (\fBbool\fR) r\- .RS 4 If true, retain unused virtual memory for later reuse rather than discarding it by calling @@ -990,6 +1000,28 @@ is enabled\&. The default is \(lq\(rq\&. .RE .PP +opt\&.stats_interval (\fBint64_t\fR) r\- +.RS 4 +Average interval between statistics outputs, as measured in bytes of allocation activity\&. The actual interval may be sporadic because decentralized event counters are used to avoid synchronization bottlenecks\&. The output may be triggered on any thread, which then calls +malloc_stats_print()\&. +opt\&.stats_interval_opts +can be combined to specify output options\&. By default, interval\-triggered stats output is disabled (encoded as \-1)\&. +.RE +.PP +opt\&.stats_interval_opts (\fBconst char *\fR) r\- +.RS 4 +Options (the +\fIopts\fR +string) to pass to the +malloc_stats_print() +for interval based statistics printing (enabled through +opt\&.stats_interval)\&. See available options in +malloc_stats_print()\&. Has no effect unless +opt\&.stats_interval +is enabled\&. The default is +\(lq\(rq\&. +.RE +.PP opt\&.junk (\fBconst char *\fR) r\- [\fB\-\-enable\-fill\fR] .RS 4 Junk filling\&. If set to @@ -1046,13 +1078,13 @@ This option is disabled by default\&. opt\&.tcache (\fBbool\fR) r\- .RS 4 Thread\-specific caching (tcache) enabled/disabled\&. When there are multiple threads, each thread uses a tcache for objects up to a certain size\&. Thread\-specific caching allows many allocations to be satisfied without performing any thread synchronization, at the cost of increased memory use\&. See the -opt\&.lg_tcache_max +opt\&.tcache_max option for related tuning information\&. This option is enabled by default\&. .RE .PP -opt\&.lg_tcache_max (\fBsize_t\fR) r\- +opt\&.tcache_max (\fBsize_t\fR) r\- .RS 4 -Maximum size class (log base 2) to cache in the thread\-specific cache (tcache)\&. At a minimum, all small size classes are cached, and at a maximum all large size classes are cached\&. The default maximum is 32 KiB (2^15)\&. +Maximum size class to cache in the thread\-specific cache (tcache)\&. At a minimum, the first size class is cached; and at a maximum, size classes up to 8 MiB can be cached\&. The default maximum is 32 KiB (2^15)\&. As a convenience, this may also be set by specifying lg_tcache_max, which will be taken to be the base\-2 logarithm of the setting of tcache_max\&. .RE .PP opt\&.thp (\fBconst char *\fR) r\- @@ -1091,7 +1123,8 @@ for heap profile format documentation\&. opt\&.prof_prefix (\fBconst char *\fR) r\- [\fB\-\-enable\-prof\fR] .RS 4 Filename prefix for profile dumps\&. If the prefix is set to the empty string, no automatic dumps will occur; this is primarily useful for disabling the automatic final heap dump (which also disables leak reporting, if enabled)\&. The default prefix is -jeprof\&. +jeprof\&. This prefix value can be overridden by +prof\&.prefix\&. .RE .PP opt\&.prof_active (\fBbool\fR) r\- [\fB\-\-enable\-prof\fR] @@ -1129,7 +1162,9 @@ Average interval (log base 2) between memory profile dumps, as measured in bytes <prefix> is controlled by the opt\&.prof_prefix -option\&. By default, interval\-triggered profile dumping is disabled (encoded as \-1)\&. +and +prof\&.prefix +options\&. By default, interval\-triggered profile dumping is disabled (encoded as \-1)\&. .RE .PP opt\&.prof_gdump (\fBbool\fR) r\- [\fB\-\-enable\-prof\fR] @@ -1147,7 +1182,9 @@ function to dump final memory usage to a file named according to the pattern <prefix> is controlled by the opt\&.prof_prefix -option\&. Note that +and +prof\&.prefix +options\&. Note that atexit() may allocate memory during application initialization and then deadlock internally when jemalloc in turn calls atexit(), so this option is not universally usable (though the application can register its own @@ -1161,7 +1198,46 @@ Leak reporting enabled/disabled\&. If enabled, use an \fBatexit\fR(3) function to report memory leaks detected by allocation sampling\&. See the opt\&.prof -option for information on analyzing heap profile output\&. This option is disabled by default\&. +option for information on analyzing heap profile output\&. Works only when combined with +opt\&.prof_final, otherwise does nothing\&. This option is disabled by default\&. +.RE +.PP +opt\&.prof_leak_error (\fBbool\fR) r\- [\fB\-\-enable\-prof\fR] +.RS 4 +Similar to +opt\&.prof_leak, but makes the process exit with error code 1 if a memory leak is detected\&. This option supersedes +opt\&.prof_leak, meaning that if both are specified, this option takes precedence\&. When enabled, also enables +opt\&.prof_leak\&. Works only when combined with +opt\&.prof_final, otherwise does nothing\&. This option is disabled by default\&. +.RE +.PP +opt\&.zero_realloc (\fBconst char *\fR) r\- +.RS 4 +Determines the behavior of +realloc() +when passed a value of zero for the new size\&. +\(lqalloc\(rq +treats this as an allocation of size zero (and returns a non\-null result except in case of resource exhaustion)\&. +\(lqfree\(rq +treats this as a deallocation of the pointer, and returns +\fBNULL\fR +without setting +\fIerrno\fR\&. +\(lqabort\(rq +aborts the process if zero is passed\&. The default is +\(lqfree\(rq +on Linux and Windows, and +\(lqalloc\(rq +elsewhere\&. +.sp +There is considerable divergence of behaviors across implementations in handling this case\&. Many have the behavior of +\(lqfree\(rq\&. This can introduce security vulnerabilities, since a +\fBNULL\fR +return value indicates failure, and the continued validity of the passed\-in pointer (per POSIX and C11)\&. +\(lqalloc\(rq +is safe, but can cause leaks in programs that expect the common behavior\&. Programs intended to be portable and leak\-free cannot assume either behavior, and must therefore never call realloc with a size of 0\&. The +\(lqabort\(rq +option enables these testing this behavior\&. .RE .PP thread\&.arena (\fBunsigned\fR) rw @@ -1182,7 +1258,7 @@ Get a pointer to the the value that is returned by the thread\&.allocated mallctl\&. This is useful for avoiding the overhead of repeated mallctl*() -calls\&. +calls\&. Note that the underlying counter should not be modified by the application\&. .RE .PP thread\&.deallocated (\fBuint64_t\fR) r\- [\fB\-\-enable\-stats\fR] @@ -1196,7 +1272,23 @@ Get a pointer to the the value that is returned by the thread\&.deallocated mallctl\&. This is useful for avoiding the overhead of repeated mallctl*() -calls\&. +calls\&. Note that the underlying counter should not be modified by the application\&. +.RE +.PP +thread\&.peak\&.read (\fBuint64_t\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Get an approximation of the maximum value of the difference between the number of bytes allocated and the number of bytes deallocated by the calling thread since the last call to +thread\&.peak\&.reset, or since the thread\*(Aqs creation if it has not called +thread\&.peak\&.reset\&. No guarantees are made about the quality of the approximation, but jemalloc currently endeavors to maintain accuracy to within one hundred kilobytes\&. +.RE +.PP +thread\&.peak\&.reset (\fBvoid\fR) \-\- [\fB\-\-enable\-stats\fR] +.RS 4 +Resets the counter for net bytes allocated in the calling thread to zero\&. This affects subsequent calls to +thread\&.peak\&.read, but not the values returned by +thread\&.allocated +or +thread\&.deallocated\&. .RE .PP thread\&.tcache\&.enabled (\fBbool\fR) rw @@ -1224,11 +1316,27 @@ Control whether sampling is currently active for the calling thread\&. This is a prof\&.active; both must be active for the calling thread to sample\&. This flag is enabled by default\&. .RE .PP +thread\&.idle (\fBvoid\fR) \-\- +.RS 4 +Hints to jemalloc that the calling thread will be idle for some nontrivial period of time (say, on the order of seconds), and that doing some cleanup operations may be beneficial\&. There are no guarantees as to what specific operations will be performed; currently this flushes the caller\*(Aqs tcache and may (according to some heuristic) purge its associated arena\&. +.sp +This is not intended to be a general\-purpose background activity mechanism, and threads should not wake up multiple times solely to call it\&. Rather, a thread waiting for a task should do a timed wait first, call +thread\&.idle +if no task appears in the timeout interval, and then do an untimed wait\&. For such a background activity mechanism, see +background_thread\&. +.RE +.PP tcache\&.create (\fBunsigned\fR) r\- .RS 4 Create an explicit thread\-specific cache (tcache) and return an identifier that can be passed to the \fBMALLOCX_TCACHE(\fR\fB\fItc\fR\fR\fB)\fR macro to explicitly use the specified cache rather than the automatically managed one that is used by default\&. Each explicit cache can be used by only one thread at a time; the application must assure that this constraint holds\&. +.sp +If the amount of space supplied for storing the thread\-specific cache identifier does not equal +sizeof(\fBunsigned\fR), no thread\-specific cache will be created, no data will be written to the space pointed by +\fIoldp\fR, and +\fI*oldlenp\fR +will be set to 0\&. .RE .PP tcache\&.flush (\fBunsigned\fR) \-w @@ -1634,6 +1742,12 @@ Maximum size supported by this large size class\&. arenas\&.create (\fBunsigned\fR, \fBextent_hooks_t *\fR) rw .RS 4 Explicitly create a new arena outside the range of automatically managed arenas, with optionally specified extent hooks, and return the new arena index\&. +.sp +If the amount of space supplied for storing the arena index does not equal +sizeof(\fBunsigned\fR), no arena will be created, no data will be written to the space pointed by +\fIoldp\fR, and +\fI*oldlenp\fR +will be set to 0\&. .RE .PP arenas\&.lookup (\fBunsigned\fR, \fBvoid*\fR) rw @@ -1666,7 +1780,16 @@ Dump a memory profile to the specified file, or if NULL is specified, to a file <prefix> is controlled by the opt\&.prof_prefix -option\&. +and +prof\&.prefix +options\&. +.RE +.PP +prof\&.prefix (\fBconst char *\fR) \-w [\fB\-\-enable\-prof\fR] +.RS 4 +Set the filename prefix for profile dumps\&. See +opt\&.prof_prefix +for the default setting\&. This can be useful to differentiate profile dumps such as from forked processes\&. .RE .PP prof\&.gdump (\fBbool\fR) rw [\fB\-\-enable\-prof\fR] @@ -1676,7 +1799,9 @@ When enabled, trigger a memory profile dump every time the total virtual memory <prefix> is controlled by the opt\&.prof_prefix -option\&. +and +prof\&.prefix +options\&. .RE .PP prof\&.reset (\fBsize_t\fR) \-w [\fB\-\-enable\-prof\fR] @@ -1752,6 +1877,18 @@ for details)\&. Retained memory is excluded from mapped memory statistics, e\&.g stats\&.mapped\&. .RE .PP +stats\&.zero_reallocs (\fBsize_t\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Number of times that the +realloc() +was called with a non\-\fBNULL\fR +pointer argument and a +\fB0\fR +size argument\&. This is a fundamentally unsafe pattern in portable programs; see +opt\&.zero_realloc +for details\&. +.RE +.PP stats\&.background_thread\&.num_threads (\fBsize_t\fR) r\- [\fB\-\-enable\-stats\fR] .RS 4 Number of @@ -1825,6 +1962,26 @@ is one of the counters in mutex profiling counters\&. .RE .PP +stats\&.mutexes\&.prof_thds_data\&.{counter} (\fBcounter specific type\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Statistics on +\fIprof\fR +threads data mutex (global scope; profiling related)\&. +{counter} +is one of the counters in +mutex profiling counters\&. +.RE +.PP +stats\&.mutexes\&.prof_dump\&.{counter} (\fBcounter specific type\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Statistics on +\fIprof\fR +dumping mutex (global scope; profiling related)\&. +{counter} +is one of the counters in +mutex profiling counters\&. +.RE +.PP stats\&.mutexes\&.reset (\fBvoid\fR) \-\- [\fB\-\-enable\-stats\fR] .RS 4 Reset all mutex profile statistics, including global mutexes, arena mutexes and bin mutexes\&. @@ -2242,7 +2399,7 @@ heap_v2/524288 [\&.\&.\&.] @ 0x5f86da8 0x5f5a1dc [\&.\&.\&.] 0x29e4d4e 0xa200316 0xabb2988 [\&.\&.\&.] t*: 13: 6688 [0: 0] - t3: 12: 6496 [0: ] + t3: 12: 6496 [0: 0] t99: 1: 192 [0: 0] [\&.\&.\&.] @@ -2264,9 +2421,9 @@ to indicate descriptions of the corresponding fields\&. <heap_profile_format_version>/<mean_sample_interval> <aggregate>: <curobjs>: <curbytes> [<cumobjs>: <cumbytes>] [\&.\&.\&.] - <thread_3_aggregate>: <curobjs>: <curbytes>[<cumobjs>: <cumbytes>] + <thread_3_aggregate>: <curobjs>: <curbytes> [<cumobjs>: <cumbytes>] [\&.\&.\&.] - <thread_99_aggregate>: <curobjs>: <curbytes>[<cumobjs>: <cumbytes>] + <thread_99_aggregate>: <curobjs>: <curbytes> [<cumobjs>: <cumbytes>] [\&.\&.\&.] @ <top_frame> <frame> [\&.\&.\&.] <frame> <frame> <frame> [\&.\&.\&.] <backtrace_aggregate>: <curobjs>: <curbytes> [<cumobjs>: <cumbytes>] @@ -2432,7 +2589,8 @@ is not \fInewlen\fR is too large or too small\&. Alternatively, \fI*oldlenp\fR -is too large or too small; in this case as much data as possible are read despite the error\&. +is too large or too small; when it happens, except for a very few cases explicitly documented otherwise, as much data as possible are read despite the error, with the amount of data read being recorded in +\fI*oldlenp\fR\&. .RE .PP ENOENT diff --git a/lib/libc/stdlib/memalignment.3 b/lib/libc/stdlib/memalignment.3 new file mode 100644 index 000000000000..4a2269a82c81 --- /dev/null +++ b/lib/libc/stdlib/memalignment.3 @@ -0,0 +1,53 @@ +.\" +.\" Copyright (c) 2025 Robert Clausecker <fuz@FreeBSD.org> +.\" +.\" SPDX-License-Identifier: BSD-2-Clause +.\" +.Dd November 10, 2025 +.Dt MEMALIGNMENT 3 +.Os +.Sh NAME +.Nm memalignment +.Nd find the memory alignment of an object +.Sh SYNOPSIS +.Lb libc +.In stdlib.h +.Ft size_t +.Fn memalignment "const void *ptr" +.Sh DESCRIPTION +The +.Fn memalignment +function determines the alignment of the object pointed to by +.Fa ptr . +This alignment is a power of\~2, and may be larger than the range +supported by the +.Sy alignof +operator. +The value returned can be compared to the result of +.Sy alignof , +and if it is greater or equal, the alignment requirement of the operand +is satisfied. +.Sh RETURN VALUES +Returns the alignment of +.Fa ptr +as a power of\~2. +If +.Fa ptr +is a null pointer, an alignment of zero is returned. +An alignment of zero indicates that the tested pointer cannot be used to +access an object of any type. +.Sh SEE ALSO +.Xr aligned_alloc 3 , +.Xr posix_memalign 3 +.Sh STANDARDS +The +.Fn memalignment +function conforms to +.St -isoC-2023 . +.Sh HISTORY +The +.Fn memalignment +function was added in +.Fx 15.1. +.Sh AUTHOR +.An Robert Clausecker Aq Mt fuz@FreeBSD.org diff --git a/lib/libc/stdlib/memalignment.c b/lib/libc/stdlib/memalignment.c new file mode 100644 index 000000000000..771ddc2f5253 --- /dev/null +++ b/lib/libc/stdlib/memalignment.c @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2025 Robert Clausecker <fuz@FreeBSD.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <stdint.h> +#include <stdlib.h> + +size_t +memalignment(const void *p) +{ + uintptr_t align; + + if (p == NULL) + return (0); + + align = (uintptr_t)p; + align &= -align; + +#if UINTPTR_MAX > SIZE_MAX + /* if alignment overflows size_t, return maximum possible */ + if (align > SIZE_MAX) + align = SIZE_MAX - SIZE_MAX/2; +#endif + + return (align); +} diff --git a/lib/libc/stdlib/realpath.3 b/lib/libc/stdlib/realpath.3 index 065ba312c2ef..76f40249963b 100644 --- a/lib/libc/stdlib/realpath.3 +++ b/lib/libc/stdlib/realpath.3 @@ -28,7 +28,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd May 11, 2012 +.Dd October 10, 2025 .Dt REALPATH 3 .Os .Sh NAME @@ -108,11 +108,11 @@ and .Xr getcwd 3 . .Sh SEE ALSO .Xr getcwd 3 -.\" .Sh STANDARDS -.\" The -.\" .Fn realpath -.\" function conforms to -.\" .St -p1003.1-2001 . +.Sh STANDARDS +The +.Fn realpath +function conforms to +.St -p1003.1-2001 . .Sh HISTORY The .Fn realpath diff --git a/lib/libc/stdlib/realpath.c b/lib/libc/stdlib/realpath.c index 4c52b73319ab..18f29e95ee6b 100644 --- a/lib/libc/stdlib/realpath.c +++ b/lib/libc/stdlib/realpath.c @@ -49,7 +49,7 @@ realpath1(const char *path, char *resolved) { struct stat sb; char *p, *q; - size_t left_len, resolved_len, next_token_len; + size_t left_len, prev_len, resolved_len, next_token_len; unsigned symlinks; ssize_t slen; char left[PATH_MAX], next_token[PATH_MAX], symlink[PATH_MAX]; @@ -98,6 +98,7 @@ realpath1(const char *path, char *resolved) left_len = 0; } + prev_len = resolved_len; if (resolved[resolved_len - 1] != '/') { if (resolved_len + 1 >= PATH_MAX) { errno = ENAMETOOLONG; @@ -133,8 +134,17 @@ realpath1(const char *path, char *resolved) errno = ENAMETOOLONG; return (NULL); } - if (lstat(resolved, &sb) != 0) + if (lstat(resolved, &sb) != 0) { + /* + * EACCES means the parent directory is not + * readable, while ENOTDIR means the parent + * directory is not a directory. Rewind the path + * to correctly indicate where the error lies. + */ + if (errno == EACCES || errno == ENOTDIR) + resolved[prev_len] = '\0'; return (NULL); + } if (S_ISLNK(sb.st_mode)) { if (symlinks++ > MAXSYMLINKS) { errno = ELOOP; diff --git a/lib/libc/stdlib/strfmon.c b/lib/libc/stdlib/strfmon.c index 68a36a6d5567..230d194233f5 100644 --- a/lib/libc/stdlib/strfmon.c +++ b/lib/libc/stdlib/strfmon.c @@ -106,7 +106,7 @@ vstrfmon_l(char *__restrict s, size_t maxsize, locale_t loc, const char *__restrict format, va_list ap) { char *dst; /* output destination pointer */ - const char *fmt; /* current format poistion pointer */ + const char *fmt; /* current format position pointer */ struct lconv *lc; /* pointer to lconv structure */ char *asciivalue; /* formatted double pointer */ |
