Skip to content

Commit cea487d

Browse files
committed
Destroy Simulation and Universe when destroying CelestiaCore
- Fix use-after-free when destroying Timelines - Use single ownership of TimelinePhase - celx phase routines use non-owning pointers
1 parent 6f77a93 commit cea487d

19 files changed

+220
-239
lines changed

src/celengine/axisarrow.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -220,8 +220,8 @@ VelocityVectorArrow::VelocityVectorArrow(const Body& _body) :
220220
Eigen::Vector3d
221221
VelocityVectorArrow::getDirection(double tdb) const
222222
{
223-
const TimelinePhase* phase = body.getTimeline()->findPhase(tdb).get();
224-
return phase->orbitFrame()->getOrientation(tdb).conjugate() * phase->orbit()->velocityAtTime(tdb);
223+
const TimelinePhase& phase = body.getTimeline()->findPhase(tdb);
224+
return phase.orbitFrame()->getOrientation(tdb).conjugate() * phase.orbit()->velocityAtTime(tdb);
225225
}
226226

227227
std::string_view
@@ -278,8 +278,8 @@ SpinVectorArrow::SpinVectorArrow(const Body& _body) :
278278
Eigen::Vector3d
279279
SpinVectorArrow::getDirection(double tdb) const
280280
{
281-
const TimelinePhase* phase = body.getTimeline()->findPhase(tdb).get();
282-
return phase->bodyFrame()->getOrientation(tdb).conjugate() * phase->rotationModel()->angularVelocityAtTime(tdb);
281+
const TimelinePhase& phase = body.getTimeline()->findPhase(tdb);
282+
return phase.bodyFrame()->getOrientation(tdb).conjugate() * phase.rotationModel()->angularVelocityAtTime(tdb);
283283
}
284284

285285
std::string_view

src/celengine/body.cpp

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -255,25 +255,25 @@ Body::markUpdated()
255255
const std::shared_ptr<const ReferenceFrame>&
256256
Body::getOrbitFrame(double tdb) const
257257
{
258-
return timeline->findPhase(tdb)->orbitFrame();
258+
return timeline->findPhase(tdb).orbitFrame();
259259
}
260260

261261
const celestia::ephem::Orbit*
262262
Body::getOrbit(double tdb) const
263263
{
264-
return timeline->findPhase(tdb)->orbit().get();
264+
return timeline->findPhase(tdb).orbit().get();
265265
}
266266

267267
const std::shared_ptr<const ReferenceFrame>&
268268
Body::getBodyFrame(double tdb) const
269269
{
270-
return timeline->findPhase(tdb)->bodyFrame();
270+
return timeline->findPhase(tdb).bodyFrame();
271271
}
272272

273273
const celestia::ephem::RotationModel*
274274
Body::getRotationModel(double tdb) const
275275
{
276-
return timeline->findPhase(tdb)->rotationModel().get();
276+
return timeline->findPhase(tdb).rotationModel().get();
277277
}
278278

