Skip to content

CTest errors fail to be caught by the CI workflow #1418

@YanzhaoW

Description

@YanzhaoW

Describe the bug
Multiple crashes in ctests are not caught by the CI workflow.

Unused file source in run_reco_timebased.C

FairRunAna *fRun = new FairRunAna();
FairFileSource *fFileSource = new FairFileSource(inFile);
fRun->SetSink(std::make_unique<FairRootFileSink>(outFile));
fRun->RunWithTimeStamps();
fRun->SetUseFairLinks(kTRUE);

Here even though the file source fFileSource is initialised, it isn't used by FairRun. Obviously this should have crashed the program since FairRunAna must have a source to analyze (it does crash the the PR #1254).

Double deleting of file source in FairRootManager and FairRun

In FairRootManager, the file source is deleted here:

delete fSourceChain;
if (fSink)
delete fSink;
if (fSource)
delete fSource;

In FairRun, the file source is deleted automatically using std::unique_ptr:

FairAlignmentHandler fAlignmentHandler;
std::unique_ptr<FairSource> fSource{}; //!
void AlignGeometry() const;

However, deleting from FairRootManager is sometimes prevented by:

LOG(debug) << "Enter Destructor of FairRun";
// So that FairRootManager does not try to delete these, because we will do that:
fRootManager->SetSource(nullptr);
fRootManager->SetSink(nullptr);

But everything falls apart if FairRootManager is deleted before FairRun, as has happened in Ctests such as run_digi_timebased.C:

// ----- Reconstruction run -------------------------------------------
FairRunAna* fRun = new FairRunAna();
FairFileSource* fFileSource = new FairFileSource(inFile);
fRun->SetSource(fFileSource);

Here FairRunAna is initialised with the "evil" new operator and not deleted at the end of the program. As the result, the destructor of FairRootManager is executed followed by the destructor of FairRun. Therefore, we have the double deleting of one file source pointer, which is an UB (some time the program crashes, sometimes not).

Additional context
I have never understood what is the use of this "idiom". It's also used at many places in R3BRoot.

if(a_ptr != nullptr)
    delete a_ptr;

If a_ptr is a nullptr, deleting a nullptr is totally fine in c++. If a_ptr is not a nullptr but it's been deleted, we have a double deleting anyway. I'm confused which scenario this "idiom" is trying to prevent.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions