Andrej Nazarov created THRIFT-4781:
--------------------------------------

             Summary: C++ clients crash when exceptions are typedefed in the IDL
                 Key: THRIFT-4781
                 URL: https://issues.apache.org/jira/browse/THRIFT-4781
             Project: Thrift
          Issue Type: Bug
          Components: C++ - Compiler
    Affects Versions: 0.12.0, 0.11.0
            Reporter: Andrej Nazarov


If exceptions are typedefed in the IDL, they're generated as pointers in C++. 
This causes a runtime crash (memory access violation) on the C++ client-side 
when a server sends that exception and the client tries to read it. Example 
follows:
{code:java|title=service.thrift}
namespace * thrifttest.service
include "errors.thrift"
typedef errors.FooError FooError
service FooBarService
{
        string getFooString(1: i32 stringLength) throws (1: FooError e);
        string getBarString(1: i32 stringLength) throws (1: errors.BarError e);
}
{code}
{code:java|title=errors.thrift}
namespace * thrifttest.errors
exception FooError {
  1: string message
}
exception BarError {
  1: string message
}
{code}
{code:java|title=FooBarService.h}
class FooBarService_getFooString_presult {
 public:
  virtual ~FooBarService_getFooString_presult() throw();
  std::string* success;
  FooError* e; //note pointer declaration of the exception field
// snip...

class FooBarService_getBarString_presult {
 public:
  virtual ~FooBarService_getBarString_presult() throw();
  std::string* success;
   ::thrifttest::errors::BarError e; //note different declaration of the 
exception field
//snip
{code}
{code:java|title=FooBarService.cpp}
uint32_t 
FooBarService_getFooString_presult::read(::apache::thrift::protocol::TProtocol* 
iprot) {
// snip...
  while (true)
  {
// snip...
    switch (fid)
    {
// snip...
      case 1:
        if (ftype == ::apache::thrift::protocol::T_STRUCT) {
          xfer += (*(this->e)).read(iprot); // <-- this line causes access 
violation crash because the pointer is not initialized
          this->__isset.e = true;
       // snip...

uint32_t 
FooBarService_getBarString_presult::read(::apache::thrift::protocol::TProtocol* 
iprot) {
// snip...
  while (true)
  {
// snip...
    switch (fid)
    {
// snip...
      case 1:
        if (ftype == ::apache::thrift::protocol::T_STRUCT) {
          xfer += this->e.read(iprot); //<-- this gets read OK.
          this->__isset.e = true;
//snip
{code}
This happens regardless of server language (reproducible if server throwing the 
exceptions is Java, Python or C++)
 I guess this logic in 
[t_cpp_generator.cc:1104|https://github.com/apache/thrift/blob/0.11.0/compiler/cpp/src/thrift/generate/t_cpp_generator.cc#L1104]
 gets deceived in case of typedefed exceptions:
{code:title=t_cpp_generator.cc}
(pointers && !(*m_iter)->get_type()->is_xception()),
{code}
I'm no Thrift compiler expert, but I assume there is a reason why you don't 
want exceptions to be declared as pointers. Yet in this case they clearly are.



--
This message was sent by Atlassian JIRA
(v7.6.3#76005)

Reply via email to