From f692b05a07a25a92447db3e3428726285e61ff35 Mon Sep 17 00:00:00 2001 From: Olivier Couet Date: Tue, 13 Aug 2013 17:06:24 +0200 Subject: [PATCH 01/20] better marker size --- graf2d/postscript/src/TTeXDump.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graf2d/postscript/src/TTeXDump.cxx b/graf2d/postscript/src/TTeXDump.cxx index fcacf1e768454..4ddc82dd82064 100644 --- a/graf2d/postscript/src/TTeXDump.cxx +++ b/graf2d/postscript/src/TTeXDump.cxx @@ -392,7 +392,7 @@ void TTeXDump::DrawPolyMarker(Int_t n, Double_t *xw, Double_t *yw) } PrintStr("}{\\draw[mark options={color=c,fill=c},mark size="); - PrintStr(Form("%fpt,mark=",14./3*fMarkerSize)); + PrintStr(Form("%fpt,mark=",8./3.33*fMarkerSize)); switch (fMarkerStyle) { case 1 : PrintStr("*"); From fd00cb9315845df524ae6b3cc7530f66063222f5 Mon Sep 17 00:00:00 2001 From: Danilo Piparo Date: Tue, 13 Aug 2013 17:29:59 +0200 Subject: [PATCH 02/20] Fixed bug in arg parsing Some of the dummy options were declared has having an input parameter. This caused some of the Gaudi genreflex commands to fail because some headers were not found, for example Python.h. This was was due to the fact that that inclusion was considered as the parameter of the dummy option. For example: genreflex /build/nightlies/test/Tue/GAUDI/GAUDI_no_reflex/src/GaudiPython/dict/kernel.h -o ../x86_64-slc6-gcc48-opt/dict/GaudiPython/kernel_dict.cpp --no_templatetypedefs -I"/build/nightlies/test/Tue/LCGCMT/LCGCMT_danilo/LCG_Settings/../../../../../experimental/Python/2.7.4/x86_64-slc6-gcc48-opt/include/python2.7" --gccxmlopt='--gccxml-compiler lcg-g++-4.8.1 ' -s=../dict/selection_kernel.xml --gccxmlpath=/build/nightlies/test/Tue/LCGCMT/LCGCMT_danilo/LCG_Settings/../../../../../experimental/gccxml/0.9.0_20120309p2/x86_64-slc6-gcc48-opt/bin --rootmap=GaudiPythonDict.rootmap --rootmap-lib=libGaudiPythonDict -D_GNU_SOURCE -DGAUDI_V20_COMPAT -DBOOST_FILESYSTEM_VERSION=3 -I"/build/nightlies/test/Tue/GAUDI/GAUDI_no_reflex/src/GaudiPython" -I"/build/nightlies/test/Tue/GAUDI/GAUDI_no_reflex/src/InstallArea/x86_64-slc6-gcc48-opt/include" -I"/build/nightlies/test/Tue/LCGCMT/LCGCMT_danilo/LCG_Settings/../../../ROOT/ROOT_today/x86_64-slc6-gcc48-opt/root/include" -I"/build/nightlies/test/Tue/LCGCMT/LCGCMT_danilo/LCG_Settings/../../../ROOT/ROOT_today/x86_64-slc6-gcc48-opt/root/include" -I"/build/nightlies/test/Tue/LCGCMT/LCGCMT_danilo/LCG_Settings/../../../../../experimental/Boost/1.50.0_python2.7/x86_64-slc6-gcc48-opt/include/boost-1_50" -I"/build/nightlies/test/Tue/LCGCMT/LCGCMT_danilo/LCG_Settings/../../../../../experimental/xrootd/3.2.7/x86_64-slc6-gcc48-opt/include" -I"/build/nightlies/test/Tue/LCGCMT/LCGCMT_danilo/LCG_Settings/../../../../../experimental/AIDA/3.2.1/share/src/cpp" -I"/build/nightlies/test/Tue/LCGCMT/LCGCMT_danilo/LCG_Platforms/src" --no_templatetypedefs was declared to require an argument... --- core/utils/src/rootcling.cxx | 102 +++++++++++++++++++---------------- 1 file changed, 55 insertions(+), 47 deletions(-) diff --git a/core/utils/src/rootcling.cxx b/core/utils/src/rootcling.cxx index 0495784f1da42..5e75ddb78882b 100644 --- a/core/utils/src/rootcling.cxx +++ b/core/utils/src/rootcling.cxx @@ -234,7 +234,7 @@ template struct IsPointer { enum { kVal = 0 }; }; namespace std {} using namespace std; namespace genreflex { - bool verbose = false; + bool verbose = true; } #include "TClassEdit.h" @@ -3275,65 +3275,65 @@ unsigned int checkHeadersNames(std::vector& headersNames) } //______________________________________________________________________________ -unsigned int extractArgs(int& argc, char** argv, std::vector& args) +unsigned int extractArgs(int argc, char** argv, std::vector& args) { // Extract the arguments from the command line - + // loop on argv, spot strings which are not preceeded by something // starting with "-" and do not start with "-" - std::vector argsIndeces; +// std::vector argsIndeces; + unsigned int argvCounter=0; for (int i=1;i newArgv (newArgc); - unsigned int argvCounter=0; - for (int i=0;i newArgv (newArgc); +// unsigned int argvCounter=0; +// for (int i=0;i::iterator it = args.begin(); it < args.end();++it){ std::cout << i << ") " << *it << std::endl; ++i; } - + } - - argc=newArgc; - return args.size(); + +// for (int i=0;iarg << std::endl; + optionIndex++; values.push_back(opt->arg); nValues++; } @@ -3603,7 +3607,7 @@ void RiseWarningIfPresent(std::vector& options, if (options[optionIndex]){ ROOT::TMetaUtils::Warning(0, - "*** genereflex: %s are not supported anymore.\n", + "*** genereflex: %s is not supported anymore.\n", descriptor); } } @@ -3823,34 +3827,38 @@ int GenReflex(int argc, char **argv) {NOMEMBERTYPEDEFS, STRING , "" , "no_membertypedefs" , - option::FullArg::Required, + option::FullArg::None, ""}, {NOTEMPLATETYPEDEFS, STRING , "" , "no_templatetypedefs" , - option::FullArg::Required, + option::FullArg::None, ""}, {0,0,0,0,0,0} }; std::vector headersNames; - int originalArgc=argc; - extractArgs(argc,argv,headersNames); // The only args are the headers here + const int originalArgc=argc; + // The only args are the headers here + const int extractedArgs = extractArgs(argc,argv,headersNames); - // skip program name argv[0] if present - int newArgc = argc-(argc>0); - char** newArgv = argv+(argc>0); + const int offset = 1 + extractedArgs; // skip argv[0] and the headers + argc-=offset; + argv+=offset; // Parse the options - option::Stats stats(genreflexUsageDescriptor, newArgc, newArgv); + option::Stats stats(genreflexUsageDescriptor, argc, argv); std::vector options(stats.options_max);// non POD var size arrays are not C++! std::vector buffer(stats.buffer_max); // The 4 is the minimum size of the abbreviation lenght. // For example, --selction_file can be abbreviated with --sele at least. - option::Parser parse(genreflexUsageDescriptor, newArgc, newArgv, &options[0], &buffer[0], 4); + std::cout << "Parsing\n"; + option::Parser parse(genreflexUsageDescriptor, argc, argv, &options[0], &buffer[0], 5); + std::cout << "Parsing END\n"; + if (parse.error()){ ROOT::TMetaUtils::Error(0, "*** genreflex: Argument parsing error!\n"); return 1; From 85a3b013ba566effb12558206d3152ed6c263fd4 Mon Sep 17 00:00:00 2001 From: Danilo Piparo Date: Wed, 14 Aug 2013 08:39:09 +0200 Subject: [PATCH 03/20] Remove unused local typedef to cope with gcc48 warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GCC48 rises warnings when local typedefs are not used, for example: warning: typedef ‘XYZ’ locally defined but not used [-Wunused-local-typedefs] This was spotted compiling root6 in the LCG nightlies. --- math/mathmore/src/GSLMultiFit.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/math/mathmore/src/GSLMultiFit.h b/math/mathmore/src/GSLMultiFit.h index 3713101770403..c40632a84ef6e 100644 --- a/math/mathmore/src/GSLMultiFit.h +++ b/math/mathmore/src/GSLMultiFit.h @@ -108,7 +108,9 @@ class GSLMultiFit { if (npts == 0) return -1; unsigned int npar = funcVec[0].NDim(); - typedef typename std::vector FuncVec; + // Remove unused typedef to remove warning in GCC48 + // http://gcc.gnu.org/gcc-4.8/porting_to.html + // typedef typename std::vector FuncVec; //FuncIt funcIter = funcVec.begin(); fFunc.SetFunction(funcVec, npts, npar); // create solver object From fb277e8b48c52aa5b521754480b9da1ee81dd797 Mon Sep 17 00:00:00 2001 From: Fons Rademakers Date: Wed, 14 Aug 2013 13:06:42 +0200 Subject: [PATCH 04/20] add sqlitetest program. --- test/Makefile | 42 ++++++--- test/sqlitetest.cxx | 208 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 236 insertions(+), 14 deletions(-) create mode 100644 test/sqlitetest.cxx diff --git a/test/Makefile b/test/Makefile index 026c770e6d855..20d8e21b82200 100644 --- a/test/Makefile +++ b/test/Makefile @@ -276,27 +276,36 @@ STRESSHISTO = stressHistogram.$(ObjSuf) STRESSHISTS = stressHistogram.$(SrcSuf) STRESSHIST = stressHistogram$(ExeSuf) +ifeq ($(shell $(RC) --has-sqlite),yes) +SQLITETESTO = sqlitetest.$(ObjSuf) +SQLITETESTS = sqlitetest.$(SrcSuf) +SQLITETEST = sqlitetest$(ExeSuf) +endif + -OBJS = $(EVENTO) $(MAINEVENTO) $(EVENTMTO) $(HWORLDO) $(HSIMPLEO) $(MINEXAMO) \ +OBJS = $(EVENTO) $(MAINEVENTO) $(EVENTMTO) $(HWORLDO) $(HSIMPLEO) \ + $(MINEXAMO) \ $(TSTRINGO) $(TCOLLEXO) $(VVECTORO) $(VMATRIXO) $(VLAZYO) \ $(HELLOO) $(ACLOCKO) $(STRESSO) $(TBENCHO) $(BENCHO) \ $(STRESSSHAPESO) $(TCOLLBMO) $(STRESSGEOMETRYO) $(STRESSLO) \ - $(STRESSGO) $(STRESSSPO) $(TESTBITSO) \ + $(STRESSGO) $(STRESSSPO) $(TESTBITSO) \ $(CTORTUREO) $(QPRANDOMO) $(THREADSO) $(STRESSVECO) \ - $(STRESSMATHO) $(STRESSFITO) $(STRESSHISTOFITO) $(STRESSHEPIXO) \ - $(STRESSENTRYLISTO) $(STRESSROOFITO) $(STRESSROOSTATSO) $(STRESSPROOFO) \ - $(STRESSMATHMOREO) $(STRESSTMVAO) $(STRESSINTERPO) $(STRESSITERO) \ - $(STRESSHISTO) $(STRESSGUIO) - -PROGRAMS = $(EVENT) $(EVENTMTSO) $(HWORLD) $(HSIMPLE) $(MINEXAM) $(TSTRING) \ - $(TCOLLEX) $(TCOLLBM) $(VVECTOR) $(VMATRIX) $(VLAZY) \ - $(HELLOSO) $(ACLOCKSO) $(STRESS) $(TBENCHSO) $(BENCH) \ + $(STRESSMATHO) $(STRESSFITO) $(STRESSHISTOFITO) \ + $(STRESSHEPIXO) $(STRESSENTRYLISTO) $(STRESSROOFITO) \ + $(STRESSROOSTATSO) $(STRESSPROOFO) $(STRESSMATHMOREO) \ + $(STRESSTMVAO) $(STRESSINTERPO) $(STRESSITERO) \ + $(STRESSHISTO) $(STRESSGUIO) $(SQLITETESTO) + +PROGRAMS = $(EVENT) $(EVENTMTSO) $(HWORLD) $(HSIMPLE) $(MINEXAM) \ + $(TSTRING) $(TCOLLEX) $(TCOLLBM) $(VVECTOR) $(VMATRIX) \ + $(VLAZY) $(HELLOSO) $(ACLOCKSO) $(STRESS) $(TBENCHSO) $(BENCH) \ $(STRESSSHAPES) $(STRESSGEOMETRY) $(STRESSL) $(STRESSG) \ $(TESTBITS) $(CTORTURE) $(QPRANDOM) $(THREADS) $(STRESSSP) \ $(STRESSVEC) $(STRESSFIT) $(STRESSHISTOFIT) $(STRESSHEPIX) \ - $(STRESSENTRYLIST) $(STRESSROOFIT) $(STRESSROOSTATS) $(STRESSPROOF) $(STRESSMATH) \ - $(STRESSMATHMORE) $(STRESSTMVA) $(STRESSINTERP) $(STRESSITER) \ - $(STRESSHIST) $(STRESSGUI) + $(STRESSENTRYLIST) $(STRESSROOFIT) $(STRESSROOSTATS) \ + $(STRESSPROOF) $(STRESSMATH) \ + $(STRESSMATHMORE) $(STRESSTMVA) $(STRESSINTERP) $(STRESSITER) \ + $(STRESSHIST) $(STRESSGUI) $(SQLITETEST) OBJS += $(GUITESTO) $(GUIVIEWERO) $(TETRISO) @@ -719,6 +728,11 @@ $(STRESSHIST): $(STRESSHISTO) $(MT_EXE) @echo "$@ done" +$(SQLITETEST): $(SQLITETESTO) + $(LD) $(LDFLAGS) $^ $(LIBS) $(OutPutOpt)$@ + $(MT_EXE) + @echo "$@ done" + clean: @rm -f $(OBJS) $(TRACKMATHSRC) core *Dict.* @@ -726,7 +740,7 @@ distclean: clean -@(mv -f stressRooStats_ref.root stressRooStats_ref.root- >/dev/null 2>&1;true) @rm -f $(PROGRAMS) $(EVENTSO) $(EVENTLIB) *Dict.* *.def *.exp \ *.root *.ps *.so *.lib *.dll *.d *.log .def so_locations \ - files/* *.pcm + files/* *.pcm testdb.sqlite @rm -rf cxx_repository -@(mv -f stressRooStats_ref.root- stressRooStats_ref.root >/dev/null 2>&1;true) -@cd RootShower && $(MAKE) distclean diff --git a/test/sqlitetest.cxx b/test/sqlitetest.cxx new file mode 100644 index 0000000000000..16daf43395af3 --- /dev/null +++ b/test/sqlitetest.cxx @@ -0,0 +1,208 @@ +#include +#include +#include + +#include "TSQLServer.h" +#include "TSQLResult.h" +#include "TSQLRow.h" +#include "TSQLStatement.h" +#include "TTimeStamp.h" +#include "TList.h" + +int main() { + + // Create a new DB called testdb: + TSQLServer *serv=TSQLServer::Connect("sqlite://testdb.sqlite", "", ""); + if (serv == NULL) { + std::cerr << "Connection failed!" << std::endl; + _exit(1); + } + + // First, some debug-checks: + std::cout << "DB: " << serv->GetDB() << std::endl; + std::cout << "DBMS: " << serv->GetDBMS() << std::endl; + std::cout << "HOST: " << serv->GetHost() << std::endl; + std::cout << "PORT: " << serv->GetPort() << std::endl; + std::cout << "Info: " << serv->ServerInfo() << std::endl; + + // Create table: + if ((serv!=0) && serv->IsConnected()) { + // create statement instance + TSQLStatement* stmt = serv->Statement("CREATE TABLE TESTTABLE (ID1 FOO, ID2 FOO, ID3 FOO, ID4 FOO, ID5 FOO, ID6 FOO, ID7 FOO, ID8 FOO, ID9 FOO, ID10 FOO)"); + // process statement + stmt->Process(); + // destroy object + delete stmt; + } + + serv->StartTransaction();//Exec("BEGIN TRANSACTION;"); + + // Fill with data: + TSQLStatement* stmt = serv->Statement("INSERT INTO TESTTABLE (ID1, ID2, ID3, ID4, ID5, ID6, ID7, ID8, ID9, ID10) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?);", 100); + std::cout << "statement pars: " << stmt->GetNumParameters() << std::endl; + + + for (int n=0;n<10;n++) { + if (stmt->NextIteration()) { + stmt->SetInt(0, n); + stmt->SetUInt(1, n); + stmt->SetLong(2, n); + stmt->SetULong64(3, n); + stmt->SetDate(4, 2013,1,n); + stmt->SetTime(5, 1,1,n); + stmt->SetDatime(6, 2013,1,n,1,1,n); + stmt->SetTimestamp(7, 2013,1,1,1,1,n,102+n); + TString foo; + foo.Form("testbinary %d", n); + void *binary=const_cast(foo.Data()); + stmt->SetBinary(8, binary, foo.Length()); + stmt->SetString(9, Form("%d", n), 200); + } + } + + stmt->Process(); + delete stmt; + + serv->Commit(); + + delete serv; + + std::cout << "Testing tool created DB with sample data. Now reopening and selecting all." << std::endl; + + serv=TSQLServer::Connect("sqlite://testdb.sqlite", "", ""); + if (serv == NULL) { + std::cerr << "Connection failed!" << std::endl; + _exit(1); + } + + std::cout << "Select table names:" << std::endl; + TSQLResult *res=serv->GetTables(NULL, NULL); + + int fields=res->GetFieldCount(); + std::cout << "Table list has field count: " << fields << std::endl; + + int rowcount=res->GetRowCount(); + std::cout << "Table list has row count: " << rowcount << std::endl; + + TSQLRow *row=NULL; + while ((row=res->Next()) != NULL) { + for (int i=0; iGetField(i); + TSQLResult *res2=serv->GetColumns(NULL, row->GetField(i), NULL); + if (res2 == NULL) continue; + std::cout << "|"; + int fields2=res2->GetFieldCount(); + std::cout << "Cols: " << fields2 << " "; + TSQLRow *row2=NULL; + while ((row2=res2->Next()) != NULL) { + std::cout << "("; + for (int ii=0; iiGetField(ii) == NULL) continue; + std::cout << row2->GetField(ii) << "|"; + } + std::cout << ")"; + delete row2; + } + } + std::cout << std::endl; + delete row; + } + delete res; + std::cout << std::endl; + + std::cout << "Alternate way using GetTablesList:" << std::endl; + serv->GetTablesList()->Print(); + + std::cout << "Completed listing tables. Now selecting * from testtable, first using Query() and string output:" << std::endl; + row=NULL; + res=serv->Query("SELECT * from TESTTABLE;"); + fields=res->GetFieldCount(); + for (int i=0; iGetFieldName(i) << "|"; + } + std::cout << std::endl; + while ((row=res->Next()) != NULL) { + for (int i=0; iGetField(i) << "|"; + } + std::cout << std::endl; + delete row; + } + delete res; + std::cout << std::endl; + + std::cout << "Now using TSQLStatement-methods with appropriate types:" << std::endl; + + stmt = serv->Statement("SELECT * FROM TESTTABLE;", 100); + // process statement + if (stmt->Process()) { + std::cout << "iteration..." << std::endl; + // store result of statement in buffer + stmt->StoreResult(); + + // display info about selected field + std::cout << "NumFields = " << stmt->GetNumFields() << std::endl; + for (int n=0;nGetNumFields();n++) { + std::cout << "|" << std::setw(19) << stmt->GetFieldName(n) << "|"; + } + std::cout << std::endl; + + // extract rows one after another + while (stmt->NextResultRow()) { + Int_t id1 = stmt->GetInt(0); + std::cout << "|" << std::setw(19) << id1 << "|"; + + UInt_t id2 = stmt->GetUInt(1); + std::cout << "|" << std::setw(19) << id2 << "|"; + + Long_t id3 = stmt->GetLong(2); + std::cout << "|" << std::setw(19) << id3 << "|"; + + ULong64_t id4 = stmt->GetULong64(3); + std::cout << "|" << std::setw(19) << id4 << "|"; + + Int_t year=0, month=0, day=0, hour=0, minute=0, second=0, frac=0; + + stmt->GetDate(4, year, month, day); + TString id5; + id5.Form("%04d-%02d-%02d %02d:%02d:%02d", year, month, day, 0, 0, 0); + std::cout << "|" << std::setw(19) << id5 << "|"; + + stmt->GetTime(5, hour, minute, second); + TString id6; + id6.Form("%04d-%02d-%02d %02d:%02d:%02d", 2000, 01, 01, hour, minute, second); + std::cout << "|" << std::setw(19) << id6 << "|"; + + stmt->GetDatime(6, year, month, day, hour, minute, second); + TString id7; + id7.Form("%04d-%02d-%02d %02d:%02d:%02d", year, month, day, hour, minute, second); + std::cout << "|" << std::setw(19) << id7 << "|"; + + stmt->GetTimestamp(7, year, month, day, hour, minute, second, frac); + TTimeStamp ts(year,month,day,hour,minute,second); + TString id8; + id8.Form("%lu.%d", ts.GetSec(), frac); + std::cout << "|" << std::setw(19) << id8 << "|"; + + void* id9 = new unsigned char[1]; + Long_t binSize=1; + stmt->GetBinary(8, id9, binSize); + char* id9str = new char[binSize+1]; + memcpy(id9str, id9, binSize); + id9str[binSize]='\0'; + std::cout << "|" << std::setw(19) << id9str << "|"; + delete [] (unsigned char*) id9; + delete [] id9str; + + TString id10 = stmt->GetString(9); + std::cout << "|" << std::setw(19) << id10 << "|"; + + std::cout << std::endl; + } + } + delete stmt; + + delete serv; + + return 0; +} From 6096943fb27f56bd0874e32d46cc4bace9993a6e Mon Sep 17 00:00:00 2001 From: Olivier Couet Date: Wed, 14 Aug 2013 17:40:57 +0200 Subject: [PATCH 05/20] Protection added to avoid a Seg Fault on ".q" when SetHistogram is called on a TGraph2D. --- hist/hist/src/TGraph2D.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hist/hist/src/TGraph2D.cxx b/hist/hist/src/TGraph2D.cxx index 20a14c74d0efe..8fbc184ac2b68 100644 --- a/hist/hist/src/TGraph2D.cxx +++ b/hist/hist/src/TGraph2D.cxx @@ -614,7 +614,7 @@ void TGraph2D::Clear(Option_t * /*option = "" */) delete [] fZ; fZ = 0; fSize = fNpoints = 0; - if (fHistogram) { + if (fHistogram && !fUserHisto) { delete fHistogram; fHistogram = 0; } From d503711c425a648d24ef4a3ccd8c2c8e453233a2 Mon Sep 17 00:00:00 2001 From: Baozeng Ding Date: Wed, 14 Aug 2013 20:29:49 +0200 Subject: [PATCH 06/20] Protect the non-null taking functions like strcmp. --- .../NullDerefProtectionTransformer.cpp | 150 +++++++++++++++++- .../NullDerefProtectionTransformer.h | 5 + 2 files changed, 150 insertions(+), 5 deletions(-) diff --git a/interpreter/cling/lib/Interpreter/NullDerefProtectionTransformer.cpp b/interpreter/cling/lib/Interpreter/NullDerefProtectionTransformer.cpp index b287909288d2c..250b04761d88a 100644 --- a/interpreter/cling/lib/Interpreter/NullDerefProtectionTransformer.cpp +++ b/interpreter/cling/lib/Interpreter/NullDerefProtectionTransformer.cpp @@ -57,6 +57,57 @@ extern "C" { using namespace clang; namespace cling { + typedef std::map > nonnull_map_t; + + // NonNullDeclFinder finds the function decls with nonnull attribute args. + class NonNullDeclFinder + : public RecursiveASTVisitor { + private: + Sema* m_Sema; + llvm::SmallVector NonNullDeclNames; + nonnull_map_t NonNullArgIndexs; + + public: + NonNullDeclFinder(Sema* S) : m_Sema(S) {} + const llvm::SmallVector& getDeclNames() { + return NonNullDeclNames; + } + + const nonnull_map_t& getArgIndexs() { + return NonNullArgIndexs; + } + + // Deal with all the call expr in the transaction. + bool VisitCallExpr(CallExpr* TheCall) { + if (FunctionDecl* FDecl = TheCall->getDirectCallee()) { + std::bitset<32> ArgIndexs; + for (specific_attr_iterator + I = FDecl->specific_attr_begin(), + E = FDecl->specific_attr_end(); I != E; ++I) { + NonNullAttr *NonNull = *I; + + // Store all the null attr argument's index into "ArgIndexs". + for (NonNullAttr::args_iterator i = NonNull->args_begin(), + e = NonNull->args_end(); i != e; ++i) + ArgIndexs.set(*i); + } + + if (ArgIndexs.any()) { + + // Get the function decl's name. + llvm::StringRef FName = FDecl->getName(); + + // Store the function decl's name into the vector. + NonNullDeclNames.push_back(FName); + + // Store the function decl's name with its null attr args' indexs + // into the map. + NonNullArgIndexs.insert(std::make_pair(FName, ArgIndexs)); + } + } + return true; // returning false will abort the in-depth traversal. + } + }; NullDerefProtectionTransformer::NullDerefProtectionTransformer(Sema *S) : TransactionTransformer(S), FailBB(0), Builder(0), Inst(0) {} @@ -65,7 +116,6 @@ namespace cling { {} void NullDerefProtectionTransformer::Transform() { - using namespace clang; FunctionDecl* FD = getTransaction()->getWrapperFD(); if (!FD) return; @@ -105,8 +155,39 @@ namespace cling { // Find the function in the module. llvm::Function* F = getTransaction()->getModule()->getFunction(mangledName); - if (F) - runOnFunction(*F); + if (!F) return; + + llvm::IRBuilder<> TheBuilder(F->getContext()); + Builder = &TheBuilder; + runOnFunction(*F); + + NonNullDeclFinder Finder(m_Sema); + + // Find all the function decls with null attribute arguments. + for (size_t Idx = 0; Idx < getTransaction()->size(); ++Idx) { + Transaction::DelayCallInfo I = (*getTransaction())[Idx]; + for (DeclGroupRef::const_iterator J = I.m_DGR.begin(), + JE = I.m_DGR.end(); J != JE; ++J) + if ((*J)->hasBody()) + Finder.TraverseStmt((*J)->getBody()); + } + + const llvm::SmallVector& + FDeclNames = Finder.getDeclNames(); + if (FDeclNames.empty()) return; + + llvm::Module* M = F->getParent(); + + for (llvm::SmallVector::const_iterator + i = FDeclNames.begin(), e = FDeclNames.end(); i != e; ++i) { + const nonnull_map_t& ArgIndexs = Finder.getArgIndexs(); + nonnull_map_t::const_iterator it = ArgIndexs.find(*i); + + if (it != ArgIndexs.end()) { + const std::bitset<32>& ArgNums = it->second; + handleNonNullArgCall(*M, *i, ArgNums); + } + } } llvm::BasicBlock* @@ -115,6 +196,7 @@ namespace cling { llvm::Module* Md = Fn->getParent(); llvm::LLVMContext& ctx = Fn->getContext(); + llvm::BasicBlock::iterator PreInsertInst = Builder->GetInsertPoint(); FailBB = llvm::BasicBlock::Create(ctx, "FailBlock", Fn); Builder->SetInsertPoint(FailBB); @@ -157,6 +239,7 @@ namespace cling { llvm::BranchInst::Create(HandleBB, BB, Cmp, FailBB); llvm::ReturnInst::Create(Fn->getContext(), HandleBB); + Builder->SetInsertPoint(PreInsertInst); return FailBB; } @@ -182,8 +265,6 @@ namespace cling { } bool NullDerefProtectionTransformer::runOnFunction(llvm::Function &F) { - llvm::IRBuilder<> TheBuilder(F.getContext()); - Builder = &TheBuilder; std::vector WorkList; for (llvm::inst_iterator i = inst_begin(F), e = inst_end(F); i != e; ++i) { @@ -195,6 +276,7 @@ namespace cling { for (std::vector::iterator i = WorkList.begin(), e = WorkList.end(); i != e; ++i) { Inst = *i; + Builder->SetInsertPoint(Inst); llvm::LoadInst* I = llvm::cast(*i); // Find all the instructions that uses the instruction I. @@ -243,4 +325,62 @@ namespace cling { } return true; } + + void NullDerefProtectionTransformer::instrumentCallInst(llvm::Instruction* + TheCall, const std::bitset<32>& ArgIndexs) { + llvm::Type* Int8PtrTy = llvm::Type::getInt8PtrTy(TheCall->getContext()); + llvm::CallSite CS = TheCall; + + for (int index = 0; index < 32; ++index) { + if (!ArgIndexs.test(index)) continue; + llvm::Value* Arg = CS.getArgument(index); + if (!Arg) continue; + llvm::Type* ArgTy = Arg->getType(); + if (ArgTy != Int8PtrTy) + continue; + + llvm::BasicBlock* OldBB = TheCall->getParent(); + llvm::ICmpInst* Cmp + = new llvm::ICmpInst(TheCall, llvm::CmpInst::ICMP_EQ, Arg, + llvm::Constant::getNullValue(ArgTy), ""); + + llvm::Instruction* Inst = Builder->GetInsertPoint(); + llvm::BasicBlock* NewBB = OldBB->splitBasicBlock(Inst); + + OldBB->getTerminator()->eraseFromParent(); + llvm::BranchInst::Create(getTrapBB(NewBB), NewBB, Cmp, OldBB); + } + } + + void NullDerefProtectionTransformer::handleNonNullArgCall(llvm::Module& M, + const llvm::StringRef& name, const std::bitset<32>& ArgIndexs) { + + // Get the function by the name. + llvm::Function* func = M.getFunction(name); + if (!func) + return; + + // Find all the instructions that calls the function. + std::vector WorkList; + for (llvm::Value::use_iterator I = func->use_begin(), E = func->use_end(); + I != E; ++I) { + llvm::CallSite CS(*I); + if (!CS || CS.getCalledValue() != func) + continue; + WorkList.push_back(CS.getInstruction()); + } + + // There is no call instructions that call the function and return. + if (WorkList.empty()) + return; + + // Instrument all the call instructions that call the function. + for (std::vector::iterator I = WorkList.begin(), + E = WorkList.end(); I != E; ++I) { + Inst = *I; + Builder->SetInsertPoint(Inst); + instrumentCallInst(Inst, ArgIndexs); + } + return; + } } // end namespace cling diff --git a/interpreter/cling/lib/Interpreter/NullDerefProtectionTransformer.h b/interpreter/cling/lib/Interpreter/NullDerefProtectionTransformer.h index ac2214934e2fa..1d9e54f9ca65f 100644 --- a/interpreter/cling/lib/Interpreter/NullDerefProtectionTransformer.h +++ b/interpreter/cling/lib/Interpreter/NullDerefProtectionTransformer.h @@ -38,6 +38,11 @@ namespace cling { llvm::BasicBlock* getTrapBB(llvm::BasicBlock* BB); void instrumentInst(llvm::Instruction* Inst, llvm::Value* Arg); bool runOnFunction(llvm::Function& F); + void instrumentCallInst(llvm::Instruction* TheCall, + const std::bitset<32>& ArgIndexs); + void handleNonNullArgCall(llvm::Module& M, + const llvm::StringRef& FName, + const std::bitset<32>& ArgIndexs); public: NullDerefProtectionTransformer(clang::Sema* S); From 7337e1a748cae0a951486237fb02cbb5b10a275f Mon Sep 17 00:00:00 2001 From: Baozeng Ding Date: Wed, 14 Aug 2013 20:36:33 +0200 Subject: [PATCH 07/20] Add a simple test testing the new functionality. --- interpreter/cling/test/NullDeref/NonNullArg.C | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 interpreter/cling/test/NullDeref/NonNullArg.C diff --git a/interpreter/cling/test/NullDeref/NonNullArg.C b/interpreter/cling/test/NullDeref/NonNullArg.C new file mode 100644 index 0000000000000..a562e8a77bbc3 --- /dev/null +++ b/interpreter/cling/test/NullDeref/NonNullArg.C @@ -0,0 +1,9 @@ +// RUN: cat %s | %cling -Xclang -verify + +//This file checks a call instruction. The called function has arguments with nonnull attribute. +#include +char *p; +strcmp("a", p); // expected-warning {{you are about to dereference null ptr, which probably will lead to seg violation. Do you want to proceed?[y/n]}} + +strcmp(p, "a"); // expected-warning {{you are about to dereference null ptr, which probably will lead to seg violation. Do you want to proceed?[y/n]}} +.q From 2e28e4391464e9ba52ec528b973cad80be280163 Mon Sep 17 00:00:00 2001 From: Vassil Vassilev Date: Wed, 14 Aug 2013 23:10:10 +0200 Subject: [PATCH 08/20] Mark test as XFAIL. Follow the cling naming convention. --- .../NullDerefProtectionTransformer.cpp | 22 +++++++++---------- interpreter/cling/test/NullDeref/NonNullArg.C | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/interpreter/cling/lib/Interpreter/NullDerefProtectionTransformer.cpp b/interpreter/cling/lib/Interpreter/NullDerefProtectionTransformer.cpp index 250b04761d88a..ed9075642608f 100644 --- a/interpreter/cling/lib/Interpreter/NullDerefProtectionTransformer.cpp +++ b/interpreter/cling/lib/Interpreter/NullDerefProtectionTransformer.cpp @@ -64,17 +64,17 @@ namespace cling { : public RecursiveASTVisitor { private: Sema* m_Sema; - llvm::SmallVector NonNullDeclNames; - nonnull_map_t NonNullArgIndexs; + llvm::SmallVector m_NonNullDeclNames; + nonnull_map_t m_NonNullArgIndexs; public: NonNullDeclFinder(Sema* S) : m_Sema(S) {} - const llvm::SmallVector& getDeclNames() { - return NonNullDeclNames; + const llvm::SmallVector& getDeclNames() const { + return m_NonNullDeclNames; } - const nonnull_map_t& getArgIndexs() { - return NonNullArgIndexs; + const nonnull_map_t& getArgIndexs() const { + return m_NonNullArgIndexs; } // Deal with all the call expr in the transaction. @@ -98,11 +98,11 @@ namespace cling { llvm::StringRef FName = FDecl->getName(); // Store the function decl's name into the vector. - NonNullDeclNames.push_back(FName); + m_NonNullDeclNames.push_back(FName); - // Store the function decl's name with its null attr args' indexs + // Store the function decl's name with its null attr args' indexes // into the map. - NonNullArgIndexs.insert(std::make_pair(FName, ArgIndexs)); + m_NonNullArgIndexs.insert(std::make_pair(FName, ArgIndexs)); } } return true; // returning false will abort the in-depth traversal. @@ -164,7 +164,7 @@ namespace cling { NonNullDeclFinder Finder(m_Sema); // Find all the function decls with null attribute arguments. - for (size_t Idx = 0; Idx < getTransaction()->size(); ++Idx) { + for (size_t Idx = 0, E = getTransaction()->size(); Idx < E; ++Idx) { Transaction::DelayCallInfo I = (*getTransaction())[Idx]; for (DeclGroupRef::const_iterator J = I.m_DGR.begin(), JE = I.m_DGR.end(); J != JE; ++J) @@ -172,7 +172,7 @@ namespace cling { Finder.TraverseStmt((*J)->getBody()); } - const llvm::SmallVector& + const llvm::SmallVector& FDeclNames = Finder.getDeclNames(); if (FDeclNames.empty()) return; diff --git a/interpreter/cling/test/NullDeref/NonNullArg.C b/interpreter/cling/test/NullDeref/NonNullArg.C index a562e8a77bbc3..6975ac32f49ac 100644 --- a/interpreter/cling/test/NullDeref/NonNullArg.C +++ b/interpreter/cling/test/NullDeref/NonNullArg.C @@ -1,5 +1,5 @@ // RUN: cat %s | %cling -Xclang -verify - +//XFAIL:* //This file checks a call instruction. The called function has arguments with nonnull attribute. #include char *p; From afaefebd14ade8996c1571871b4a11f650585536 Mon Sep 17 00:00:00 2001 From: Vassil Vassilev Date: Thu, 15 Aug 2013 10:10:38 +0200 Subject: [PATCH 09/20] Mark back as non-failing. There is still some issue on Mac that need to be investigated. --- interpreter/cling/test/NullDeref/NonNullArg.C | 1 - 1 file changed, 1 deletion(-) diff --git a/interpreter/cling/test/NullDeref/NonNullArg.C b/interpreter/cling/test/NullDeref/NonNullArg.C index 6975ac32f49ac..3a0aa411f468d 100644 --- a/interpreter/cling/test/NullDeref/NonNullArg.C +++ b/interpreter/cling/test/NullDeref/NonNullArg.C @@ -1,5 +1,4 @@ // RUN: cat %s | %cling -Xclang -verify -//XFAIL:* //This file checks a call instruction. The called function has arguments with nonnull attribute. #include char *p; From 16cc6828107db57b430f5fe35956cb96ae3af49f Mon Sep 17 00:00:00 2001 From: Wim Lavrijsen Date: Wed, 14 Aug 2013 20:39:17 -0700 Subject: [PATCH 10/20] a bit of cleanup --- bindings/pyroot/src/TPyClassGenerator.cxx | 8 -------- 1 file changed, 8 deletions(-) diff --git a/bindings/pyroot/src/TPyClassGenerator.cxx b/bindings/pyroot/src/TPyClassGenerator.cxx index 5d879b0617d17..e3d21d8cd5278 100644 --- a/bindings/pyroot/src/TPyClassGenerator.cxx +++ b/bindings/pyroot/src/TPyClassGenerator.cxx @@ -80,10 +80,6 @@ TClass* TPyClassGenerator::GetClass( const char* name, Bool_t load, Bool_t silen std::ostringstream proxyCode; proxyCode << "class " << clName << " {\nprivate:\n PyObject* fPyObject;\npublic:\n"; -/* -// special case: constructor; add method and store callback - PyROOT::Utility::InstallMethod( &gcl, pyclass, clName, 0, "ellipsis", (void*)PyCtorCallback ); -*/ // loop over and add member functions Bool_t hasConstructor = kFALSE; for ( int i = 0; i < PyList_GET_SIZE( attrs ); ++i ) { @@ -139,10 +135,6 @@ TClass* TPyClassGenerator::GetClass( const char* name, Bool_t load, Bool_t silen else proxyCode << " TPyArg::CallConstructor(fPyObject, (PyObject*)" << (void*)pyclass << ", v)"; proxyCode << ";\n }\n"; -/* if ( mtName != "__init__" ) { - PyROOT::Utility::InstallMethod( - &gcl, attr, mtName, "TPyReturn", "ellipsis", (void*)PyMemFuncCallback ); - } */ } // no decref of attr for now (b/c of hard-wired ptr); need cleanup somehow From fb09263fc4f2e1d5029b11a20bda10591ad53e02 Mon Sep 17 00:00:00 2001 From: Wim Lavrijsen Date: Wed, 14 Aug 2013 22:20:22 -0700 Subject: [PATCH 11/20] support for Minuit callbacks into python functions --- bindings/pyroot/src/Pythonize.cxx | 120 ++++++++++++++++-------------- 1 file changed, 63 insertions(+), 57 deletions(-) diff --git a/bindings/pyroot/src/Pythonize.cxx b/bindings/pyroot/src/Pythonize.cxx index be646af6cabf1..8c1882f22ff59 100644 --- a/bindings/pyroot/src/Pythonize.cxx +++ b/bindings/pyroot/src/Pythonize.cxx @@ -1525,6 +1525,31 @@ namespace PyROOT { // workaround for Intel icc on Linux } }; +//- TMinuit behavior ---------------------------------------------------------- + void TMinuitPyCallback( void* vpyfunc, Long_t /* npar */, + Int_t& a0, Double_t* a1, Double_t& a2, Double_t* a3, Int_t a4 ) { + // a void* was passed to keep the interface on builtin types only + PyObject* pyfunc = (PyObject*)vpyfunc; + + // prepare arguments + PyObject* pya0 = BufFac_t::Instance()->PyBuffer_FromMemory( &a0, 1 ); + PyObject* pya1 = BufFac_t::Instance()->PyBuffer_FromMemory( a1, a0 ); + PyObject* pya2 = BufFac_t::Instance()->PyBuffer_FromMemory( &a2, 1 ); + PyObject* pya3 = BufFac_t::Instance()->PyBuffer_FromMemory( a3, -1 ); // size unknown + + // perform actual call + PyObject* result = PyObject_CallFunction( + pyfunc, (char*)"OOOOi", pya0, pya1, pya2, pya3, a4 ); + Py_DECREF( pya3 ); Py_DECREF( pya2 ); Py_DECREF( pya1 ); Py_DECREF( pya0 ); + + if ( ! result ) { + PyErr_Print(); + throw std::runtime_error( "TMinuit python fit function call failed" ); + } + + Py_XDECREF( result ); + } + //- TFN behavior -------------------------------------------------------------- double TFNPyCallback( void* vpyfunc, Long_t npar, double* a0, double* a1 ) { // a void* was passed to keep the interface on builtin types only @@ -1579,49 +1604,6 @@ namespace { return self; } -//- TMinuit behavior ---------------------------------------------------------- -/* TODO: implement for Cling - int TMinuitPyCallback( G__value* res, G__CONST char*, struct G__param* libp, int hash ) - { - // CINT-installable callback function to allow Minuit to call into python. - PyObject* result = 0; - - // retrieve function information - PyObject* pyfunc = PyROOT::Utility::GetInstalledMethod( G__value_get_tagnum(res) ); - if ( ! pyfunc ) - return 0; - - // prepare arguments - PyObject* arg1 = BufFac_t::Instance()->PyBuffer_FromMemory( - G__Intref(&libp->para[0]), 1 ); - int npar = *G__Intref(&libp->para[0]); - - PyObject* arg2 = BufFac_t::Instance()->PyBuffer_FromMemory( - (Double_t*)G__int(libp->para[1]), npar ); - - PyObject* arg3 = BufFac_t::Instance()->PyBuffer_FromMemory( - G__Doubleref(&libp->para[2]), 1 ); - - PyObject* arg4 = BufFac_t::Instance()->PyBuffer_FromMemory( - (Double_t*)G__int(libp->para[3]), -1 ); // size unknown - - // perform actual call - result = PyObject_CallFunction( pyfunc, (char*)"OOOOi", - arg1, arg2, arg3, arg4, (int)G__int(libp->para[4]) ); - Py_DECREF( arg4 ); Py_DECREF( arg3 ); Py_DECREF( arg2 ); Py_DECREF( arg1 ); - - if ( ! result ) { - PyErr_Print(); - throw std::runtime_error( "TMinuit python fit function call failed" ); - } - - Py_XDECREF( result ); - - G__setnull( res ); - return ( 1 || hash || res || libp ); - } - -*/ //____________________________________________________________________________ class TPretendInterpreted: public PyCallable { @@ -1768,7 +1750,6 @@ namespace { //- TMinuit behavior ----------------------------------------------------------- -/* TODO: implement for Cling class TMinuitSetFCN : public TPretendInterpreted { public: TMinuitSetFCN( int nArgs = 1 ) : TPretendInterpreted( nArgs ) {} @@ -1804,22 +1785,51 @@ namespace { if ( pyname != 0 ) name = PyROOT_PyUnicode_AsString( pyname ); - // registration with CINT - Long_t fid = Utility::InstallMethod( 0, pyfunc, name, 0, - "i - - 1 - - D - - 0 - - d - - 1 - - D - - 0 - - i - - 0 - -", - (void*)TMinuitPyCallback, 5 ); - Py_XDECREF( pyname ); + // create signature + std::vector signature; signature.reserve( 5 ); + signature.push_back( "Int_t&" ); + signature.push_back( "Double_t*" ); + signature.push_back( "Double_t&" ); + signature.push_back( "Double_t*" ); + signature.push_back( "Int_t" ); - // get function + // registration with Cling + void* fptr = Utility::CreateWrapperMethod( + pyfunc, 5, "void", signature, "TMinuitPyCallback" ); + if ( ! fptr /* PyErr was set */ ) + return 0; + + // get setter function MethodProxy* method = (MethodProxy*)PyObject_GetAttr( (PyObject*)self, PyStrings::gSetFCN ); + // CLING WORKAROUND: SetFCN(void* fun) is deprecated but for whatever reason + // still available yet not functional; select the correct one based on its + // signature of the full function pointer + PyCallable* setFCN = 0; + const MethodProxy::Methods_t& methods = method->fMethodInfo->fMethods; + for ( MethodProxy::Methods_t::const_iterator im = methods.begin(); im != methods.end(); ++im ) { + PyObject* sig = (*im)->GetSignature(); + if ( strnstr( PyROOT_PyUnicode_AsString( sig ), "Double_t&", + PyROOT_PyUnicode_GET_SIZE( sig ) ) ) { + // the comparison was not exact, but this is just a workaround + setFCN = *im; + Py_DECREF( sig ); + break; + } + Py_DECREF( sig ); + } + // END CLING WORKAROUND + // build new argument array PyObject* newArgs = PyTuple_New( 1 ); - PyTuple_SET_ITEM( newArgs, 0, PyROOT_PyCapsule_New( (void*)fid, NULL, NULL ) ); + PyTuple_SET_ITEM( newArgs, 0, PyROOT_PyCapsule_New( fptr, NULL, NULL ) ); // re-run - PyObject* result = PyObject_CallObject( (PyObject*)method, newArgs ); + // CLING WORKAROUND: this is to be the call once TMinuit is fixed: + // PyObject* result = PyObject_CallObject( (PyObject*)method, newArgs ); + PyObject* result = setFCN->operator()( self, newArgs, NULL ); + // END CLING WORKAROUND // done, may have worked, if not: 0 is returned Py_DECREF( newArgs ); @@ -1856,14 +1866,13 @@ namespace { return TMinuitSetFCN::operator()( self, args, 0, 0, release_gil ); } }; -*/ //- Fit::TFitter behavior ------------------------------------------------------ PyObject* gFitterPyCallback = 0; void FitterPyCallback( int& npar, double* gin, double& f, double* u, int flag ) { - // CINT-callable callback for Fit::Fitter derived objects. + // Cling-callable callback for Fit::Fitter derived objects. PyObject* result = 0; // prepare arguments @@ -1891,7 +1900,6 @@ namespace { Py_XDECREF( result ); } - class TFitterFitFCN : public TPretendInterpreted { public: TFitterFitFCN() : TPretendInterpreted( 2 ) {} @@ -2300,13 +2308,11 @@ Bool_t PyROOT::Pythonize( PyObject* pyclass, const std::string& name ) if ( name == "TFunction" ) // allow direct call return Utility::AddToClass( pyclass, "__call__", (PyCFunction) TFunctionCall ); -/* TODO: implement for Cling if ( name == "TMinuit" ) // allow call with python callable return Utility::AddToClass( pyclass, "SetFCN", new TMinuitSetFCN ); if ( name == "TFitter" ) // allow call with python callable (this is not correct) return Utility::AddToClass( pyclass, "SetFCN", new TMinuitFitterSetFCN ); -*/ if ( name == "Fitter" ) // really Fit::Fitter, allow call with python callable return Utility::AddToClass( pyclass, "FitFCN", new TFitterFitFCN ); From ab8456ebd16f1c43fb4e78678ef118096b4e050e Mon Sep 17 00:00:00 2001 From: Wim Lavrijsen Date: Thu, 15 Aug 2013 01:11:27 -0700 Subject: [PATCH 12/20] Make C++ CPP macros available to python; since this is potentially as slow as it is useless (but cute, and was available in CINT), it has to be enabled using "PyConfig.ExposeCppMacros = True" and are only looked up through the ROOT namespace, not on "from ROOT import *". Note: NULL is made a special case, as it is the most useful macro. --- bindings/pyroot/ROOT.py | 8 ++++++-- bindings/pyroot/src/RootModule.cxx | 19 +++++++++++++++++-- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/bindings/pyroot/ROOT.py b/bindings/pyroot/ROOT.py index a03b5337bbf80..06cef7445e5e1 100755 --- a/bindings/pyroot/ROOT.py +++ b/bindings/pyroot/ROOT.py @@ -132,11 +132,12 @@ def ismethod( object ): ### configuration --------------------------------------------------------------- class _Configuration( object ): - __slots__ = [ 'IgnoreCommandLineOptions', 'StartGuiThread', '_gts' ] + __slots__ = [ 'IgnoreCommandLineOptions', 'StartGuiThread', 'ExposeCppMacros', '_gts' ] def __init__( self ): self.IgnoreCommandLineOptions = 0 self.StartGuiThread = True + self.ExposeCppMacros = False self._gts = [] def __setGTS( self, value ): @@ -455,7 +456,7 @@ def __getattr2( self, name ): # "running" getattr return self.module.__all__ # lookup into ROOT (which may cause python-side enum/class/global creation) - attr = _root.LookupRootEntity( name ) + attr = _root.LookupRootEntity( name, PyConfig.ExposeCppMacros ) # the call above will raise AttributeError as necessary; so if we get here, # attr is valid: cache as appropriate, so we don't come back @@ -564,6 +565,9 @@ def _finishSchedule( ROOT = self ): for name in self.module.__pseudo__all__ + _memPolicyAPI + _sigPolicyAPI: self.__dict__[ name ] = getattr( _root, name ) + # the macro NULL is not available from Cling globals, but might be useful + setattr( _root, 'NULL', 0 ) + for name in std.stlclasses: setattr( _root, name, getattr( std, name ) ) diff --git a/bindings/pyroot/src/RootModule.cxx b/bindings/pyroot/src/RootModule.cxx index 0739dbe6f5df9..c8bfb857fb2f0 100644 --- a/bindings/pyroot/src/RootModule.cxx +++ b/bindings/pyroot/src/RootModule.cxx @@ -24,6 +24,7 @@ // Standard #include +#include //- from Python's dictobject.c ------------------------------------------------- @@ -73,10 +74,10 @@ namespace { PyObject* LookupRootEntity( PyObject* pyname, PyObject* args ) { // Find a match within the ROOT module for something with name 'pyname'. - const char* cname = 0; + const char* cname = 0; long macro_ok = 0; if ( pyname && PyROOT_PyUnicode_CheckExact( pyname ) ) cname = PyROOT_PyUnicode_AsString( pyname ); - else if ( ! ( args && PyArg_ParseTuple( args, const_cast< char* >( "s" ), &cname ) ) ) + else if ( ! ( args && PyArg_ParseTuple( args, const_cast< char* >( "s|l" ), &cname, ¯o_ok ) ) ) return 0; // we may have been destroyed if this code is called during shutdown @@ -111,6 +112,20 @@ namespace { TObject* object = gROOT->FindObject( name.c_str() ); if ( object != 0 ) return BindRootObject( object, object->IsA() ); + + // 5th attempt: check macro's (debatable, but this worked in CINT) + if ( macro_ok ) { + PyErr_Clear(); + std::ostringstream ismacro; + ismacro << "#ifdef " << name << "\n_pyroot_" << name << "=" << name + << ";true;\n#else\nfalse;\n#endif"; + if ( gROOT->ProcessLine( ismacro.str().c_str() ) ) { + // can now retrieve this as a global + attr = GetRootGlobalFromString( "_pyroot_"+name ); + if ( attr != 0 ) + return attr; + } + } } // still here? raise attribute error From f2280748fa2ec75d7494710d0d1052a74ad4a3bd Mon Sep 17 00:00:00 2001 From: Axel Naumann Date: Thu, 15 Aug 2013 11:03:41 +0200 Subject: [PATCH 13/20] Make kMax size constants class members. --- tree/treeplayer/src/TTreePlayer.cxx | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/tree/treeplayer/src/TTreePlayer.cxx b/tree/treeplayer/src/TTreePlayer.cxx index 7da170289083b..6fa8574ed6def 100644 --- a/tree/treeplayer/src/TTreePlayer.cxx +++ b/tree/treeplayer/src/TTreePlayer.cxx @@ -837,6 +837,18 @@ Int_t TTreePlayer::MakeClass(const char *classname, const char *option) chain->LoadTree(0); } + fprintf(fp,"\n"); + if (opt.Contains("selector")) { + fprintf(fp,"class %s : public TSelector {\n",classname); + fprintf(fp,"public :\n"); + fprintf(fp," TTree *fChain; //!pointer to the analyzed TTree or TChain\n"); + } else { + fprintf(fp,"class %s {\n",classname); + fprintf(fp,"public :\n"); + fprintf(fp," TTree *fChain; //!pointer to the analyzed TTree or TChain\n"); + fprintf(fp," Int_t fCurrent; //!current Tree number in a TChain\n"); + } + fprintf(fp,"\n// Fixed size dimensions of array or collections stored in the TTree if any.\n"); leaves = fTree->GetListOfLeaves(); for (l=0;l Date: Thu, 15 Aug 2013 02:35:24 -0700 Subject: [PATCH 14/20] fix build error on Linux --- bindings/pyroot/src/Pythonize.cxx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bindings/pyroot/src/Pythonize.cxx b/bindings/pyroot/src/Pythonize.cxx index 8c1882f22ff59..248352f64d40a 100644 --- a/bindings/pyroot/src/Pythonize.cxx +++ b/bindings/pyroot/src/Pythonize.cxx @@ -35,9 +35,11 @@ // Standard #include #include -#include #include +#include +#include // only needed for Cling TMinuit workaround + namespace { From 306dcff30a86a631da271225e8d73772071fde0d Mon Sep 17 00:00:00 2001 From: Wim Lavrijsen Date: Thu, 15 Aug 2013 02:53:56 -0700 Subject: [PATCH 15/20] strnstr -> strstr as the former is non-standard (thanks Bertrand!) remove an unused variable --- bindings/pyroot/src/Pythonize.cxx | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/bindings/pyroot/src/Pythonize.cxx b/bindings/pyroot/src/Pythonize.cxx index 248352f64d40a..ecb052267bd1d 100644 --- a/bindings/pyroot/src/Pythonize.cxx +++ b/bindings/pyroot/src/Pythonize.cxx @@ -1781,12 +1781,6 @@ namespace { if ( ! IsCallable( pyfunc ) ) return 0; - // use callable name (if available) as identifier - PyObject* pyname = PyObject_GetAttr( pyfunc, PyStrings::gName ); - const char* name = "dummy"; - if ( pyname != 0 ) - name = PyROOT_PyUnicode_AsString( pyname ); - // create signature std::vector signature; signature.reserve( 5 ); signature.push_back( "Int_t&" ); @@ -1812,8 +1806,7 @@ namespace { const MethodProxy::Methods_t& methods = method->fMethodInfo->fMethods; for ( MethodProxy::Methods_t::const_iterator im = methods.begin(); im != methods.end(); ++im ) { PyObject* sig = (*im)->GetSignature(); - if ( strnstr( PyROOT_PyUnicode_AsString( sig ), "Double_t&", - PyROOT_PyUnicode_GET_SIZE( sig ) ) ) { + if ( strstr( PyROOT_PyUnicode_AsString( sig ), "Double_t&" ) ) { // the comparison was not exact, but this is just a workaround setFCN = *im; Py_DECREF( sig ); From d4a3ee4a670e95b60724c74e7ade57a92f8d10a7 Mon Sep 17 00:00:00 2001 From: Olivier Couet Date: Thu, 15 Aug 2013 12:20:02 +0200 Subject: [PATCH 16/20] Release notes update --- hist/doc/v600/index.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hist/doc/v600/index.md b/hist/doc/v600/index.md index cc4f7b16449c5..33786288f5ac8 100644 --- a/hist/doc/v600/index.md +++ b/hist/doc/v600/index.md @@ -158,6 +158,8 @@ `TGraph2D` after a `Clear` is performed. - In `GetHistogram()` the lower and higher axis limits are always different. +- Protection added to avoid a Seg Fault on `.q` when `SetHistogram()` + is called on a `TGraph2D`. ### TF1 From f8ef51a3e10cc11154b6a60211915c9f0e77e720 Mon Sep 17 00:00:00 2001 From: Olivier Couet Date: Thu, 15 Aug 2013 13:08:54 +0200 Subject: [PATCH 17/20] In TGraph2DPainter::PaintLevels the colour levels used to paint the triangles did not match the minimum and maximum set by the user on the TGraph2D. --- hist/hist/inc/TGraph2D.h | 2 ++ hist/histpainter/src/TGraph2DPainter.cxx | 12 ++++++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/hist/hist/inc/TGraph2D.h b/hist/hist/inc/TGraph2D.h index b21a33c4d9f54..e1b16149ba737 100644 --- a/hist/hist/inc/TGraph2D.h +++ b/hist/hist/inc/TGraph2D.h @@ -113,6 +113,8 @@ class TGraph2D : public TNamed, public TAttLine, public TAttFill, public TAttMar virtual Double_t GetErrorY(Int_t bin) const; virtual Double_t GetErrorZ(Int_t bin) const; Double_t GetMargin() const {return fMargin;} + Double_t GetMaximum() const {return fMaximum;}; + Double_t GetMinimum() const {return fMinimum;}; TAxis *GetXaxis() const ; TAxis *GetYaxis() const ; TAxis *GetZaxis() const ; diff --git a/hist/histpainter/src/TGraph2DPainter.cxx b/hist/histpainter/src/TGraph2DPainter.cxx index 04bbd4c9eeaa9..e683acf711e56 100644 --- a/hist/histpainter/src/TGraph2DPainter.cxx +++ b/hist/histpainter/src/TGraph2DPainter.cxx @@ -589,8 +589,12 @@ void TGraph2DPainter::PaintLevels(Int_t *t,Double_t *x, Double_t *y, Double_t x0 = x[0] , x2 = x[0]; Double_t y0 = y[0] , y2 = y[0]; Double_t z0 = fZ[p0], z2 = fZ[p0]; - Double_t zmin = fZmin; - Double_t zmax = fZmax; + Double_t zmin = fGraph2D->GetMinimum(); + Double_t zmax = fGraph2D->GetMaximum(); + if (zmin==-1111 && zmax==-1111) { + zmin = fZmin; + zmax = fZmax; + } // Order along Z axis the points (xi,yi,zi) where "i" belongs to {0,1,2} // After this z0 < z1 < z2 @@ -773,7 +777,7 @@ void TGraph2DPainter::PaintPolyMarker(Option_t *option) Bool_t colors = opt.Contains("pcol"); Int_t ncolors = gStyle->GetNumberOfColors(); Int_t it, theColor; - + // Initialize the levels on the Z axis if (colors) { Int_t ndiv = gCurrentHist->GetContour(); @@ -783,7 +787,7 @@ void TGraph2DPainter::PaintPolyMarker(Option_t *option) } if (gCurrentHist->TestBit(TH1::kUserContour) == 0) gCurrentHist->SetContour(ndiv); } - + Double_t *xm = new Double_t[fNpoints]; Double_t *ym = new Double_t[fNpoints]; Double_t hzmin = gCurrentHist->GetMinimum(); From b209e7bb200298e8a9500ab5dc70bea0c6c8f5d2 Mon Sep 17 00:00:00 2001 From: Olivier Couet Date: Thu, 15 Aug 2013 13:13:07 +0200 Subject: [PATCH 18/20] Release notes update. --- hist/doc/v600/index.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hist/doc/v600/index.md b/hist/doc/v600/index.md index 33786288f5ac8..44c548fe496ac 100644 --- a/hist/doc/v600/index.md +++ b/hist/doc/v600/index.md @@ -119,6 +119,10 @@ histo2->Draw("same"); } ``` +- In `TGraph2DPainter::PaintLevels` the colour levels used to paint + the triangles did not match the minimum and maximum set by the + user on the `TGraph2D`. This problem was reported + [here](http://root.cern.ch/phpBB3/viewtopic.php?f=3&t=16937&p=72314#p72314) ### TPaletteAxis From 72dbdbdf2e5988fd7e83efa5381180a8778592d7 Mon Sep 17 00:00:00 2001 From: Dario Berzano Date: Thu, 15 Aug 2013 13:36:38 +0200 Subject: [PATCH 19/20] Harmonized a couple of R_ASSERTs --- proof/proof/src/TProof.cxx | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/proof/proof/src/TProof.cxx b/proof/proof/src/TProof.cxx index 3c21f18a761c8..697faec3d5c0b 100644 --- a/proof/proof/src/TProof.cxx +++ b/proof/proof/src/TProof.cxx @@ -2837,7 +2837,15 @@ Bool_t TProof::PollForNewWorkers() TList *reqWorkers = new TList(); reqWorkers->SetOwner(kFALSE); - R__ASSERT(gProofServ); + if (!TestBit(TProof::kIsMaster)) { + Error("PollForNewWorkers", "Can't invoke: not on a master -- should not happen!"); + return -1; + } + if (!gProofServ) { + Error("PollForNewWorkers", "No ProofServ available -- should not happen!"); + return -1; + } + gProofServ->GetWorkers(reqWorkers, dummy, kTRUE); // last 2 are dummy // List of new workers only (TProofNodeInfo) @@ -6927,8 +6935,14 @@ Int_t TProof::GoMoreParallel(Int_t nWorkersToAdd) // is sent back to the client when we go "more" parallel. // Returns -1 on error, number of total (not added!) workers on success. - if (!IsValid() || !IsMaster() || IsIdle()) + if (!IsValid() || !IsMaster() || IsIdle()) { + Error("GoMoreParallel", "Can't invoke here -- should not happen!"); return -1; + } + if (!gProofServ) { + Error("GoMoreParallel", "No ProofServ available -- should not happen!"); + return -1; + } TSlave *sl = 0x0; TIter next( fSlaves ); @@ -7004,7 +7018,6 @@ Int_t TProof::GoMoreParallel(Int_t nWorkersToAdd) // Notify the client that we've got more workers, and print info on // Master's log as well - R__ASSERT(gProofServ); TString s; s.Form("PROOF just went more parallel (%d additional worker%s, %d worker%s total)", nAddedWorkers, (nAddedWorkers == 1) ? "" : "s", From 33c8a6f69e659834e6aa6c70575c4ae63d36f04a Mon Sep 17 00:00:00 2001 From: Dario Berzano Date: Thu, 15 Aug 2013 12:05:21 +0200 Subject: [PATCH 20/20] Fixed CID 52067 and retval of PollForNewWorkers() --- proof/proof/inc/TProof.h | 2 +- proof/proof/src/TProof.cxx | 12 ++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/proof/proof/inc/TProof.h b/proof/proof/inc/TProof.h index 7dd4a61723558..c7747e498aa8d 100644 --- a/proof/proof/inc/TProof.h +++ b/proof/proof/inc/TProof.h @@ -679,7 +679,7 @@ friend class TXProofServ; // to access EUrgent Int_t HandleInputMessage(TSlave *wrk, TMessage *m, Bool_t deactonfail = kFALSE); void HandleSubmerger(TMessage *mess, TSlave *sl); void SetMonitor(TMonitor *mon = 0, Bool_t on = kTRUE); - Bool_t PollForNewWorkers(); + Int_t PollForNewWorkers(); void ReleaseMonitor(TMonitor *mon); diff --git a/proof/proof/src/TProof.cxx b/proof/proof/src/TProof.cxx index 697faec3d5c0b..c65e43f049dd4 100644 --- a/proof/proof/src/TProof.cxx +++ b/proof/proof/src/TProof.cxx @@ -2827,10 +2827,10 @@ Int_t TProof::Collect(TMonitor *mon, Long_t timeout, Int_t endtype, Bool_t deact } //______________________________________________________________________________ -Bool_t TProof::PollForNewWorkers() +Int_t TProof::PollForNewWorkers() { // Asks the PROOF Serv for new workers in Dynamic Startup mode and activates - // them. Returns the number of new workers found. + // them. Returns the number of new workers found, or <0 on errors. // Requests for worker updates Int_t dummy = 0; @@ -2884,10 +2884,14 @@ Bool_t TProof::PollForNewWorkers() Int_t nNewWorkers = newWorkers->GetEntries(); // Add the new workers - if (newWorkers->GetEntries() > 0) { + if (nNewWorkers > 0) { PDB(kGlobal, 1) Info("PollForNewWorkers", "Requesting to add %d new worker(s)", newWorkers->GetEntries()); - AddWorkers(newWorkers); + Int_t rv = AddWorkers(newWorkers); + if (rv < 0) { + Error("PollForNewWorkers", "Call to AddWorkers() failed (got %d < 0)", rv); + return -1; + } // Don't delete newWorkers: AddWorkers() will do that } else {