segfault in vfscanf(3): clang and __restrict usage

Jean-Sébastien Pédron dumbbell at FreeBSD.org
Tue Apr 24 19:49:32 UTC 2012


-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi everyone,

vfscanf(3) in HEAD (r234606) segfaults when compiled with clang. For
instance, here is a call made in cmake which crashes:
    fscanf(f, "%*[^\n]\n");

The same libc, compiled with GCC, doesn't segfault.

When it encounters a character class, __svfscanf() calls convert_ccl():

static const int suppress;
#define SUPPRESS_PTR    ((void *)&suppress)

static __inline int
convert_ccl(FILE *fp, char * __restrict p, [...])
{
        [...]

        if (p == SUPPRESS_PTR) {
		[...]
	} else {
		[...]
	}

	[...]
}

In this case, there's no argument following the format string, and
convert_ccl is called with p = SUPPRESS_PTR. Therefore, we should
enter the if{} block. But when compiled with clang, we enter the
else{} block (causing the segfault).

I made a small program that shows the problem (attached): it seems to
be related to the __restrict qualifier.

Compiled with GCC:
    ./ptr-comp
    p=0x600ac8 vs. SUPPRESS_PTR=0x600ac8
    p == SUPPRESS_PTR

Compiled with clang:
    ./ptr-comp
    p=0x4007dc vs. SUPPRESS_PTR=0x4007dc
    p != SUPPRESS_PTR -> WRONG

- From what I understand about __restrict, it indicates that the pointer
is the only one pointing to a resource. In vfscanf.c, "suppress" may
be pointed by several pointers at a time, so I think __restrict here
is incorrect. But I'm really not sure I got it right. And I don't know
either if clang behavior is expected.

What do you think?

- -- 
Jean-Sébastien Pédron
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.19 (FreeBSD)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAk+XA8kACgkQa+xGJsFYOlOt9wCffUwQ344hfanDzU27wdgW5C+t
4fYAoKPh26OW/ge+VbLaOMTT/YtUYOwM
=OblW
-----END PGP SIGNATURE-----
-------------- next part --------------
#include <stdio.h>

static const int suppress;
#define SUPPRESS_PTR	((void *)&suppress)

void
func(char * __restrict p)
{

	printf("p=%p vs. SUPPRESS_PTR=%p\n", p, SUPPRESS_PTR);

	if (p == SUPPRESS_PTR)
		printf("p == SUPPRESS_PTR\n");
	else
		printf("p != SUPPRESS_PTR -> WRONG\n");
}

int
main(int argc, char *argv [])
{
	char *p;

	p = SUPPRESS_PTR;
	func(p);

	return (0);
}
-------------- next part --------------
PROG = ptr-comp

.include <bsd.prog.mk>


More information about the freebsd-current mailing list