Skip to content

Commit

Permalink
MAYA-127095 remove usage of macros leading to fatal exits
Browse files Browse the repository at this point in the history
We should strive to reduce the number of scenarios under which Maya crashes.
Instead, when possible, we should report an error to user and abort the
operation. MayaUSD has extensive undo/redo capabilities now and code is able to
undo partially done operations. Given this, errors should be reported and
propagated back.

The macros TF_AXIOM and TF_FATAL_ERROR cause crashes when their conditions are
not met, even in release builds. Remove TF_AXIOM and TF_FATAL_ERROR, replacing
them with:

- TF_WARN when the situation was not an error but an unusual situation.
- TF_VERIFY when it still warrant an error message to the user, for example during error handling.
- Simple if/else, with an error return value when not a hard error.
- Simple if when the condition was trivial, like an empty node when iterating over USD nodes.
- In a few cases, TF_DEV_AXIOM when the condition was really strictly enforced by a class constructor.
- Entirely removed, when the code was already dealing with the error.
- C++ exception when the error needs to propagate to caller, in particular in constructors.
  • Loading branch information
pierrebai-adsk committed May 11, 2023
1 parent 65707a8 commit e92d7bb
Show file tree
Hide file tree
Showing 28 changed files with 199 additions and 139 deletions.
2 changes: 1 addition & 1 deletion doc/codingGuidelines.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ In general, macros should be avoided (see [Modern C++](https://docs.google.com/d
inline PXR_NS::UsdPrim prim() const
{
PXR_NAMESPACE_USING_DIRECTIVE
TF_AXIOM(fItem != nullptr);
TF_VERIFY(fItem != nullptr);
return fItem->prim();
}
```
Expand Down
15 changes: 11 additions & 4 deletions lib/mayaUsd/fileio/orphanedNodesManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -174,12 +174,19 @@ OrphanedNodesManager::OrphanedNodesManager()

void OrphanedNodesManager::add(const Ufe::Path& pulledPath, const MDagPath& editedAsMayaRoot)
{
// Adding a node twice to the orphan manager is idem-potent. The manager was already
// racking that node.
if (pulledPrims().containsDescendantInclusive(pulledPath))
return;

// Add the edited-as-Maya root to our pulled prims prefix tree. Also add the full
// configuration of variant set selections for each ancestor, up to the USD
// pseudo-root. Variants on the pulled path itself are ignored, as once
// pulled into Maya they cannot be changed.
TF_AXIOM(!pulledPrims().containsDescendantInclusive(pulledPath));
TF_AXIOM(pulledPath.runTimeId() == MayaUsd::ufe::getUsdRunTimeId());
if (pulledPath.runTimeId() != MayaUsd::ufe::getUsdRunTimeId()) {
TF_WARN("Trying to monitor a non-USD node for edit-as-Maya orphaning.");
return;
}

// We store a list of (path, list of (variant set, variant set selection)),
// for all ancestors, starting at closest ancestor.
Expand All @@ -192,7 +199,7 @@ void OrphanedNodesManager::add(const Ufe::Path& pulledPath, const MDagPath& edit
OrphanedNodesManager::Memento OrphanedNodesManager::remove(const Ufe::Path& pulledPath)
{
Memento oldPulledPrims(preserve());
TF_AXIOM(pulledPrims().remove(pulledPath) != nullptr);
TF_VERIFY(pulledPrims().remove(pulledPath) != nullptr);
return oldPulledPrims;
}

Expand Down Expand Up @@ -323,7 +330,7 @@ void OrphanedNodesManager::handleOp(const Ufe::SceneCompositeNotification::Op& o
// USD sends resync changes (UFE subtree invalidate) on the
// pseudo-root itself. Since the pseudo-root has no payload or
// variant, ignore these.
TF_AXIOM(parentItem->path().nbSegments() == 1);
TF_VERIFY(parentItem->path().nbSegments() == 1);
return;
}
auto parentPrim = parentUsdItem->prim();
Expand Down
4 changes: 3 additions & 1 deletion lib/mayaUsd/fileio/primUpdater.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,9 @@ bool UsdMayaPrimUpdater::canEditAsMaya() const
// prim will round-trip back through export, so we do not check for
// exporter (to USD) capability.
auto prim = MayaUsd::ufe::ufePathToPrim(_path);
TF_AXIOM(prim);
// Invalid prim cannot be edited.
if (!prim)
return false;
return (UsdMayaPrimReaderRegistry::Find(prim.GetTypeName()) != nullptr);
}

Expand Down
34 changes: 15 additions & 19 deletions lib/mayaUsd/fileio/primUpdaterManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ bool allowTopologyModifications(MDagPath& root)
// prim as the root of the USD hierarchy to be pulled. The UFE path and
// the prim refer to the same object: the prim is passed in as an
// optimization to avoid an additional call to ufePathToPrim().
using PullImportPaths = std::pair<std::vector<MDagPath>, std::vector<Ufe::Path>>;
using PullImportPaths = std::vector<std::pair<MDagPath, Ufe::Path>>;
PullImportPaths pullImport(
const Ufe::Path& ufePulledPath,
const UsdPrim& pulledPrim,
Expand Down Expand Up @@ -282,14 +282,13 @@ PullImportPaths pullImport(
}
progressBar.advance();

std::vector<MDagPath> addedDagPaths;
std::vector<Ufe::Path> pulledUfePaths;
std::vector<MDagPath> addedDagPaths;

// Execute the command, which can succeed but import nothing.
bool success = readJob->Read(&addedDagPaths);
if (!success || addedDagPaths.size() == 0) {
TF_WARN("Nothing to edit in the selection.");
return PullImportPaths({}, {});
return PullImportPaths();
}
progressBar.advance();

Expand Down Expand Up @@ -423,17 +422,18 @@ PullImportPaths pullImport(
progressBar.advance();

// For each added Dag path, get the UFE path of the pulled USD prim.
pulledUfePaths.reserve(addedDagPaths.size());
PullImportPaths pulledPaths;
pulledPaths.reserve(addedDagPaths.size());
for (const auto& dagPath : addedDagPaths) {
auto found = objToUfePath.find(MObjectHandle(dagPath.node()));
TF_AXIOM(found != objToUfePath.end());
pulledUfePaths.emplace_back(found->second);
if (TF_VERIFY(found != objToUfePath.end())) {
pulledPaths.emplace_back(std::make_pair(dagPath, found->second));
}
}
progressBar.advance();

auto ret = PullImportPaths(addedDagPaths, pulledUfePaths);
progressBar.advance();
return ret;
return pulledPaths;
}

//------------------------------------------------------------------------------
Expand All @@ -460,18 +460,15 @@ bool pullCustomize(const PullImportPaths& importedPaths, const UsdMayaPrimUpdate
{
// The number of imported paths should (hopefully) never be so great
// as to overwhelm the computation with progress bar updates.
MayaUsd::ProgressBarScope progressBar(importedPaths.first.size());
MayaUsd::ProgressBarScope progressBar(importedPaths.size());

// Record all USD modifications in an undo block and item.
UsdUndoBlock undoBlock(
&UsdUndoableItemUndoItem::create("Pull customize USD data modifications"));

TF_AXIOM(importedPaths.first.size() == importedPaths.second.size());
auto dagPathIt = importedPaths.first.begin();
auto ufePathIt = importedPaths.second.begin();
for (; dagPathIt != importedPaths.first.end(); ++dagPathIt, ++ufePathIt) {
const auto& dagPath = *dagPathIt;
const auto& pulledUfePath = *ufePathIt;
for (const auto& importedPair : importedPaths) {
const auto& dagPath = importedPair.first;
const auto& pulledUfePath = importedPair.second;
MFnDependencyNode dgNodeFn(dagPath.node());

auto registryItem = getUpdaterItem(dgNodeFn);
Expand Down Expand Up @@ -1156,7 +1153,7 @@ bool PrimUpdaterManager::editAsMaya(const Ufe::Path& path, const VtDictionary& u

// 1) Perform the import
PullImportPaths importedPaths = pullImport(path, pulledPrim, context);
if (importedPaths.first.empty()) {
if (importedPaths.empty()) {
return false;
}
progressBar.advance();
Expand All @@ -1170,7 +1167,7 @@ bool PrimUpdaterManager::editAsMaya(const Ufe::Path& path, const VtDictionary& u

#ifdef HAS_ORPHANED_NODES_MANAGER
if (_orphanedNodesManager) {
RecordPullVariantInfoUndoItem::execute(_orphanedNodesManager, path, importedPaths.first[0]);
RecordPullVariantInfoUndoItem::execute(_orphanedNodesManager, path, importedPaths[0].first);
}
#endif

Expand Down Expand Up @@ -1498,7 +1495,6 @@ bool PrimUpdaterManager::duplicate(
}
// Copy from DG to USD
else if (srcProxyShape == nullptr && dstProxyShape) {
TF_AXIOM(srcPath.nbSegments() == 1);
MDagPath dagPath = PXR_NS::UsdMayaUtil::nameToDagPath(Ufe::PathString::string(srcPath));
if (!dagPath.isValid()) {
return false;
Expand Down
6 changes: 4 additions & 2 deletions lib/mayaUsd/ufe/UsdCamera.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,10 @@ class MAYAUSD_CORE_PUBLIC UsdCamera : public Ufe::Camera
inline PXR_NS::UsdPrim prim() const
{
PXR_NAMESPACE_USING_DIRECTIVE
TF_AXIOM(fItem != nullptr);
return fItem->prim();
if (TF_VERIFY(fItem != nullptr))
return fItem->prim();
else
return PXR_NS::UsdPrim();
}

// Ufe::Camera overrides
Expand Down
8 changes: 4 additions & 4 deletions lib/mayaUsd/ufe/UsdConnections.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,8 @@ UsdConnections::UsdConnections(const Ufe::SceneItem::Ptr& item)
, _sceneItem(std::dynamic_pointer_cast<UsdSceneItem>(item))
#endif
{
if (!TF_VERIFY(_sceneItem)) {
TF_FATAL_ERROR("Invalid scene item.");
}
// Note: TF_VERIFY emits a TF_CODING_ERROR.
TF_VERIFY(_sceneItem);
}

UsdConnections::~UsdConnections() { }
Expand All @@ -55,7 +54,8 @@ UsdConnections::Ptr UsdConnections::create(const Ufe::SceneItem::Ptr& item)

std::vector<Ufe::Connection::Ptr> UsdConnections::allConnections() const
{
TF_AXIOM(_sceneItem);
if (!TF_VERIFY(_sceneItem))
return {};

std::vector<Ufe::Connection::Ptr> result;

Expand Down
3 changes: 2 additions & 1 deletion lib/mayaUsd/ufe/UsdContextOps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1172,7 +1172,8 @@ Ufe::UndoableCommand::Ptr UsdContextOps::doOpCmd(const ItemPath& itemPath)
} // Variant sets
else if (itemPath[0] == kUSDToggleVisibilityItem) {
auto object3d = UsdObject3d::create(fItem);
TF_AXIOM(object3d);
if (!TF_VERIFY(object3d))
return nullptr;
auto current = object3d->visibility();
return object3d->setVisibleCmd(!current);
} // Visibility
Expand Down
6 changes: 4 additions & 2 deletions lib/mayaUsd/ufe/UsdContextOps.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,10 @@ class MAYAUSD_CORE_PUBLIC UsdContextOps : public Ufe::ContextOps
inline PXR_NS::UsdPrim prim() const
{
PXR_NAMESPACE_USING_DIRECTIVE
TF_AXIOM(fItem != nullptr);
return fItem->prim();
if (TF_VERIFY(fItem != nullptr))
return fItem->prim();
else
return PXR_NS::UsdPrim();
}

// When we are created from the ProxyShapeContextOpsHandler we do not have the proper
Expand Down
6 changes: 4 additions & 2 deletions lib/mayaUsd/ufe/UsdHierarchy.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,10 @@ class MAYAUSD_CORE_PUBLIC UsdHierarchy : public Ufe::Hierarchy
inline PXR_NS::UsdPrim prim() const
{
PXR_NAMESPACE_USING_DIRECTIVE
TF_AXIOM(fItem != nullptr);
return fItem->prim();
if (TF_VERIFY(fItem != nullptr))
return fItem->prim();
else
return PXR_NS::UsdPrim();
}

UsdSceneItem::Ptr usdSceneItem() const;
Expand Down
6 changes: 4 additions & 2 deletions lib/mayaUsd/ufe/UsdLight.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,10 @@ class MAYAUSD_CORE_PUBLIC UsdLight : public Ufe::Light
inline PXR_NS::UsdPrim prim() const
{
PXR_NAMESPACE_USING_DIRECTIVE
TF_AXIOM(fItem != nullptr);
return fItem->prim();
if (TF_VERIFY(fItem != nullptr))
return fItem->prim();
else
return PXR_NS::UsdPrim();
}

// Ufe::Light overrides
Expand Down
10 changes: 7 additions & 3 deletions lib/mayaUsd/ufe/UsdPathMappingHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ Ufe::Path UsdPathMappingHandler::toHost(const Ufe::Path& runTimePath) const { re

Ufe::Path UsdPathMappingHandler::fromHost(const Ufe::Path& hostPath) const
{
TF_AXIOM(hostPath.nbSegments() == 1);
TF_VERIFY(hostPath.nbSegments() == 1);

// First look in our cache to see if we've already computed a mapping for the input.
auto found = fromHostCache.find(hostPath);
Expand All @@ -134,7 +134,9 @@ Ufe::Path UsdPathMappingHandler::fromHost(const Ufe::Path& hostPath) const
Ufe::Path mayaMappedPath;
Ufe::PathSegment::Components mayaComps;
while (dagPath.isValid() && (dagPath.length() > 0)) {
TF_AXIOM(!mayaHostPath.empty());
if (!TF_VERIFY(!mayaHostPath.empty())) {
return {};
}
mayaComps.emplace_back(mayaHostPath.back());
mayaHostPath = mayaHostPath.pop();
Ufe::Path ufePath;
Expand All @@ -143,7 +145,9 @@ Ufe::Path UsdPathMappingHandler::fromHost(const Ufe::Path& hostPath) const
// append the Maya component array.
std::reverse(mayaComps.begin(), mayaComps.end());

TF_AXIOM(ufePath.nbSegments() == 2);
if (!TF_VERIFY(ufePath.nbSegments() == 2)) {
return {};
}
const auto& usdSegment = ufePath.getSegments()[1];
mayaMappedPath = ufePath.popSegment() + replaceLastComponent(usdSegment, mayaComps);

Expand Down
6 changes: 4 additions & 2 deletions lib/mayaUsd/ufe/UsdRotatePivotTranslateUndoableCommand.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,10 @@ class MAYAUSD_CORE_PUBLIC UsdRotatePivotTranslateUndoableCommand
inline PXR_NS::UsdPrim prim() const
{
PXR_NAMESPACE_USING_DIRECTIVE
TF_AXIOM(fItem != nullptr);
return fItem->prim();
if (TF_VERIFY(fItem != nullptr))
return fItem->prim();
else
return PXR_NS::UsdPrim();
}

private:
Expand Down
6 changes: 4 additions & 2 deletions lib/mayaUsd/ufe/UsdSceneItemOps.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,10 @@ class MAYAUSD_CORE_PUBLIC UsdSceneItemOps : public Ufe::SceneItemOps
inline PXR_NS::UsdPrim prim() const
{
PXR_NAMESPACE_USING_DIRECTIVE
TF_AXIOM(fItem != nullptr);
return fItem->prim();
if (TF_VERIFY(fItem != nullptr))
return fItem->prim();
else
return PXR_NS::UsdPrim();
}

//@{
Expand Down
12 changes: 6 additions & 6 deletions lib/mayaUsd/ufe/UsdShaderAttributeDef.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,27 +47,27 @@ UsdShaderAttributeDef::~UsdShaderAttributeDef() { }

std::string UsdShaderAttributeDef::name() const
{
TF_AXIOM(fShaderAttributeDef);
TF_DEV_AXIOM(fShaderAttributeDef);
return fShaderAttributeDef->GetName().GetString();
}

std::string UsdShaderAttributeDef::type() const
{
TF_AXIOM(fShaderAttributeDef);
TF_DEV_AXIOM(fShaderAttributeDef);
return usdTypeToUfe(fShaderAttributeDef);
}

std::string UsdShaderAttributeDef::defaultValue() const
{
TF_AXIOM(fShaderAttributeDef);
TF_DEV_AXIOM(fShaderAttributeDef);
std::ostringstream defaultValue;
defaultValue << fShaderAttributeDef->GetDefaultValue();
return defaultValue.str();
}

Ufe::AttributeDef::IOType UsdShaderAttributeDef::ioType() const
{
TF_AXIOM(fShaderAttributeDef);
TF_DEV_AXIOM(fShaderAttributeDef);
return fShaderAttributeDef->IsOutput() ? Ufe::AttributeDef::OUTPUT_ATTR
: Ufe::AttributeDef::INPUT_ATTR;
}
Expand Down Expand Up @@ -131,7 +131,7 @@ static const MetadataMap _metaMap = {

Ufe::Value UsdShaderAttributeDef::getMetadata(const std::string& key) const
{
TF_AXIOM(fShaderAttributeDef);
TF_DEV_AXIOM(fShaderAttributeDef);
const NdrTokenMap& metadata = fShaderAttributeDef->GetMetadata();
auto it = metadata.find(TfToken(key));
if (it != metadata.cend()) {
Expand All @@ -154,7 +154,7 @@ Ufe::Value UsdShaderAttributeDef::getMetadata(const std::string& key) const

bool UsdShaderAttributeDef::hasMetadata(const std::string& key) const
{
TF_AXIOM(fShaderAttributeDef);
TF_DEV_AXIOM(fShaderAttributeDef);
const NdrTokenMap& metadata = fShaderAttributeDef->GetMetadata();
auto it = metadata.find(TfToken(key));
if (it != metadata.cend()) {
Expand Down
4 changes: 3 additions & 1 deletion lib/mayaUsd/ufe/UsdShaderAttributeHolder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,9 @@ UsdShaderAttributeHolder::UsdShaderAttributeHolder(

// sdrProp must be valid at creation and will stay valid.
PXR_NAMESPACE_USING_DIRECTIVE
TF_AXIOM(sdrProp && sdrType != PXR_NS::UsdShadeAttributeType::Invalid);
if (!TF_VERIFY(sdrProp && sdrType != PXR_NS::UsdShadeAttributeType::Invalid)) {
throw std::runtime_error("Invalid shader attribute holder");
}
}

UsdAttributeHolder::UPtr UsdShaderAttributeHolder::create(
Expand Down
Loading

0 comments on commit e92d7bb

Please sign in to comment.