3

I've encountered a weird structure member alignment issue in C++. This happens when using gSoap 2.8.2. gSoap defines this struct:

struct SOAP_STD_API soap
{ short state;          /* 0 = uninitialized, 1 = initialized, 2 = copy of another soap struct */
  short version;        /* 1 = SOAP1.1 and 2 = SOAP1.2 (set automatically from namespace URI in nsmap table) */
  soap_mode mode;
  soap_mode imode;
  soap_mode omode;
  const char *float_format; /* user-definable format string for floats (<1024 chars) */
  const char *double_format;    /* user-definable format string for doubles (<1024 chars) */
  const char *dime_id_format;   /* user-definable format string for integer DIME id (<SOAP_TAGLEN chars) */
  const char *http_version; /* HTTP version used "1.0" or "1.1" */
  const char *http_content; /* optional custom response content type (with SOAP_FILE) */
  const char *encodingStyle;    /* default = NULL which means that SOAP encoding is used */
  const char *actor;        /* SOAP-ENV:actor or role attribute value */
  const char *lang;     /* xml:lang attribute value of SOAP-ENV:Text */
  int recv_timeout;     /* when > 0, gives socket recv timeout in seconds, < 0 in usec */
  int send_timeout;     /* when > 0, gives socket send timeout in seconds, < 0 in usec */
  int connect_timeout;      /* when > 0, gives socket connect() timeout in seconds, < 0 in usec */
  int accept_timeout;       /* when > 0, gives socket accept() timeout in seconds, < 0 in usec */
  int socket_flags;     /* socket recv() and send() flags, e.g. set to MSG_NOSIGNAL to disable sigpipe */
  int connect_flags;        /* connect() SOL_SOCKET sockopt flags, e.g. set to SO_DEBUG to debug socket */
  int bind_flags;       /* bind() SOL_SOCKET sockopt flags, e.g. set to SO_REUSEADDR to enable reuse */
  int accept_flags;     /* accept() SOL_SOCKET sockopt flags */
  unsigned short linger_time;   /* linger time for SO_LINGER option */
  const struct Namespace *namespaces;   /* Pointer to global namespace mapping table */
  struct Namespace *local_namespaces;   /* Local namespace mapping table */
  struct soap_nlist *nlist; /* namespace stack */
  struct soap_blist *blist; /* block allocation stack */
  struct soap_clist *clist; /* class instance allocation list */
  void *alist;          /* memory allocation (malloc) list */
  struct soap_ilist *iht[SOAP_IDHASH];
  struct soap_plist *pht[SOAP_PTRHASH];
  struct soap_pblk *pblk;   /* plist block allocation */
  short pidx;           /* plist block allocation */
  struct SOAP_ENV__Header *header;
  struct SOAP_ENV__Fault *fault;
  int idnum;
  void *user;           /* for user to pass user-defined data */
  void *data[4];        /* extension data = {smdevp, mecevp, ...} */
  struct soap_plugin *plugins;  /* linked list of plug-in data */
  const char *userid;       /* HTTP Basic authorization userid */
  const char *passwd;       /* HTTP Basic authorization passwd */
  int (*fpost)(struct soap*, const char*, const char*, int, const char*, const char*, size_t);
  int (*fget)(struct soap*);    /* HTTP GET hook (not set by default) */
  int (*fput)(struct soap*);    /* HTTP PUT hook (handled as POST) */
  int (*fdel)(struct soap*);    /* HTTP DELETE hook (not set by default) */
  int (*fopt)(struct soap*);    /* HTTP OPTIONS hook (not set by default) */
  int (*fhead)(struct soap*);   /* HTTP HEAD hook (not set by default) */
  int (*fform)(struct soap*);   /* HTTP/HTML form handler for plugins */
  int (*fposthdr)(struct soap*, const char*, const char*);
  int (*fresponse)(struct soap*, int, size_t);
  int (*fparse)(struct soap*);
  int (*fparsehdr)(struct soap*, const char*, const char*);
  int (*fheader)(struct soap*);
  int (*fresolve)(struct soap*, const char*, struct in_addr* inaddr);
  int (*fconnect)(struct soap*, const char*, const char*, int);
  int (*fdisconnect)(struct soap*);
  int (*fclosesocket)(struct soap*, SOAP_SOCKET);
  int (*fshutdownsocket)(struct soap*, SOAP_SOCKET, int);
  SOAP_SOCKET (*fopen)(struct soap*, const char*, const char*, int);
  SOAP_SOCKET (*faccept)(struct soap*, SOAP_SOCKET, struct sockaddr*, int *n);
  int (*fclose)(struct soap*);
  int (*fsend)(struct soap*, const char*, size_t);
  size_t (*frecv)(struct soap*, char*, size_t);
  int (*fpoll)(struct soap*);
  int (*fselect)(struct soap*, SOAP_SOCKET, int, int, void*);
  void *fselect_param;
  void (*fseterror)(struct soap*, const char **c, const char **s);
  int (*fignore)(struct soap*, const char*);
  int (*fserveloop)(struct soap*);
  void *(*fplugin)(struct soap*, const char*);
  void *(*fmalloc)(struct soap*, size_t);
#ifndef WITH_LEANER
  int (*feltbegin)(struct soap*, const char*);
  int (*feltendin)(struct soap*, const char*, const char*);
  int (*feltbegout)(struct soap*, const char*);
  int (*feltendout)(struct soap*, const char*);
  int (*fprepareinitsend)(struct soap*);
  int (*fprepareinitrecv)(struct soap*);
  int (*fpreparesend)(struct soap*, const char*, size_t);
  int (*fpreparerecv)(struct soap*, const char*, size_t);
  int (*fpreparefinalsend)(struct soap*);
  int (*fpreparefinalrecv)(struct soap*);
  int filterstop;
  int (*ffiltersend)(struct soap*, const char**, size_t*);
  int (*ffilterrecv)(struct soap*, char*, size_t*, size_t);
  void *(*fdimereadopen)(struct soap*, void*, const char*, const char*, const char*);
  void *(*fdimewriteopen)(struct soap*, const char*, const char*, const char*);
  void (*fdimereadclose)(struct soap*, void*);
  void (*fdimewriteclose)(struct soap*, void*);
  size_t (*fdimeread)(struct soap*, void*, char*, size_t);
  int (*fdimewrite)(struct soap*, void*, const char*, size_t);
  void *(*fmimereadopen)(struct soap*, void*, const char*, const char*, const char*);
  void *(*fmimewriteopen)(struct soap*, void*, const char*, const char*, const char*, enum soap_mime_encoding);
  void (*fmimereadclose)(struct soap*, void*);
  void (*fmimewriteclose)(struct soap*, void*);
  size_t (*fmimeread)(struct soap*, void*, char*, size_t);
  int (*fmimewrite)(struct soap*, void*, const char*, size_t);
#endif
  SOAP_SOCKET master;
  SOAP_SOCKET socket;
#if defined(__cplusplus) && !defined(WITH_LEAN) && !defined(WITH_COMPAT)
  std::ostream *os;
  std::istream *is;
#else
  void *os;     /* preserve struct size */
  void *is;     /* preserve struct size */
#endif
#ifndef UNDER_CE
  int sendfd;       /* WinCE FD to send */
  int recvfd;       /* WinCE FD to receive */
#else
  FILE *sendfd;
  FILE *recvfd;
#endif
  size_t bufidx;    /* index in soap.buf[] */
  size_t buflen;    /* length of soap.buf[] content */
  soap_wchar ahead; /* parser lookahead */
  short cdata;      /* CDATA parser state */
  short body;       /* parsed XML element has a body or not */
  unsigned int level;   /* XML nesting level */
  size_t count;     /* message length counter */
  size_t length;    /* message length as set by HTTP header */
  char *labbuf;     /* look-aside buffer */
  size_t lablen;    /* look-aside buffer allocated length */
  size_t labidx;    /* look-aside buffer index to available part */
  char buf[SOAP_BUFLEN];/* send and receive buffer */
  char msgbuf[1024];    /* in/out buffer for HTTP/MIME headers >=1024 bytes */
  char tmpbuf[1024];    /* in/out buffer for HTTP/MIME headers, simpleType values, element and attribute tag names, and DIME must be >=1024 bytes */
  char tag[SOAP_TAGLEN];
  char id[SOAP_TAGLEN];
  char href[SOAP_TAGLEN];
  char type[SOAP_TAGLEN];
  char arrayType[SOAP_TAGLEN];
  char arraySize[SOAP_TAGLEN];
  char arrayOffset[SOAP_TAGLEN];
  short other;
  short position;
  int positions[SOAP_MAXDIMS];
  short root;
  struct soap_attribute *attributes;    /* attribute list */
  short encoding;   /* when set, output encodingStyle */
  short mustUnderstand; /* a mustUnderstand element was parsed or is output */
  short null;       /* parsed XML is xsi:nil */
  short ns;     /* when not set, output full xmlns bindings */
  short part;       /* SOAP part state (header or body) */
  short event;      /* engine events and states for use by plugins */
  short alloced;
  short peeked;
  size_t chunksize;
  size_t chunkbuflen;
  char endpoint[SOAP_TAGLEN];
  char path[SOAP_TAGLEN];
  char host[SOAP_TAGLEN];
  char *action;
  char *authrealm;      /* HTTP authentication realm */
  char *prolog;         /* XML declaration prolog */
  unsigned long ip;     /* IP number */
  int port;         /* port number */
  short keep_alive;     /* connection should be kept open */
  short tcp_keep_alive;     /* enable SO_KEEPALIVE */
  unsigned int tcp_keep_idle;   /* set TCP_KEEPIDLE */
  unsigned int tcp_keep_intvl;  /* set TCP_KEEPINTVL */
  unsigned int tcp_keep_cnt;    /* set TCP_KEEPCNT */
  unsigned int max_keep_alive;  /* maximum keep-alive session (default=100) */
  const char *proxy_http_version;/* HTTP version of proxy "1.0" or "1.1" */
  const char *proxy_host;   /* Proxy Server host name */
  int proxy_port;       /* Proxy Server port (default = 8080) */
  const char *proxy_userid; /* Proxy Authorization user name */
  const char *proxy_passwd; /* Proxy Authorization password */
  const char *proxy_from;   /* X-Forwarding-For header returned by proxy */
  int status;           /* -1 when request, else error code to be returned by server */
  int error;
  int errmode;
  int errnum;
#ifndef WITH_LEANER
  struct soap_dom_element *dom;
  struct soap_dime dime;
  struct soap_mime mime;
  struct soap_xlist *xlist;
#endif
#if !defined(WITH_LEAN) || defined(SOAP_DEBUG)
  const char *logfile[SOAP_MAXLOGS];
  FILE *fdebug[SOAP_MAXLOGS];
  struct soap_mlist *mht[SOAP_PTRHASH];
#endif
#ifndef WITH_LEAN
  const char *wsuid;        /* space-separated string of element tags */
  const char *c14nexclude;  /* space-separated string of prefixes */
  struct soap_cookie *cookies;
  const char *cookie_domain;
  const char *cookie_path;
  int cookie_max;
#endif
#ifndef WITH_NOIO
  int ipv6_multicast_if; /* in6addr->sin6_scope_id IPv6 value */
  char* ipv4_multicast_if; /* IP_MULTICAST_IF IPv4 setsockopt interface_addr */
  unsigned char ipv4_multicast_ttl; /* IP_MULTICAST_TTL value 0..255 */
#ifdef WITH_IPV6
  struct sockaddr_storage peer; /* IPv6: set by soap_accept and by UDP recv */
#else
  struct sockaddr_in peer;  /* IPv4: set by soap_connect/soap_accept and by UDP recv */
#endif
#endif
  size_t peerlen;
#if defined(WITH_OPENSSL)   /* OpenSSL */
  int (*fsslauth)(struct soap*);
  int (*fsslverify)(int, X509_STORE_CTX*);
  BIO *bio;
  SSL *ssl;
  SSL_CTX *ctx;
  SSL_SESSION *session;
  const char *dhfile;
  const char *randfile;
#elif defined(WITH_GNUTLS)      /* GNUTLS */
  int (*fsslauth)(struct soap*);
  void *fsslverify;
  gnutls_certificate_credentials_t xcred;   /* cert pointer */
  gnutls_anon_client_credentials_t acred;   /* anon pointer */
  gnutls_priority_t cache;          /* priority cache pointer */
  gnutls_session_t session;         /* session pointer */
  gnutls_dh_params_t dh_params;
  gnutls_rsa_params_t rsa_params;
#else               /* No SSL/TLS */
  void *fsslauth;       /* dummy members, to preserve struct size */
  void *fsslverify;
  void *bio;
  void *ssl;
  void *ctx;
  void *session;
  void *dh_params;
  void *rsa_params;
#endif
  unsigned short ssl_flags;
  const char *keyfile;
  const char *password;
  const char *cafile;
  const char *capath;
  const char *crlfile;
  char session_host[SOAP_TAGLEN];
  int session_port;
#ifdef WITH_C_LOCALE
  locale_t c_locale;        /* set to C locale by default */
#else
  void *c_locale;
#endif
#ifdef WITH_ZLIB
  z_stream *d_stream;       /* decompression stream */
  uLong z_crc;          /* internal gzip crc */
#else
  void *d_stream;       /* dummy members, to preserve struct size */
  soap_int32 z_crc;
#endif
  const char *z_dict;       /* support for zlib static dictionaries */
  unsigned int z_dict_len;
  short zlib_state;     /* SOAP_ZLIB_NONE, SOAP_ZLIB_DEFLATE, or SOAP_ZLIB_INFLATE */
  short zlib_in;        /* SOAP_ZLIB_NONE, SOAP_ZLIB_DEFLATE, or SOAP_ZLIB_GZIP */
  short zlib_out;       /* SOAP_ZLIB_NONE, SOAP_ZLIB_DEFLATE, or SOAP_ZLIB_GZIP */
  char *z_buf;          /* buffer */
  size_t z_buflen;
  unsigned short z_level;   /* compression level to be used (0=none, 1=fast to 9=best) */
  float z_ratio_in;     /* detected compression ratio compressed_length/length of inbound message */
  float z_ratio_out;        /* detected compression ratio compressed_length/length of outbound message */
#ifdef WMW_RPM_IO       /* VxWorks */
  void *rpmreqid;
#endif
#ifdef __cplusplus
  soap();
  soap(soap_mode);
  soap(soap_mode, soap_mode);
  soap(const struct soap&);
  virtual ~soap();
#else
  void (*dummy)(void);
#endif
};

