Update copyright to LGPL on all files
[dyninst.git] / testsuite / src / dyninst / test_fork_13.C
1 /*
2  * Copyright (c) 1996-2009 Barton P. Miller
3  * 
4  * We provide the Paradyn Parallel Performance Tools (below
5  * described as "Paradyn") on an AS IS basis, and do not warrant its
6  * validity or performance.  We reserve the right to update, modify,
7  * or discontinue this software at any time.  We shall have no
8  * obligation to supply such updates or modifications or any other
9  * form of support to you.
10  * 
11  * By your use of Paradyn, you understand and agree that we (or any
12  * other person or entity with proprietary rights in Paradyn) are
13  * under no obligation to provide either maintenance services,
14  * update services, notices of latent defects, or correction of
15  * defects for Paradyn.
16  * 
17  * This library is free software; you can redistribute it and/or
18  * modify it under the terms of the GNU Lesser General Public
19  * License as published by the Free Software Foundation; either
20  * version 2.1 of the License, or (at your option) any later version.
21  * 
22  * This library is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
25  * Lesser General Public License for more details.
26  * 
27  * You should have received a copy of the GNU Lesser General Public
28  * License along with this library; if not, write to the Free Software
29  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
30  */
31
32 // $Id: test_fork_13.C,v 1.1 2008/10/30 19:21:34 legendre Exp $
33 /*
34  * #Name: test7_9
35  * #Desc: Memory deallocate in parent
36  * #Arch: all
37  * #Dep: 
38  */
39
40 #include "BPatch.h"
41 #include "BPatch_Vector.h"
42 #include "BPatch_thread.h"
43 #include "BPatch_snippet.h"
44
45 #include "test_lib.h"
46 #include "test_lib_test7.h"
47
48 #include "dyninst_comp.h"
49 class test_fork_13_Mutator : public DyninstMutator {
50 private:
51   BPatch *bpatch;
52
53 public:
54   virtual bool hasCustomExecutionPath() { return true; }
55   virtual test_results_t setup(ParameterDict &param);
56   virtual test_results_t executeTest();
57 };
58 extern "C" DLLEXPORT TestMutator *test_fork_13_factory() {
59   return new test_fork_13_Mutator();
60 }
61
62 static bool parentDone;
63 static bool childDone;
64 static bool passedTest;
65 static BPatch_thread *parentThread;
66 static BPatch_thread *childThread;
67 static int msgid;
68
69
70 // FIXME This comment is inconsistent.  Figure out what this test is really
71 // doing and clear it up.
72 /* Verify that if a variable in the parent process is freed with 
73    BPatch_thread::free, the corresponding variable in the child process
74    isn't also deleted.
75
76    parent/child: malloc a variable
77    parent/child: oneTimeCode(snippetA)  (malloced variable = 10)
78    --- fork ---
79    child:  insert snippet B  (malloced_var += 5);
80    parent: free(getInheritedVariable(malloced_var))
81
82    --- run  ---
83    parent: verify malloced_var = 15
84    (no way to verify the child variable has indeed been freed)
85 */
86
87 static BPatch_variableExpr *var7_9p;
88 static BPatch_variableExpr *var7_9c;
89
90 static void prepareTestCase9(procType proc_type, BPatch_thread *thread, forkWhen when)
91 {
92
93    if(proc_type == Parent_p  &&  when == PreFork) {
94       BPatch_image *parImage = thread->getImage();
95       var7_9p = thread->malloc(*(parImage->findType("int")));
96       if(doError(&passedTest, (var7_9p==NULL),
97                  "  Unable to malloc variable in parent\n")) return;
98
99       BPatch_arithExpr a_expr7_9p(BPatch_assign, *var7_9p,
100                                   BPatch_constExpr(10));
101       thread->oneTimeCode(a_expr7_9p);
102    } else if(proc_type == Parent_p  &&  when == PostFork) {
103       // can't delete var7_9p here, since then the getInheritedVariable
104       // would be operating on a freed variable
105    } else if(proc_type == Child_p  &&  when == PostFork) {
106       var7_9c = thread->getInheritedVariable(*var7_9p);
107       parentThread->free(*var7_9p);
108
109       BPatch_image *childImage = thread->getImage();
110
111       BPatch_Vector<BPatch_function *> found_funcs;
112       const char *inFunction = "test_fork_13_func1";
113       if ((NULL == childImage->findFunction(inFunction, found_funcs, 1)) || !found_funcs.size()) {
114         logerror("    Unable to find function %s\n",
115                 inFunction);
116         exit(1);
117       }
118       
119       if (1 < found_funcs.size()) {
120         logerror("%s[%d]:  WARNING  : found %d functions named %s.  Using the first.\n", 
121                 __FILE__, __LINE__, found_funcs.size(), inFunction);
122       }
123       
124       BPatch_Vector<BPatch_point *> *points7_9c = found_funcs[0]->findPoint(BPatch_entry);
125
126       if(doError(&passedTest, !points7_9c || ((*points7_9c).size() == 0),
127                  "  Unable to find entry point to \"test_fork_13_func1\".\n")) return;
128       BPatch_point *point7_9c = (*points7_9c)[0];
129
130       BPatch_arithExpr a_expr7_9c(BPatch_plus, *var7_9c, BPatch_constExpr(5));
131       BPatch_arithExpr b_expr7_9c(BPatch_assign, *var7_9c, a_expr7_9c);
132
133       thread->insertSnippet(b_expr7_9c, *point7_9c, BPatch_callBefore);
134    }
135 }
136
137 static void checkTestCase9(procType proc_type, BPatch_thread */*thread*/) {
138    char varname[50];
139    sprintf(varname,"test%d malloced var",9);
140
141    if(proc_type == Child_p) {
142       if(! verifyProcMemory(varname, var7_9c, 15, proc_type)) {
143          passedTest = false;
144       }
145    }
146 }
147
148 /* We make changes at post-fork */
149 static void postForkFunc(BPatch_thread *parent, BPatch_thread *child)
150 {
151     //dprintf("in postForkFunc\n");
152     /* For later identification */
153     childThread = child;
154     dprintf("Preparing tests on parent\n");
155     prepareTestCase9(Parent_p, parent, PostFork);
156     dprintf("Preparing tests on child\n");
157     prepareTestCase9(Child_p,  child,  PostFork);
158     dprintf("Fork handler finished (parent %p, child %p)\n", parent, child);
159 }
160
161 /* And verify them when they exit */
162 static void exitFunc(BPatch_thread *thread, BPatch_exitType exit_type) {
163     dprintf("Exit func called\n");
164     if (thread == parentThread) {
165         dprintf("Parent exit reached, checking...\n");
166         checkTestCase9(Parent_p, thread);
167         parentDone = true;
168         dprintf("Parent done\n");
169     }
170     else if (thread == childThread) {
171         dprintf("Child exit reached, checking...\n");
172         checkTestCase9(Child_p, thread);
173         dprintf("Child done\n");
174         childDone = true;
175     }
176     else {
177         dprintf("Thread ptr 0x%x, parent 0x%x, child 0x%x\n",
178                 thread, parentThread, childThread);
179         assert(0 && "Unexpected BPatch_thread in exitFunc");
180     }
181     return;
182 }
183
184 static void initialPreparation(BPatch_thread *parent)
185 {
186    //cerr << "in initialPreparation\n";
187    assert(parent->isStopped());
188
189    //cerr << "ok, inserting instr\n";
190    prepareTestCase9(Parent_p, parent, PreFork);
191 }
192
193 static int mutatorTest(BPatch *bpatch, BPatch_thread *appThread)
194 {
195     if ( !setupMessaging(&msgid) )
196     {
197        passedTest = false;
198        return passedTest;
199     }
200
201     parentThread = appThread;
202
203     initialPreparation(parentThread);
204     /* ok, do the fork */;
205     parentThread->continueExecution();
206
207     /* the rest of the execution occurs in postForkFunc() */
208     /* Secondary test: we should not have to manually continue
209        either parent or child at any point */
210
211     while ( !parentThread->isTerminated() ) 
212     {
213        bpatch->waitForStatusChange();
214     }
215
216     // At this point if childThread == NULL the postfork handler failed
217     // to run.  Fail gracefully instead of segfaulting on 
218     // childThread->isTerminated()
219     if (doError(&passedTest, childThread == NULL,
220              "childThread == NULL: postForkFunc must not have run\n") )
221     {
222        return passedTest;
223     }
224     
225     if ( !childThread->isTerminated() )
226     {
227        bpatch->waitForStatusChange();
228     }
229     return passedTest;
230 }
231
232 test_results_t test_fork_13_Mutator::executeTest() {
233   // Initialize global variables
234   parentDone = false;
235   childDone = false;
236   passedTest = true;
237   parentThread = NULL;
238   childThread = NULL;
239   msgid = -1;
240
241   // Register callbacks
242   bpatch->registerPostForkCallback(postForkFunc);
243   bpatch->registerExitCallback(exitFunc);
244
245   bool passed = mutatorTest(bpatch, appThread);
246
247   // Remove callbacks upon test completion
248   bpatch->registerPostForkCallback(NULL);
249   bpatch->registerExitCallback(NULL);
250
251   showFinalResults(passed, 9);
252   if ( passed )
253     return PASSED;
254   else
255     return FAILED;
256 }
257
258 test_results_t test_fork_13_Mutator::setup(ParameterDict &param) {
259 #ifdef os_windows_test
260   return SKIPPED;
261 #else
262   bpatch = (BPatch *)(param["bpatch"]->getPtr());
263   appThread = (BPatch_thread *)(param["appThread"]->getPtr());
264
265   return PASSED;
266 #endif
267 }