times(2) misbehaviour

Joakim Tjernlund joakim.tjernlund at transmode.se
Sun Jan 31 21:26:35 UTC 2010


>
> Hello,
>
> after a big bug hunt we also found that the implementation of the
> "times" system call in uClibc 0.9.29/0.9.30 is problematic on some 32
> bits architectures (arm926 in our case); like it was reported 2 years
> ago by Will.
>
> The fact that uClibc considers some Linux sys_times() return values as
> errors makes some user space applications become crazy (Qt in our case):
> when Linux "times" syscall's return value is inside uClibc errors range
> (cf INTERNAL_SYSCALL_ERROR_P macro), uClibc forward a (-1) error code to
> caller. An application may freeze during many seconds (40 if system tick
> is 10ms), if it's event handling relies on times() accuracy. Problem
> occurs after 5 minutes of system's running, when Linux tick timer value
> reaches its limit on 32 bits systems.

Oh yes, been there done that :)
Most arch's has this bug in linux(ppc in recent 2.6 does not).

You can work around that in your app., but one should not have too:
  errno = 0;
  ret = times(NULL); /* Linux can handle NULL */
  /* Workaround broken syscall impl.
   * A bugfix exists for the kernel,
   * 2.6.29 for ppc and possibly some more arch
   */
  if (errno)
    ret = (unsigned long) (-errno);

Not sure I like:
> +  /* Return value (clock_t) -1 signals an error to userspace, but if there
> +     wasn't any, return 0 instead. */
> +  if (ret == (clock_t) -1)
> +    return (clock_t) 0;
this will skip ahead a tick

Does the patch work for times(NULL) too? Perhaps EFAULT
can not be returned in this case?

>
> glibc has a special handling for "times" syscall.
> I have attached a patch that implements times in the same way as glibc.
>
> Could maintainers of uClibc get inspired from that patch and do a
> correction for this problem please ?
>
> Thanks !
> Regards,
> Julien

> > --
> >
> >
>
> Implements "times" syscall like on glibc: only EFAULT is considered as a valid
> error code from Linux kernel.
> To handle architectures that can't distinguish the error from a return value,
> make the application segfault in case of error (== bad struct tms parameter).
>
> Signed-off-by: Julien Boibessot <julien.boibessot at armadeus.com>
>
> Index: uClibc-0.9.29/libc/sysdeps/linux/common/times.c
> ===================================================================
> --- uClibc-0.9.29.orig/libc/sysdeps/linux/common/times.c   2010-01-27 10:15:
> 38.000000000 +0100
> +++ uClibc-0.9.29/libc/sysdeps/linux/common/times.c   2010-01-27 10:49:37.
> 000000000 +0100
> @@ -12,5 +12,39 @@
>
>  libc_hidden_proto(times)
>
> -_syscall1(clock_t, times, struct tms *, buf);
> +clock_t times(struct tms *buf)
> +{
> +  INTERNAL_SYSCALL_DECL (err);
> +  clock_t ret = INTERNAL_SYSCALL (times, err, 1, buf);
> +  if (INTERNAL_SYSCALL_ERROR_P (ret, err)
> +      && __builtin_expect (INTERNAL_SYSCALL_ERRNO (ret, err) == EFAULT, 0))
> +    {
> +      /* This might be an error or not.  For architectures which have
> +         no separate return value and error indicators we cannot
> +         distinguish a return value of -1 from an error.  Do it the
> +         hard way.  We crash applications which pass in an invalid BUF
> +         pointer.  */
> +#define touch(v) \
> +      do {                                                                    \
> +        clock_t temp = v;                                                     \
> +        asm volatile ("" : "+r" (temp));                                      \
> +        v = temp;                                                             \
> +      } while (0)
> +      touch (buf->tms_utime);
> +      touch (buf->tms_stime);
> +      touch (buf->tms_cutime);
> +      touch (buf->tms_cstime);
> +
> +      /* If we come here the tms struct is valid and the kernel did not
> +         return an EFAULT error.  Return the value given by the kernel.  */
> +    }
> +
> +  /* Return value (clock_t) -1 signals an error to userspace, but if there
> +     wasn't any, return 0 instead. */
> +  if (ret == (clock_t) -1)
> +    return (clock_t) 0;
> +
> +  return ret;
> +}
> +
>  libc_hidden_def(times)
> _______________________________________________
> uClibc mailing list
> uClibc at uclibc.org
> http://lists.busybox.net/mailman/listinfo/uclibc



More information about the uClibc mailing list