which is later on used widely through the library. I needed to modify the behavior a bit, but even a simple line like

struct soap *soap;
...
// soap->error is 401 up to this point
soap->error = 0;
// soap->error is still 401, at least according to VS2008 debugger

First thing i did was look at the assembly:

soap->error = 0;
172A35D8  mov         eax,dword ptr [soap] 
172A35DB  mov         dword ptr [eax+191A4h],0 

while, &soap->error = 0x0cb3ead0 and soap = 0x0cb25930, and 0x0cb3ead0 - 0x0cb25930 = 0x191A0 which is 4 bytes less. So either the debugger is wrong , either the assembly, but since the library works, the doubts are highly on the debugger. Either way it is quite impossible to alter the code in these circumstances.

Any suggestions what could cause this ? Is my pointer arithmetic wrong somewhere? I tried

#pragma pack(push)
#pragma pack(1)
...
#pragma pack(pop)

around the structure definition but that did not help.

ismail
  • 46,010
  • 9
  • 86
  • 95
Rudolfs Bundulis
  • 11,636
  • 6
  • 33
  • 71
  • Perhaps there are inconsistent #ifdef's. – Raymond Chen Jan 27 '14 at 15:24
  • You do not debug a binary with an optimized build, are you? A lot of "variable value should have been x, I am seeing y" kind of errors observed in a debugger are actually due to optimizations making life difficult for debugger. – vhallac Jan 27 '14 at 17:26
  • @RaymondChen well i thought so too but the code that misbehaves is in the same translation unit (.cpp) file, so they could not be inconsistent, since there were no undef's or whatsoever after the structure. – Rudolfs Bundulis Jan 27 '14 at 21:30
  • @vhallac no it is a debug build. – Rudolfs Bundulis Jan 27 '14 at 21:30
  • Hm. If it is a C++ build, then the four byte discrepancy may be caused by the compiler inserting a vtable to the beginning of structure (though it really shouldn't, in this case). You can check offset of state (0 or 4?). If it is 0, then you can find where things go out of sync using a binary search-like detective work. – vhallac Jan 29 '14 at 17:28
  • @vhallac, I did already come to the point where I was leaning towards doing a by-variable address comparison to see where the offset goes wrong, but since I needed to add the functionality urgently I simply added what was needed without relying on the debugger, but the vtable thing did not come to my mind. Will check this out, but it sounds like a possibility since the gSoap generated proxy classes inherit from this struct. – Rudolfs Bundulis Jan 29 '14 at 17:43

2 Answers2

0

The four byte discrepancy might be introduced by a C++ compiler adding a vtable to the beginning of the structure. To verify the existence of such a constant difference, you can check the code generated when modifying the element at offset 0 (state).

vhallac
  • 13,301
  • 3
  • 25
  • 36
0

I encountered the same problem recently, I changed the structure alignment setting of the project in Visual Studio from default to zp1, then it worked fine.

Matt
  • 6,010
  • 25
  • 36
  • Thanks, the fixes I needed to do are already in, but I'll check this out - if it helps then at least I'll be aware of this in the future:) – Rudolfs Bundulis Jul 15 '15 at 21:23
  • @RudolfsBundulis, can you post your fix as the answer? I just found that my fix works for some member variables in that struct, for some not. – Matt Jul 20 '15 at 21:27
  • maybe you misunderstood me - I don't have a fix for this issue, with fixes I meant that I patched the proxies as needed w/o debugging so I do not need to solve this any more:) – Rudolfs Bundulis Jul 20 '15 at 21:39