summaryrefslogtreecommitdiff
path: root/cpp
diff options
context:
space:
mode:
Diffstat (limited to 'cpp')
-rw-r--r--cpp/CHANGES7
-rw-r--r--cpp/src/slice2cpp/Gen.cpp70
2 files changed, 75 insertions, 2 deletions
diff --git a/cpp/CHANGES b/cpp/CHANGES
index b9ff3b5de3e..638e4e192e5 100644
--- a/cpp/CHANGES
+++ b/cpp/CHANGES
@@ -1,6 +1,13 @@
Changes since version 1.5.1
---------------------------
+- Fixed a bug in slice2cpp that permitted impossible exceptions
+ to be received by a client if client and server used Slice
+ definitions with mismatched exception specifications. The
+ client now correctly receives UnknownUserException if the
+ server throws an exception that, according to the client's
+ view of the operation, is impossible.
+
- The documentation has always stated that same-named constructs
cannot be directly nested inside each other. (For example, a
module `M' cannot contain a constant named `M'. The slice2cpp
diff --git a/cpp/src/slice2cpp/Gen.cpp b/cpp/src/slice2cpp/Gen.cpp
index 1ad5b03a644..e214f8e1f7e 100644
--- a/cpp/src/slice2cpp/Gen.cpp
+++ b/cpp/src/slice2cpp/Gen.cpp
@@ -1577,6 +1577,50 @@ Slice::Gen::DelegateMVisitor::visitOperation(const OperationPtr& p)
C << nl << "return __ret;";
}
C << eb;
+
+ //
+ // Generate a catch block for each legal user exception. This is necessary
+ // to prevent an "impossible" user exception to be thrown if client and
+ // and server use different exception specifications for an operation. For
+ // example:
+ //
+ // Client compiled with:
+ // exception A {};
+ // exception B {};
+ // interface I {
+ // void op() throws A;
+ // };
+ //
+ // Server compiled with:
+ // exception A {};
+ // exception B {};
+ // interface I {
+ // void op() throws B; // Differs from client
+ // };
+ //
+ // We need the catch blocks so, if the server throws B from op(), the
+ // client receives UnknownUserException instead of B.
+ //
+ ExceptionList throws = p->throws();
+ throws.sort();
+ throws.unique();
+#if defined(__SUNPRO_CC)
+ throws.sort(derivedToBaseCompare);
+#else
+ throws.sort(Slice::DerivedToBaseCompare());
+#endif
+ for(ExceptionList::const_iterator i = throws.begin(); i != throws.end(); ++i)
+ {
+ string scoped = (*i)->scoped();
+ C << nl << "catch(const " << (*i)->scoped() << "&)";
+ C << sb;
+ C << nl << "throw;";
+ C << eb;
+ }
+ C << nl << "catch(const ::Ice::UserException&)";
+ C << sb;
+ C << nl << "throw ::Ice::UnknownUserException(__FILE__, __LINE__);";
+ C << eb;
C << nl << "catch(const ::Ice::LocalException& __ex)";
C << sb;
C << nl << "throw ::IceInternal::NonRepeatable(__ex);";
@@ -3518,9 +3562,31 @@ Slice::Gen::AsyncVisitor::visitOperation(const OperationPtr& p)
C << nl << "__finished(__ex);";
C << nl << "return;";
C << eb;
- C << nl << "catch(const ::Ice::UserException& __ex)";
+
+ //
+ // Generate a catch block for each legal user exception.
+ // (See comment in DelegateMVisitor::visitOperation() for details.)
+ //
+ ExceptionList throws = p->throws();
+ throws.sort();
+ throws.unique();
+#if defined(__SUNPRO_CC)
+ throws.sort(derivedToBaseCompare);
+#else
+ throws.sort(Slice::DerivedToBaseCompare());
+#endif
+ for(ExceptionList::const_iterator i = throws.begin(); i != throws.end(); ++i)
+ {
+ string scoped = (*i)->scoped();
+ C << nl << "catch(const " << (*i)->scoped() << "& __ex)";
+ C << sb;
+ C << nl << "ice_exception(__ex);";
+ C << nl << "return;";
+ C << eb;
+ }
+ C << nl << "catch(const ::Ice::UserException&)";
C << sb;
- C << nl << "ice_exception(__ex);";
+ C << nl << "ice_exception(::Ice::UnknownUserException(__FILE__, __LINE__));";
C << nl << "return;";
C << eb;
C << nl << "ice_response" << spar << args << epar << ';';