Bug 231517

Summary: fts: causes error in valgrind
Product: Base System Reporter: Nikola Kolev <koue>
Component: kernAssignee: freebsd-bugs (Nobody) <bugs>
Status: New ---    
Severity: Affects Only Me CC: cem, pjfloyd
Priority: ---    
Version: 11.2-STABLE   
Hardware: Any   
OS: Any   

Description Nikola Kolev 2018-09-20 14:38:38 UTC
Hi,

Calling 'fts_close' immediately after 'fts_open' causes error in valgrind:

$ valgrind --track-origins=yes --tool=memcheck --leak-check=yes --show-reachable=yes ./ftstest
==76510== Memcheck, a memory error detector
==76510== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==76510== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==76510== Command: ./ftstest
==76510== 
==76510== Conditional jump or move depends on uninitialised value(s)
==76510==    at 0x4EA2297: fts_close (in /lib/libc.so.7)
==76510==    by 0x4008D9: main (in /root/fts/ftstest)
==76510==  Uninitialised value was created by a heap allocation
==76510==    at 0x4C245B1: malloc (in /usr/local/lib/valgrind/vgpreload_memcheck-amd64-freebsd.so)
==76510==    by 0x4EA1F01: fts_open (in /lib/libc.so.7)
==76510==    by 0x40089E: main (in /root/fts/ftstest)
==76510== 
==76510== 
==76510== HEAP SUMMARY:
==76510==     in use at exit: 0 bytes in 0 blocks
==76510==   total heap usage: 5 allocs, 5 frees, 2,647 bytes allocated
==76510== 
==76510== All heap blocks were freed -- no leaks are possible
==76510== 
==76510== For counts of detected and suppressed errors, rerun with: -v
==76510== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)



ftstest.c
=========

#include <fts.h>
#include <stdio.h>
#include <sys/stat.h>

int
main(void) {
	FTS *fts;
	FTSENT *e;
	char *path = "/etc";
	char * const path_argv[] = { path, NULL };

	if ((fts = fts_open(path_argv, FTS_LOGICAL, NULL)) == NULL) {
		printf("fts_open error: %s\n", path);
		return (1);
	}
	fts_close(fts);
	return (0);
}



If 'fts_read' is called before 'fts_close' no complaints from vagrind.

+	while ((e = fts_read(fts)) != NULL) {
+		printf("name: %s, mtime: %ld\n", e->fts_name, e->fts_statp->st_mtime);
+	}

I don't know if its related but I found same issue in GNU maillist:
https://lists.gnu.org/archive/html/bug-gnulib/2018-05/msg00117.html
Comment 1 Paul Floyd 2022-06-08 19:17:50 UTC
With a debug build of libc I get

==1494== Conditional jump or move depends on uninitialised value(s)
==1494==    at 0x48F29D7: fts_close (lib/libc/gen/fts.c:256)
==1494==    by 0x2019B6: main (ftstest.c:17)
==1494==  Uninitialised value was created by a heap allocation
==1494==    at 0x484CBC4: malloc (vg_replace_malloc.c:397)
==1494==    by 0x48F2606: fts_alloc (lib/libc/gen/fts.c:1022)
==1494==    by 0x48F2606: fts_open (lib/libc/gen/fts.c:195)
==1494==    by 0x20197E: main (ftstest.c:13)

fts_open does this

	struct _fts_private *priv;

	if ((priv = calloc(1, sizeof(*priv))) == NULL)
		return (NULL);

	sp = &priv->ftsp_fts;

	if ((sp->fts_cur = fts_alloc(sp, "", 0)) == NULL)


where the first member of _fts_private is
	FTS		ftsp_fts;
meaning p[riv and sp are equivalent addresses.


And the error code is

	if (sp->fts_cur) {
		for (p = sp->fts_cur; p->fts_level >= FTS_ROOTLEVEL;) { // ERROR


It's what p points to that is not initialized:

gdb) p p
$5 = (FTSENT *) 0x54652d0
(gdb) p sizeof(*p)
$6 = 152
(gdb) mo check_memory defined 0x54652d0 152
Address 0x54652D0 len 152 not defined:
Uninitialised value at 0x54652D0 was created by a heap allocation
==1649==    at 0x484CBC4: malloc (vg_replace_malloc.c:397)
==1649==    by 0x48F2606: fts_alloc (lib/libc/gen/fts.c:1022)
==1649==    by 0x48F2606: fts_open (lib/libc/gen/fts.c:195)
==1649==    by 0x20197E: main (ftstest.c:13)
 Address 0x54652d0 is 0 bytes inside a block of size 377 alloc'd
==1649==    at 0x484CBC4: malloc (vg_replace_malloc.c:397)
==1649==    by 0x48F2606: fts_alloc (lib/libc/gen/fts.c:1022)
==1649==    by 0x48F2606: fts_open (lib/libc/gen/fts.c:195)
==1649==    by 0x20197E: main (ftstest.c:13)

[using vgdb and the monitor command]

As far as I'm concerned it's a bug in fts_open.