clone() prototype

Frank Bergmann <[email protected]> Thu, 23 Feb 2012 13:54:30 +0100 (CET)
Newsgroups gmane.linux.lib.dietlibc
Message-ID <[email protected]>
Hi,

the current prototype of clone() as of 2011-12-20 (sched.h) still seems to
be wrong.

Environment is i386, different kernels and gcc.

dietlibc declares the function prototype of the first argument of clone()
as
  int *(*fn)(void*)
but actually uses
  int (*fn)(void*)
as the following code snippet shows.

$ gcc -Os -Wall -o clonefunctest clonefunctest.c # glibc uses int (*fn)(void *)
$ ./clonefunctest 
child_status=123 wait=Success

$ diet -Os gcc -Os -Wall -o clonefunctest clonefunctest.c  # still return int and not int*
clonefunctest.c: In function ?measure?:
clonefunctest.c:24: warning: return makes pointer from integer without a cast
/opt/diet/lib-i386/libc.a(vprintf.o): In function `vprintf':
vprintf.c:(.text+0x20): warning: warning: the printf functions add several kilobytes of bloat.
$ ./clonefunctest 
child_status=123 wait=Success

$ diet -Os gcc -Os -Wall -o clonefunctest2 clonefunctest2.c  # return int* as declared in sched.h
/opt/diet/lib-i386/libc.a(vprintf.o): In function `vprintf':
vprintf.c:(.text+0x20): warning: warning: the printf functions add several kilobytes of bloat.
$ ./clonefunctest2 
child_status=64 wait=Success

Here the "thread" returns with int* (actually pointer to 123) but the
status is the low byte of the (aligned) address.

$ diff -u clonefunctest.c clonefunctest2.c
--- clonefunctest.c     2012-02-23 13:16:39.000000000 +0100
+++ clonefunctest2.c    2012-02-23 13:16:54.000000000 +0100
@@ -21,7 +21,8 @@
 /* int clone(int (*fn)(void *) */
 int measure(void *notused) {
 #endif
-  return 123;
+  *pglobalint = 123;
+  return pglobalint;
 }
 
 int main(int argc, char *argv[]) {


$ cat clonefunctest.c
#define _GNU_SOURCE
#include <features.h>
#include <stdint.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sched.h>

#define STACKSIZE 4096
static char stack[STACKSIZE];

static int globalint;
static int *pglobalint;

#ifdef __dietlibc__
/* /opt/diet/include/sched.h:int clone(int *(*fn)(void*),void* stack,int flags,void* arg, ...); */
int *measure(void *notused) {
#else
/* int clone(int (*fn)(void *) */
int measure(void *notused) {
#endif
  return 123;
}

int main(int argc, char *argv[]) {
  char *child_stack;
  uint32_t flags;
  int child_status;

  pglobalint = &globalint;
  globalint = 0;
  child_status = -1;

  child_stack = stack + STACKSIZE;
  flags =
    CLONE_FILES |
    CLONE_FS |
    CLONE_VM;
  clone(measure, child_stack, flags, 0);
  /* NOTE: dietlibc defines 'int *(*)(void *)' but glibc defines 'int (*)(void *)' as first arg */
  waitpid(-1, &child_status, __WALL);
  printf("child_status=%d wait=%s\n", WEXITSTATUS(child_status), strerror(errno));
  return 0;
}


Frank

-- 
EDV Frank Bergmann                           Tel.     05221-9249753
LPIC-3 Linux Professional                    Fax      05221-9249754
Pödinghauser Str. 5                          email    [email protected]
32051 Herford                                USt-IdNr DE237314606