diff options
Diffstat (limited to 'cpp')
-rw-r--r-- | cpp/CHANGES | 7 | ||||
-rw-r--r-- | cpp/src/slice2cpp/Gen.cpp | 70 |
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 << ';'; |