Update copyright year to 2015 for new files.
[platform/upstream/glibc.git] / dlfcn / tst-rec-dlopen.c
1 /* Test recursive dlopen using malloc hooks.
2    Copyright (C) 2015 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, see
17    <http://www.gnu.org/licenses/>.  */
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <malloc.h>
22 #include <dlfcn.h>
23
24 #define DSO "moddummy1.so"
25 #define FUNC "dummy1"
26
27 #define DSO1 "moddummy2.so"
28 #define FUNC1 "dummy2"
29
30 /* Result of the called function.  */
31 int func_result;
32
33 /* Prototype for my hook.  */
34 void *custom_malloc_hook (size_t, const void *);
35
36 /* Pointer to old malloc hooks.  */
37 void *(*old_malloc_hook) (size_t, const void *);
38
39 /* Call function func_name in DSO dso_name via dlopen.  */
40 void
41 call_func (const char *dso_name, const char *func_name)
42 {
43   int ret;
44   void *dso;
45   int (*func) (void);
46   char *err;
47
48   /* Open the DSO.  */
49   dso = dlopen (dso_name, RTLD_NOW|RTLD_GLOBAL);
50   if (dso == NULL)
51     {
52       err = dlerror ();
53       fprintf (stderr, "%s\n", err);
54       exit (1);
55     }
56   /* Clear any errors.  */
57   dlerror ();
58
59   /* Lookup func.  */
60   *(void **) (&func) = dlsym (dso, func_name);
61   if (func == NULL)
62     {
63       err = dlerror ();
64       if (err != NULL)
65         {
66           fprintf (stderr, "%s\n", err);
67           exit (1);
68         }
69     }
70   /* Call func.  */
71   func_result = (*func) ();
72
73   /* Close the library and look for errors too.  */
74   ret = dlclose (dso);
75   if (ret != 0)
76     {
77       err = dlerror ();
78       fprintf (stderr, "%s\n", err);
79       exit (1);
80     }
81
82 }
83
84 /* Empty hook that does nothing.  */
85 void *
86 custom_malloc_hook (size_t size, const void *caller)
87 {
88   void *result;
89   /* Restore old hooks.  */
90   __malloc_hook = old_malloc_hook;
91   /* First call a function in another library via dlopen.  */
92   call_func (DSO1, FUNC1);
93   /* Called recursively.  */
94   result = malloc (size);
95   /* Restore new hooks.  */
96   __malloc_hook = custom_malloc_hook;
97   return result;
98 }
99
100 static int
101 do_test (void)
102 {
103   /* Save old hook.  */
104   old_malloc_hook = __malloc_hook;
105   /* Install new hook.  */
106   __malloc_hook = custom_malloc_hook;
107
108   /* Bug 17702 fixes two things:
109        * A recursive dlopen unmapping the ld.so.cache.
110        * An assertion that _r_debug is RT_CONSISTENT at entry to dlopen.
111      We can only test the latter. Testing the former requires modifying
112      ld.so.conf to cache the dummy libraries, then running ldconfig,
113      then run the test. If you do all of that (and glibc's test
114      infrastructure doesn't support that yet) then the test will
115      SEGFAULT without the fix. If you don't do that, then the test
116      will abort because of the assert described in detail below.  */
117   call_func (DSO, FUNC);
118
119   /* Restore old hook.  */
120   __malloc_hook = old_malloc_hook;
121
122   /* The function dummy2() is called by the malloc hook. Check to
123      see that it was called. This ensures the second recursive
124      dlopen happened and we called the function in that library.
125      Before the fix you either get a SIGSEGV when accessing mmap'd
126      ld.so.cache data or an assertion failure about _r_debug not
127      beint RT_CONSISTENT.  We don't test for the SIGSEGV since it
128      would require finding moddummy1 or moddummy2 in the cache and
129      we don't have any infrastructure to test that, but the _r_debug
130      assertion triggers.  */
131   printf ("Returned result is %d\n", func_result);
132   if (func_result <= 0)
133     {
134       printf ("FAIL: Function call_func() not called.\n");
135       exit (1);
136     }
137
138   printf ("PASS: Function call_func() called more than once.\n");
139   return 0;
140 }
141
142 #define TEST_FUNCTION do_test ()
143 #include "../test-skeleton.c"