ast: fix memleaks detected by ASAN during testing
[scilab.git] / scilab / modules / ast / src / cpp / ast / run_CallExp.hpp
1 /*
2  *  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  *  Copyright (C) 2014 - Scilab Enterprises - Antoine ELIAS
4  *
5  * Copyright (C) 2012 - 2016 - Scilab Enterprises
6  *
7  * This file is hereby licensed under the terms of the GNU GPL v2.0,
8  * pursuant to article 5.3.4 of the CeCILL v.2.1.
9  * This file was originally licensed under the terms of the CeCILL v2.1,
10  * and continues to be available under such terms.
11  * For more information, see the COPYING file which you should have received
12  * along with this program.
13  *
14  */
15
16 //file included in runvisitor.cpp
17 namespace ast {
18
19 template<class T>
20 void RunVisitorT<T>::visitprivate(const CallExp &e)
21 {
22     CoverageInstance::invokeAndStartChrono((void*)&e);
23     types::typed_list outTmp;
24     types::typed_list inTmp;
25     std::vector<std::wstring> vectOptName;
26     std::vector<int> vectNbResult;
27
28     int iRetCount = getExpectedSize();
29     int iSaveExpectedSize = iRetCount;
30
31     //get function arguments
32     exps_t args = e.getArgs();
33     getInputs(e, args, inTmp, vectOptName, vectNbResult);
34
35     // reset expected size for recursive call
36     // ie [a, b] = l(1)(1), where l is a list containing a function with two output argument
37     setExpectedSize(-1);
38     // get function/variable
39     try
40     {
41         e.getName().accept(*this);
42     }
43     catch (ScilabException &)
44     {
45         cleanIn(inTmp, outTmp);
46         CoverageInstance::stopChrono((void*)&e);
47         throw;
48     }
49     setExpectedSize(iSaveExpectedSize);
50
51     types::InternalType* pIT = getResult();
52
53     // pIT can be NULL if one of call return nothing. foo()(1) with foo return nothing.
54     if(pIT == NULL)
55     {
56         clearResult();
57         cleanIn(inTmp, outTmp);
58         std::wostringstream os;
59         os << _W("Cannot extract from nothing.") << std::endl;
60         CoverageInstance::stopChrono((void*)&e);
61         throw ast::InternalError(os.str(), 999, e.getLocation());
62     }
63
64     types::typed_list out;
65     types::typed_list in;
66     types::optional_list opt;
67
68     int iInvokeNbOut = 0;
69     try
70     {
71         // getInvokeNbOut will parse the file in case of macrofile
72         // this could throw an exception
73         iInvokeNbOut = pIT->getInvokeNbOut();
74     }
75     catch (const InternalError& ie)
76     {
77         clearResult();
78         cleanIn(inTmp, outTmp);
79         CoverageInstance::stopChrono((void*)&e);
80         throw ie;
81     }
82
83     // manage case [a,b]=foo() where foo is defined as a=foo()
84     if (iInvokeNbOut != -1 && iInvokeNbOut < iRetCount)
85     {
86         clearResult();
87         cleanIn(inTmp, outTmp);
88         std::wostringstream os;
89         os << _W("Wrong number of output arguments.\n") << std::endl;
90         CoverageInstance::stopChrono((void*)&e);
91         throw ast::InternalError(os.str(), 999, e.getLocation());
92     }
93
94     if (pIT->isCallable())
95     {
96         CoverageInstance::invoke(static_cast<types::Callable *>(pIT));
97     }
98
99     // manage input according the function/variable
100     int iLoop = -1;
101     int iterIn = 0;
102     int iterOptName = 0;
103     for (auto& arg : args)
104     {
105         iLoop++;
106
107         //special case for empty extraction of list ( list()(:) )
108         if (vectNbResult[iLoop] == 0)
109         {
110             continue;
111         }
112
113         //extract implicit list for call()
114         if (pIT->isCallable() || pIT->isUserType())
115         {
116             if (inTmp[iterIn]->isImplicitList())
117             {
118                 types::ImplicitList* pIL = inTmp[iterIn]->getAs<types::ImplicitList>();
119                 if (pIL->isComputable())
120                 {
121                     types::InternalType* pITExtract = pIL->extractFullMatrix();
122                     pITExtract->IncreaseRef();
123                     inTmp[iterIn] = pITExtract;
124                     pIL->DecreaseRef();
125                     pIL->killMe();
126                 }
127             }
128         }
129
130         // management of optional input
131         if (arg->isAssignExp())
132         {
133             if (pIT->hasInvokeOption())
134             {
135                 opt[vectOptName[iterOptName]] = inTmp[iterIn];
136
137                 //in case of macro/macrofile, we have to shift input param
138                 //so add NULL item in in list to keep initial order
139                 if (pIT->isMacro() || pIT->isMacroFile())
140                 {
141                     in.push_back(new types::ListInsert(new types::String(vectOptName[iterOptName].data())));
142                 }
143
144                 iterOptName++;
145                 iterIn++;
146             }
147             else
148             {
149                 in.push_back(inTmp[iterIn++]);
150             }
151
152             continue;
153         }
154
155         // default case
156         for (int i = 0; i < vectNbResult[iLoop]; i++, iterIn++)
157         {
158             in.push_back(inTmp[iterIn]);
159         }
160     }
161
162     try
163     {
164         // Extraction with a List in input argument.
165         // This extraction must be a recursive extract.
166         int iLoopSize = 1;
167         types::List* pListArg = NULL;
168         if (pIT->isCallable() == false && in.size() == 1 && in[0]->isList())
169         {
170             pListArg = in[0]->getAs<types::List>();
171             iLoopSize = pListArg->getSize();
172             cleanOpt(opt, out);
173         }
174
175         setExpectedSize(iSaveExpectedSize);
176
177         // override iRetCount only in relevant cases
178         if (pIT->isCallable() && e.getParent()->isSeqExp())
179         {
180             iRetCount = std::max(0, iRetCount);
181         }
182         else
183         {
184             iRetCount = std::max(1, iRetCount);
185         }
186
187         for (int i = 0; i < iLoopSize; i++)
188         {
189             if (pListArg)
190             {
191                 in[0] = pListArg->get(i);
192
193                 if (in[0]->isList())
194                 {
195                     if (pIT->isCallable())
196                     {
197                         // list used like "varargin"
198                         types::List* pLFuncArgs = in[0]->getAs<types::List>();
199                         types::typed_list input;
200                         for (int j = 0; j < pLFuncArgs->getSize(); j++)
201                         {
202                             input.push_back(pLFuncArgs->get(j));
203                             input.back()->IncreaseRef();
204                         }
205
206                         in = input;
207                     }
208                     else
209                     {
210                         pListArg->DecreaseRef();
211                         pListArg->killMe();
212
213                         std::wostringstream os;
214                         os << _W("Invalid index.\n");
215                         throw ast::InternalError(os.str(), 999, e.getFirstLocation());
216                     }
217                 }
218                 else
219                 {
220                     in[0]->IncreaseRef();
221                 }
222             }
223
224             bool ret = false;
225             if (pIT->isInvokable() == false)
226             {
227                 // call overload
228                 ret = Overload::call(L"%" + pIT->getShortTypeStr() + L"_e", in, iRetCount, out, true);
229             }
230             else
231             {
232                 ret = pIT->invoke(in, opt, iRetCount, out, e);
233                 if (ret == false && pIT->isUserType())
234                 {
235                     // call overload
236                     ret = Overload::call(L"%" + pIT->getShortTypeStr() + L"_e", in, iRetCount, out, true);
237                 }
238             }
239
240             if (ret)
241             {
242                 if (iSaveExpectedSize != -1 && iSaveExpectedSize > out.size())
243                 {
244                     char szError[bsiz];
245                     if (pIT->isCallable())
246                     {
247                         char* strFName = wide_string_to_UTF8(pIT->getAs<types::Callable>()->getName().c_str());
248                         os_sprintf(szError, _("%s: Wrong number of output argument(s): %d expected.\n"), strFName, out.size());
249                         FREE(strFName);
250                     }
251                     else
252                     {
253                         os_sprintf(szError, _("%s: Wrong number of output argument(s): %d expected.\n"), "extract", out.size());
254                     }
255
256                     wchar_t* wError = to_wide_string(szError);
257                     std::wstring err(wError);
258                     FREE(wError);
259                     throw InternalError(err, 999, e.getLocation());
260                 }
261
262                 setExpectedSize(iSaveExpectedSize);
263                 setResult(out);
264                 cleanIn(in, out);
265                 cleanOpt(opt, out);
266
267                 // In case a.b(), getResult contain pIT ("b").
268                 // If out == pIT, do not delete it.
269                 if (getResult() != pIT)
270                 {
271                     // protect element of out in case where
272                     // out contain elements of pIT
273                     for (int i = 0; i < out.size(); i++)
274                     {
275                         out[i]->IncreaseRef();
276                     }
277
278                     pIT->killMe();
279
280                     // unprotect
281                     for (int i = 0; i < out.size(); i++)
282                     {
283                         out[i]->DecreaseRef();
284                     }
285                 }
286
287                 if (pListArg && i + 1 != iLoopSize)
288                 {
289                     pIT = out[0];
290                     out.clear();
291                     setResult(NULL);
292                 }
293             }
294             else
295             {
296                 std::wostringstream os;
297                 os << _W("Invalid index.\n");
298                 throw ast::InternalError(os.str(), 999, e.getFirstLocation());
299             }
300         }
301
302         if (pListArg)
303         {
304             pListArg->DecreaseRef();
305             pListArg->killMe();
306         }
307     }
308     catch (InternalAbort & ia)
309     {
310         setExpectedSize(iSaveExpectedSize);
311         if (pIT != getResult())
312         {
313             pIT->killMe();
314         }
315
316         clearResult();
317         cleanInOut(in, out);
318         cleanOpt(opt, out);
319         CoverageInstance::stopChrono((void*)&e);
320
321         throw ia;
322     }
323     catch (const InternalError& ie)
324     {
325         setExpectedSize(iSaveExpectedSize);
326         if (pIT != getResult())
327         {
328             pIT->killMe();
329         }
330
331         clearResult();
332         cleanInOut(in, out);
333         cleanOpt(opt, out);
334         CoverageInstance::stopChrono((void*)&e);
335
336         throw ie;
337     }
338
339     CoverageInstance::stopChrono((void*)&e);
340 }
341
342 template<class T>
343 void RunVisitorT<T>::visitprivate(const CellCallExp &e)
344 {
345     CoverageInstance::invokeAndStartChrono((void*)&e);
346
347     //get head
348     T execMeCell;
349     try
350     {
351         e.getName().accept(execMeCell);
352     }
353     catch (ScilabException &)
354     {
355         CoverageInstance::stopChrono((void*)&e);
356         throw;
357     }
358
359     if (execMeCell.getResult() != NULL)
360     {
361         //a{xxx} with a variable, extraction
362         types::InternalType *pIT = NULL;
363
364         pIT = execMeCell.getResult();
365
366         if (pIT)
367         {
368
369             if (pIT->isCell() == false)
370             {
371                 CoverageInstance::stopChrono((void*)&e);
372                 throw ast::InternalError(_W("[error] Cell contents reference from a non-cell array object.\n"), 999, e.getFirstLocation());
373             }
374
375             //Create list of indexes
376             ast::exps_t exps = e.getArgs();
377             types::typed_list *pArgs = GetArgumentList(exps);
378
379             if (pArgs->size() == 0)
380             {
381                 // Case a{}
382                 delete pArgs;
383                 std::wostringstream os;
384                 os << _W("Cell : Cannot extract without arguments.\n");
385                 CoverageInstance::stopChrono((void*)&e);
386                 throw ast::InternalError(os.str(), 999, e.getFirstLocation());
387             }
388
389             types::List* pList = pIT->getAs<types::Cell>()->extractCell(pArgs);
390
391             if (pList == NULL)
392             {
393                 delete pArgs;
394                 std::wostringstream os;
395                 os << _W("inconsistent row/column dimensions\n");
396                 //os << ((*e.args_get().begin())->getLocation()).getLocationString() << std::endl;
397                 CoverageInstance::stopChrono((void*)&e);
398                 throw ast::InternalError(os.str(), 999, e.getFirstLocation());
399             }
400
401             if (pList->getSize() == 1)
402             {
403                 types::InternalType* ret = pList->get(0);
404                 setResult(ret);
405
406                 ret->IncreaseRef();
407                 pList->killMe();
408                 ret->DecreaseRef();
409             }
410             else
411             {
412                 setResult(pList);
413             }
414
415
416             //clean pArgs return by GetArgumentList
417             for (int iArg = 0; iArg < (int)pArgs->size(); iArg++)
418             {
419                 (*pArgs)[iArg]->killMe();
420             }
421             delete pArgs;
422         }
423     }
424     else
425     {
426         //result == NULL ,variable doesn't exist :(
427         // Should never be in this case
428         // In worst case variable pointing to function does not exists
429         // visitprivate(SimpleVar) will throw the right exception.
430     }
431     CoverageInstance::stopChrono((void*)&e);
432 }
433
434 void RunVisitor::getInputs(const CallExp& e, exps_t& args, types::typed_list& inTmp, std::vector<std::wstring>& vectOptName, std::vector<int>& vectNbResult)
435 {
436     try
437     {
438         for (auto& arg : args)
439         {
440             int iSize = getExpectedSize();
441             if (arg->isAssignExp())
442             {
443                 AssignExp* pAssign = static_cast<AssignExp*>(arg);
444                 //optional parameter
445                 Exp* pL = &pAssign->getLeftExp();
446                 if (!pL->isSimpleVar())
447                 {
448                     std::wostringstream os;
449                     os << _W("left side of optional parameter must be a variable") << std::endl;
450                     CoverageInstance::stopChrono((void*)&e);
451                     throw ast::InternalError(os.str(), 999, e.getLocation());
452                 }
453
454                 SimpleVar* pVar = pL->getAs<SimpleVar>();
455                 Exp* pR = &pAssign->getRightExp();
456                 // optional parameter have only one output argument
457                 setExpectedSize(1);
458                 try
459                 {
460                     pR->accept(*this);
461                 }
462                 catch (ScilabException &)
463                 {
464                     CoverageInstance::stopChrono((void*)&e);
465                     throw;
466                 }
467                 setExpectedSize(iSize);
468                 types::InternalType* pITR = getResult();
469                 // IncreaseRef to protect opt argument of scope_end delete
470                 // It will be deleted by clear_opt
471                 pITR->IncreaseRef();
472
473                 vectOptName.push_back(pVar->getSymbol().getName());
474                 inTmp.push_back(pITR);
475                 vectNbResult.push_back(1);
476
477                 clearResult();
478                 continue;
479             }
480
481             setExpectedSize(-1);
482             try
483             {
484                 arg->accept(*this);
485             }
486             catch (ScilabException &)
487             {
488                 CoverageInstance::stopChrono((void*)&e);
489                 throw;
490             }
491             setExpectedSize(iSize);
492
493             if (getResult() == NULL)
494             {
495                 //special case for empty extraction of list ( list()(:) )
496                 vectNbResult.push_back(0);
497                 continue;
498             }
499
500             if (isSingleResult())
501             {
502                 inTmp.push_back(getResult());
503                 getResult()->IncreaseRef();
504             }
505             else
506             {
507                 for (int i = 0; i < getResultSize(); i++)
508                 {
509                     types::InternalType * pITArg = getResult(i);
510                     pITArg->IncreaseRef();
511                     inTmp.push_back(pITArg);
512                 }
513             }
514
515             vectNbResult.push_back(getResultSize());
516             clearResult();
517         }
518     }
519     catch (const InternalError& ie)
520     {
521         clearResult();
522         types::typed_list outTmp;
523         cleanIn(inTmp, outTmp);
524         CoverageInstance::stopChrono((void*)&e);
525         throw ie;
526     }
527 }
528 } /* namespace ast */