279279
/*! Get the radius of a sphere large enough to contain the primary
@@ -581,16 +581,16 @@ Body::getPosition(double tdb) const
581581
{
582582
Eigen::Vector3d position = Eigen::Vector3d::Zero();
583583

584-
const TimelinePhase* phase = timeline->findPhase(tdb).get();
585-
Eigen::Vector3d p = phase->orbit()->positionAtTime(tdb);
586-
const ReferenceFrame* frame = phase->orbitFrame().get();
584+
const TimelinePhase& phase = timeline->findPhase(tdb);
585+
Eigen::Vector3d p = phase.orbit()->positionAtTime(tdb);
586+
const ReferenceFrame* frame = phase.orbitFrame().get();
587587

588588
while (frame->getCenter().getType() == SelectionType::Body)
589589
{
590-
phase = frame->getCenter().body()->timeline->findPhase(tdb).get();
590+
const TimelinePhase& centerPhase = frame->getCenter().body()->timeline->findPhase(tdb);
591591
position += frame->getOrientation(tdb).conjugate() * p;
592-
p = phase->orbit()->positionAtTime(tdb);
593-
frame = phase->orbitFrame().get();
592+
p = centerPhase.orbit()->positionAtTime(tdb);
593+
frame = centerPhase.orbitFrame().get();
594594
}
595595

596596
position += frame->getOrientation(tdb).conjugate() * p;
@@ -606,20 +606,20 @@ Body::getPosition(double tdb) const
606606
Eigen::Quaterniond
607607
Body::getOrientation(double tdb) const
608608
{
609-
const TimelinePhase* phase = timeline->findPhase(tdb).get();
610-
return phase->rotationModel()->orientationAtTime(tdb) * phase->bodyFrame()->getOrientation(tdb);
609+
const TimelinePhase& phase = timeline->findPhase(tdb);
610+
return phase.rotationModel()->orientationAtTime(tdb) * phase.bodyFrame()->getOrientation(tdb);
611611
}
612612

613613
/*! Get the velocity of the body in the universal frame.
614614
*/
615615
Eigen::Vector3d
616616
Body::getVelocity(double tdb) const
617617
{
618-
const TimelinePhase* phase = timeline->findPhase(tdb).get();
618+
const TimelinePhase& phase = timeline->findPhase(tdb);
619619

620-
const ReferenceFrame* orbitFrame = phase->orbitFrame().get();
620+
const ReferenceFrame* orbitFrame = phase.orbitFrame().get();
621621

622-
Eigen::Vector3d v = phase->orbit()->velocityAtTime(tdb);
622+
Eigen::Vector3d v = phase.orbit()->velocityAtTime(tdb);
623623
v = orbitFrame->getOrientation(tdb).conjugate() * v + orbitFrame->getCenter().getVelocity(tdb);
624624

625625
if (!orbitFrame->isInertial())
@@ -636,11 +636,11 @@ Body::getVelocity(double tdb) const
636636
Eigen::Vector3d
637637
Body::getAngularVelocity(double tdb) const
638638
{
639-
const TimelinePhase* phase = timeline->findPhase(tdb).get();
639+
const TimelinePhase& phase = timeline->findPhase(tdb);
640640

641-
Eigen::Vector3d v = phase->rotationModel()->angularVelocityAtTime(tdb);
641+
Eigen::Vector3d v = phase.rotationModel()->angularVelocityAtTime(tdb);
642642

643-
const ReferenceFrame* bodyFrame = phase->bodyFrame().get();
643+
const ReferenceFrame* bodyFrame = phase.bodyFrame().get();
644644
v = bodyFrame->getOrientation(tdb).conjugate() * v;
645645
if (!bodyFrame->isInertial())
646646
{
@@ -659,8 +659,8 @@ Body::getAngularVelocity(double tdb) const
659659
Eigen::Matrix4d
660660
Body::getLocalToAstrocentric(double tdb) const
661661
{
662-
const TimelinePhase* phase = timeline->findPhase(tdb).get();
663-
Eigen::Vector3d p = phase->orbitFrame()->convertToAstrocentric(phase->orbit()->positionAtTime(tdb), tdb);
662+
const TimelinePhase& phase = timeline->findPhase(tdb);
663+
Eigen::Vector3d p = phase.orbitFrame()->convertToAstrocentric(phase.orbit()->positionAtTime(tdb), tdb);
664664
return Eigen::Transform<double, 3, Eigen::Affine>(Eigen::Translation3d(p)).matrix();
665665
}
666666

@@ -670,17 +670,17 @@ Eigen::Vector3d
670670
Body::getAstrocentricPosition(double tdb) const
671671
{
672672
// TODO: Switch the iterative method used in getPosition
673-
const TimelinePhase* phase = timeline->findPhase(tdb).get();
674-
return phase->orbitFrame()->convertToAstrocentric(phase->orbit()->positionAtTime(tdb), tdb);
673+
const TimelinePhase& phase = timeline->findPhase(tdb);
674+
return phase.orbitFrame()->convertToAstrocentric(phase.orbit()->positionAtTime(tdb), tdb);
675675
}
676676

677677
/*! Get a rotation that converts from the ecliptic frame to the body frame.
678678
*/
679679
Eigen::Quaterniond
680680
Body::getEclipticToFrame(double tdb) const
681681
{
682-
const TimelinePhase* phase = timeline->findPhase(tdb).get();
683-
return phase->bodyFrame()->getOrientation(tdb);
682+
const TimelinePhase& phase = timeline->findPhase(tdb);
683+
return phase.bodyFrame()->getOrientation(tdb);
684684
}
685685

686686
/*! Get a rotation that converts from the ecliptic frame to the body's
@@ -689,8 +689,8 @@ Body::getEclipticToFrame(double tdb) const
689689
Eigen::Quaterniond
690690
Body::getEclipticToEquatorial(double tdb) const
691691
{
692-
const TimelinePhase* phase = timeline->findPhase(tdb).get();
693-
return phase->rotationModel()->equatorOrientationAtTime(tdb) * phase->bodyFrame()->getOrientation(tdb);
692+
const TimelinePhase& phase = timeline->findPhase(tdb);
693+
return phase.rotationModel()->equatorOrientationAtTime(tdb) * phase.bodyFrame()->getOrientation(tdb);
694694
}
695695

696696
// The body-fixed coordinate system has an origin at the center of the
@@ -699,8 +699,8 @@ Body::getEclipticToEquatorial(double tdb) const
699699
Eigen::Quaterniond
700700
Body::getEquatorialToBodyFixed(double tdb) const
701701
{
702-
const TimelinePhase* phase = timeline->findPhase(tdb).get();
703-
return phase->rotationModel()->spin(tdb);
702+
const TimelinePhase& phase = timeline->findPhase(tdb);
703+
return phase.rotationModel()->spin(tdb);
704704
}
705705

706706
/*! Get a transformation to convert from the object's body fixed frame

src/celengine/frametree.cpp

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "frametree.h"
1414

1515
#include <algorithm>
16+
#include <cassert>
1617

1718
#include <celephem/orbit.h>
1819
#include "frame.h"
@@ -57,7 +58,11 @@ FrameTree::FrameTree(Body* body) :
5758
{
5859
}
5960

60-
FrameTree::~FrameTree() = default;
61+
FrameTree::~FrameTree()
62+
{
63+
for (const auto& phase : children)
64+
phase->m_owner = nullptr;
65+
}
6166

6267
/*! Return the default reference frame for the object a frame tree is associated
6368
* with.
@@ -138,8 +143,10 @@ FrameTree::recomputeBoundingSphere()
138143
/*! Add a new phase to this tree.
139144
*/
140145
void
141-
FrameTree::addChild(const std::shared_ptr<const TimelinePhase>& phase)
146+
FrameTree::addChild(TimelinePhase* phase)
142147
{
148+
assert(phase->m_owner == nullptr);
149+
phase->m_owner = this;
143150
children.push_back(phase);
144151
markChanged();
145152
}
@@ -148,12 +155,14 @@ FrameTree::addChild(const std::shared_ptr<const TimelinePhase>& phase)
148155
* phase doesn't exist in the tree.
149156
*/
150157
void
151-
FrameTree::removeChild(const std::shared_ptr<const TimelinePhase>& phase)
158+
FrameTree::removeChild(TimelinePhase* phase)
152159
{
153160
auto iter = std::find(children.begin(), children.end(), phase);
154161
if (iter != children.end())
155162
{
156163
children.erase(iter);
164+
assert(phase->m_owner == this);
165+
phase->m_owner = nullptr;
157166
markChanged();
158167
}
159168
}
@@ -162,7 +171,8 @@ FrameTree::removeChild(const std::shared_ptr<const TimelinePhase>& phase)
162171
const TimelinePhase*
163172
FrameTree::getChild(unsigned int n) const
164173
{
165-
return children[n].get();
174+
assert(n < children.size());
175+
return children[n];
166176
}
167177

168178
/*! Get the number of immediate children of this tree. */

src/celengine/frametree.h

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@ class FrameTree //NOSONAR
2828
explicit FrameTree(Body*);
2929
~FrameTree();
3030

31+
FrameTree(const FrameTree&) = delete;
32+
FrameTree& operator=(const FrameTree&) = delete;
33+
FrameTree(FrameTree&&) = delete;
34+
FrameTree& operator=(FrameTree&&) = delete;
35+
3136
/*! Return the star that this tree is associated with; it will be
3237
* nullptr for frame trees associated with solar system bodies.
3338
*/
@@ -38,8 +43,6 @@ class FrameTree //NOSONAR
3843

3944
const std::shared_ptr<const ReferenceFrame>& getDefaultReferenceFrame() const;
4045

41-
void addChild(const std::shared_ptr<const TimelinePhase>& phase);
42-
void removeChild(const std::shared_ptr<const TimelinePhase>& phase);
4346
const TimelinePhase* getChild(unsigned int n) const;
4447
unsigned int childCount() const;
4548

@@ -89,9 +92,12 @@ class FrameTree //NOSONAR
8992
}
9093

9194
private:
95+
void addChild(TimelinePhase* phase);
96+
void removeChild(TimelinePhase* phase);
97+
9298
Star* starParent{ nullptr };
9399
Body* bodyParent{ nullptr };
94-
std::vector<std::shared_ptr<const TimelinePhase>> children;
100+
std::vector<TimelinePhase*> children;
95101

96102
double m_boundingSphereRadius{ 0.0 };
97103
double m_maxChildRadius{ 0.0 };
@@ -100,4 +106,6 @@ class FrameTree //NOSONAR
100106
BodyClassification m_childClassMask{ BodyClassification::EmptyMask };
101107

102108
std::shared_ptr<const ReferenceFrame> defaultFrame;
109+
110+
friend class TimelinePhase;
103111
};

src/celengine/render.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3581,11 +3581,11 @@ void Renderer::buildLabelLists(const math::InfiniteFrustum& viewFrustum,
35813581
if (body->getName().empty())
35823582
continue;
35833583

3584-
const TimelinePhase* phase = body->getTimeline()->findPhase(now).get();
3585-
const Body* primary = phase->orbitFrame()->getCenter().body();
3584+
const TimelinePhase& phase = body->getTimeline()->findPhase(now);
3585+
const Body* primary = phase.orbitFrame()->getCenter().body();
35863586
if (primary != nullptr && util::is_set(primary->getClassification(), BodyClassification::Invisible))
35873587
{
3588-
const Body* parent = phase->orbitFrame()->getCenter().body();
3588+
const Body* parent = phase.orbitFrame()->getCenter().body();
35893589
if (parent != nullptr)
35903590
primary = parent;
35913591
}
@@ -3617,8 +3617,8 @@ void Renderer::buildLabelLists(const math::InfiniteFrustum& viewFrustum,
36173617
// position.
36183618
if (primary != lastPrimary)
36193619
{
3620-
Vector3d p = phase->orbitFrame()->getOrientation(now).conjugate() *
3621-
phase->orbit()->positionAtTime(now);
3620+
Vector3d p = phase.orbitFrame()->getOrientation(now).conjugate() *
3621+
phase.orbit()->positionAtTime(now);
36223622
Vector3d v = ri.position.cast<double>() - p;
36233623

36243624
primarySphere = math::Sphered(v, primary->getRadius());

src/celengine/simulation.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,17 @@
1414

1515
#include <algorithm>
1616
#include <cstddef>
17+
#include <utility>
1718

1819
#include <celutil/strnatcmp.h>
1920
#include "body.h"
2021
#include "location.h"
2122
#include "render.h"
2223

2324

24-
Simulation::Simulation(Universe* universe, const std::shared_ptr<celestia::engine::ObserverSettings>& observerSettings) :
25-
universe(universe)
25+
Simulation::Simulation(std::unique_ptr<Universe>&& universe,
26+
const std::shared_ptr<celestia::engine::ObserverSettings>& observerSettings) :
27+
universe(std::move(universe))
2628
{
2729
activeObserver = new Observer(observerSettings);
2830
observers.push_back(activeObserver);
@@ -63,7 +65,7 @@ void Simulation::render(Renderer& renderer, Observer& observer)
6365

6466
Universe* Simulation::getUniverse() const
6567
{
66-
return universe;
68+
return universe.get();
6769
}
6870

6971

src/celengine/simulation.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ class Renderer;
3333
class Simulation
3434
{
3535
public:
36-
Simulation(Universe*, const std::shared_ptr<celestia::engine::ObserverSettings>&);
36+
Simulation(std::unique_ptr<Universe>&&,
37+
const std::shared_ptr<celestia::engine::ObserverSettings>&);
3738
~Simulation();
3839

3940
double getTime() const; // Julian date
@@ -131,7 +132,7 @@ class Simulation
131132
double storedTimeScale{ 1.0 };
132133
bool syncTime{ true };
133134

134-
Universe* universe;
135+
std::unique_ptr<Universe> universe;
135136

136137
mutable std::optional<SolarSystem*> closestSolarSystem{ std::nullopt };
137138
Selection selection;

0 commit comments

Comments
 (0)