Date: Sat, 1 Jul 2017 19:42:11 -0700 From: Mark Millard <markmi@dsl-only.net> To: Konstantin Belousov <kib@freebsd.org>, FreeBSD PowerPC ML <freebsd-ppc@freebsd.org>, FreeBSD Current <freebsd-current@freebsd.org>, freebsd-hackers@freebsd.org Subject: head -r320521 (e.g.): another powerpc64 problem: programs using fgets crash trying to store address over code instead of into __cleanup_info__ Message-ID: <B203F272-002C-48BE-ADB1-8D03881380C1@dsl-only.net>
next in thread | raw e-mail | index | archive | help
[Note: this is from a amd64 -> powerpc64 cross-build based on system clang 4 instead of gcc 4.2.1. I'm building a gcc 4.2.1 based system currently so that I can test a more standard configuration. But I'm one of the ones that experiments with finding things to report for clang targeting powerpc64 and powerpc.] powerpc64 is having programs crash with an attempt to store addresses over code instead of into __cleanup_info__ when fgets is used. ntpd is an example. As is sshd (although I've looked at its details less). Building up the context for this claim. . . public declaration: struct _pthread_cleanup_info { __uintptr_t pthread_cleanup_pad[8]; }; private declaration: struct pthread_cleanup { struct pthread_cleanup *prev; void (*routine)(void *); void *routine_arg; int onheap; }; ntpd and sshd die with segmentation faults in: void __pthread_cleanup_push_imp(void (*routine)(void *), void *arg, struct _pthread_cleanup_info *info) { struct pthread *curthread =3D _get_curthread(); struct pthread_cleanup *newbuf; newbuf =3D (void *)info; newbuf->routine =3D routine; newbuf->routine_arg =3D arg; newbuf->onheap =3D 0; newbuf->prev =3D curthread->cleanup; curthread->cleanup =3D newbuf; } at the statement: newbuf->routine =3D routine; But it turns out that the bt is like: __pthread_cleanup_push_imp(routine=3D0x507b1248 = <__stdio_cancel_cleanup>, arg=3D0x0, info=3D0x509eaaf4) __pthread_cleanup_push_imp_int(p0=3D0x507b1248,p1=3D0x0) fgets (buf=3D0x51415000 "", n=3D511, fp=3D0x507d4c40) . . . Note the 2 arguments to __pthread_cleanup_push_imp_int when called from fgets but the 3 arguemnts to __pthread_cleanup_push_imp . . . fgets uses FLOCK_CANCELSAFE(fp) : #define FLOCKFILE_CANCELSAFE(fp) = \ { = \ struct _pthread_cleanup_info __cleanup_info__; = \ if (__isthreaded) { = \ _FLOCKFILE(fp); = \ ___pthread_cleanup_push_imp( = \ __stdio_cancel_cleanup, (fp), = \ &__cleanup_info__); = \ } else { = \ ___pthread_cleanup_push_imp( = \ __stdio_cancel_cleanup, NULL, = \ &__cleanup_info__); = \ } = \ { #define FUNLOCKFILE_CANCELSAFE() = \ (void)0; = \ } = \ ___pthread_cleanup_pop_imp(1); = \ } where here the NULL case is in use. 3 arguments. But: STUB_FUNC2(__pthread_cleanup_push_imp, PJT_CLEANUP_PUSH_IMP, void, = void*, void *); which is use of: #define STUB_FUNC2(name, idx, ret, p0_type, p1_type) \ static ret FUNC_EXP(name)(p0_type, p1_type) __used; \ static ret FUNC_INT(name)(p0_type, p1_type) __used; \ WEAK_REF(FUNC_EXP(name), name); \ WEAK_REF(FUNC_INT(name), __CONCAT(_, name)); \ typedef ret (*FUNC_TYPE(name))(p0_type, p1_type); \ static ret FUNC_EXP(name)(p0_type p0, p1_type p1) \ { \ FUNC_TYPE(name) func; \ func =3D (FUNC_TYPE(name))__thr_jtable[idx][0]; \ return (func(p0, p1)); \ } \ static ret FUNC_INT(name)(p0_type p0, p1_type p1) \ { \ FUNC_TYPE(name) func; \ func =3D (FUNC_TYPE(name))__thr_jtable[idx][1]; \ return (func(p0, p1)); \ } so only 2 arguments to func (i.e., __pthread_cleanup_push_imp here). Compared to: ___pthread_cleanup_push_imp( = \ __stdio_cancel_cleanup, NULL, = \ &__cleanup_info__); = \ As a result junk is used instead of &__cleanup_info__. On powerpc64 it happens to be the address of ___pthread_cleanup_push_imp that happens to be in r5 (normally the third argument) at the time. So: newbuf->routine =3D routine; tries to replace the first instruction of ___pthread_cleanup_push_imp . As far as I can tell what should be used is: =20 #define STUB_FUNC3(name, idx, ret, p0_type, p1_type, p2_type) \ static ret FUNC_EXP(name)(p0_type, p1_type, p2_type) __used; \ static ret FUNC_INT(name)(p0_type, p1_type, p2_type) __used; \ WEAK_REF(FUNC_EXP(name), name); \ WEAK_REF(FUNC_INT(name), __CONCAT(_, name)); \ typedef ret (*FUNC_TYPE(name))(p0_type, p1_type, p2_type); \ static ret FUNC_EXP(name)(p0_type p0, p1_type p1, p2_type p2) \ { \ FUNC_TYPE(name) func; \ func =3D (FUNC_TYPE(name))__thr_jtable[idx][0]; \ return (func(p0, p1, p2)); \ } \ static ret FUNC_INT(name)(p0_type p0, p1_type p1, p2_type p2) \ { \ FUNC_TYPE(name) func; \ func =3D (FUNC_TYPE(name))__thr_jtable[idx][1]; \ return (func(p0, p1, p2)); \ } with the p2_type being: struct _pthread_cleanup_info * but I'm not expert in this code. =3D=3D=3D Mark Millard markmi at dsl-only.net
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?B203F272-002C-48BE-ADB1-8D03881380C1>