Archived

This forum has been archived. Please start a new discussion on GitHub.

java client with VC6.0 server: unknown c++ exception?

I'm a pretty new ICE user, but I have managed to get quite a few things running that are actually useful (nice system!)

however, I'm hitting what may be either a bug or evidence that I'm doing something wrong.

I have a simple interface that looks like this:
#ifndef _POSE_SERVER_ICE_
#define _POSE_SERVER_ICE_

module PoseModule {

  struct Pose {
    string ObjectName;
	double x;
	double y;
	double z;
	double roll;
	double pitch;
	double yaw;
  };

  exception ObjectNotFound {
    string requestedObjectName;
  };

  sequence<Pose> PoseSequence;
  sequence<string> StringSequence;

  interface PoseServer {
    nonmutating StringSequence getTrackedObjectNames();
    nonmutating Pose getPose(string objectName) throws ObjectNotFound;
    nonmutating PoseSequence getAllPoses();

	void setHomeFrame(string objectName) throws ObjectNotFound;
  };
};

#endif

so I'm defining a PoseServer that can serve up the positions of a set of objects. I have a few clients written that use this information; these are all written in Java, and run on both Linux and Windows. I have two servers that produce different behaviors, both written in C++. One of the servers runs on Linux, and one runs on Windows. Here's the interesting part: I can only call the functions that take no arguments when the communication is between a java client and a windows c++ server (the java client can be running on either linux or windows and the behavior is the same). The call to getPose(string objectName), for example, causes an Ice.UnknownException with unknown="unknown c++ exception" to be thrown in the java client. As far as I can tell, the servant function is never even reached. The functions taking no arguments work fine regardless of which servant is running. And the functions which take arguments run correctly when the servant is running on Linux.

does this sound familiar to anyone? I am confused.

I'll try porting my simple Linux servant thing to windows, to see if the identical code runs on that side. the windows servant has all sorts of GUI stuff in it which makes it impractical to port back to linux.

thanks for any insight!

Comments

  • more information

    so apparently the servant is getting called. My windows port of my linux servant is a console app, so I'm seeing debugging messages now, and I get:

    .....exe: warning: dispatch exception: unknown c++ exception
    identity: PoseServer
    facet:
    operation: getPose

    apparently this exception is occurring before my actual servant implementation function of getPose is called (my breakpoint isn't hit, nor is my printf showing anything before this exception happens).

    I have a suspicion that this may have something to do with stlport, which appears to be giving me grief elsewhere. In particular, I can't use the Ice::stringToIdentity() function on windows - I get a deadlock on some stlport mutex. Instead, I have to do

    Ice::identity id;
    id.name = "PoseServer";

    which is apparently all that the Ice::stringToIdentity is doing with my string (since nothing needs to be quoted).
  • claykunz wrote:
    so apparently the servant is getting called. My windows port of my linux servant is a console app, so I'm seeing debugging messages now, and I get:

    .....exe: warning: dispatch exception: unknown c++ exception
    identity: PoseServer
    facet:
    operation: getPose

    The client receives an UnknownException if the server code throws an exception that is not an Ice run time or user exception. For example, if the operation in the server throws something like a char, or std::bad_alloc, or whatever, the client gets to see an UnknownException.
    apparently this exception is occurring before my actual servant implementation function of getPose is called (my breakpoint isn't hit, nor is my printf showing anything before this exception happens).

    Just to be sure, insert a statement such as
    cerr << "operation X called" << endl;
    
    as the first line of code in operation implementation in the servant. (Be sure to print to stderr, not stdout, so you get unbuffered output.)
    I have a suspicion that this may have something to do with stlport, which appears to be giving me grief elsewhere. In particular, I can't use the Ice::stringToIdentity() function on windows - I get a deadlock on some stlport mutex.

    I would first ensure that you have a working Ice installation. Do all the tests pass? And can you run all the Ice demos?

    Cheers,

    Michi.
  • matthew
    matthew NL, Canada
    You should also keep in mind that under Windows an unknown exception can often mean an access violation since this raises a structured exception which MS unwisely decided to mix with the C++ exception model and catch with ... If you run your app in the VC 6 debugger be sure to change debug/exceptions "access violation" to "Stop always" instead of "Stop if not handled".

    Regards, Matthew
  • "... which MS unwisely decided to mix"

    Tangential, off-topic and all that.

    To be very fair MS does not advocate mixing C++ exception model with structured exception handling. That much is very clearly stated in the MSDN documentation. There are also list of things you must look out for if you happen to mix C and C++ code and you want to use structured exception for the C part.

    I don't have links handy but the Gods of Google can find anything for you in a matter of nanoseconds.
  • thanks for the quick replies!

    I haven't tried any of the testers, because I installed from the binary distribution - it looks to me like the testers are only included in the source distribution. I have managed to build and run one of the simple demos (the hello world client & server) without trouble. I'll try to find a slightly more complex demo and see how that goes.

    meanwhile, I toggled the access violation/exception switch (thanks for the tip) and sure enough, that's what's going on. The backtrace shows that the access violation is happening before my servant's function is being reached:
    STL::__owned_link::_Owner() line 275 + 3 bytes
    _STL::__stl_debug_engine<bool>::_Stamp_all(_STL::__owned_list * 0x0181d740, _STL::__owned_list * 0x0181d644) line 355 + 8 bytes
    _STL::__stl_debug_engine<bool>::_Swap_owners(_STL::__owned_list & {...}, _STL::__owned_list & {...}) line 391 + 13 bytes
    _STL::__owned_list::_Swap_owners(_STL::__owned_list & {...}) line 331 + 13 bytes
    _STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> >::swap(_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> > & {...}) line 515
    IceInternal::BasicStream::read(_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> > & {...}) line 1371 + 66 bytes
    PoseModule::PoseServer::___getPose(IceInternal::Incoming & {...}, const Ice::Current & {...}) line 784 + 15 bytes
    PoseModule::PoseServer::__dispatch(IceInternal::Incoming & {...}, const Ice::Current & {...}) line 855 + 19 bytes
    IceInternal::Incoming::invoke(const IceInternal::Handle<IceInternal::ServantManager> & {...}) line 178 + 68 bytes
    Ice::ConnectionI::invokeAll(IceInternal::BasicStream & {...}, int 1, int 3, unsigned char 0, const IceInternal::Handle<IceInternal::ServantManager> & {...}, const IceInternal::Handle<Ice::ObjectAdapter> & {...}) line 2226
    Ice::ConnectionI::message(IceInternal::BasicStream & {...}, const IceInternal::Handle<IceInternal::ThreadPool> & {...}) line 1280
    IceInternal::ThreadPool::run() line 622 + 56 bytes
    IceInternal::ThreadPool::EventHandlerThread::run() line 836 + 31 bytes
    startHook(void * 0x003aaaf8) line 206 + 29 bytes
    _threadstartex(void * 0x003aae00) line 212 + 13 bytes
    KERNEL32! 7c80b50b()
    

    my read of this is that the STL code is getting an access violation in the part where it's demarshalling the argument to the function. incidentally, at this point, I'm using a VC++ client with the VC++ server, just to keep things simple.

    the line in ___getPose where the call to read() is happening looks like:
    ::IceInternal::DispatchStatus
    PoseModule::PoseServer::___getPose(::IceInternal::Incoming& __inS, const ::Ice::Current& __current) const
    {
       ::IceInternal::BasicStream* __is = __inS.is();
        ::IceInternal::BasicStream* __os = __inS.os();
        ::std::string objectName;
        __is->read(objectName);
    

    so for now, I'm going to look at the demo programs and find one that passes a string as an arg from client to server, and see what happens.

    again, thanks for the quick replies.
  • MFC hello client & server OK

    so the printer client & server demos run fine, so my next attempt to further complicate things was to bring MFC into the picture (the server program that has the access violation is an MFC application). I modified the MFC hello demo so that a string is passed through the sayHello() function, and that also works fine. at this point, I guess I'm going to have to wade through all the various compiler & linker switches to see what I'm doing differently between the functioning demo program and the non-functioning server...

    the fact that I'm pretty new at windows programming doesn't help much (I'm really a linux person.....)

    I'll also try to get the tests running; that would be a nice sanity check.
  • bernard
    bernard Jupiter, FL
    Also make sure you're using the STLPort that came with your Ice binary distribution: the include must be first in your list of include directories as described in the README.txt

    Cheers,
    Bernard
  • stlport

    yes, I have

    c:\ice-2.1.2-vc60\include\stlport

    at the top of the include files directory list under options/directories in vc6.0

    so just for kicks, I switched my project from the debug configuration to the release configuration, and switched from using iced.lib and iceutild.lib to ice.lib and iceutil.lib, and now it works. I understand that this also switches off the stlport debug flags, which is why I tried it (since the access violation was happening from within an stlport debugging function).

    while that's nice, I still want to be able to debug my program, so ideally I'd leave it in the debugging configuration. also, the fact that stlport was hitting a seg fault shows me that I have something else configured wrong.

    is there something I need to fix with the runtime-library ordering? I'm not sure how windows does it, but perhaps the stlport runtime lib needs to be loaded before (or perhaps instead of) some MS runtime that is confusing things.

    actually, at this point I should probably try to learn some things from the stlport web pages...
  • confused, but it works now

    ok, I finally have this thing working. I think this goes back to the fact that I'm a newbie at windows developing, but what I did was to add stlport_vc6_stldebug.lib to my link line, which apparently fixed things. I may have also been in trouble by not having the latest service pack of vc6.0 installed on my machine, but I'm fixing that now.

    if anyone's interested, the link input pane of my project settings now contains something like:

    object/library modules:

    iced.lib iceutild.lib stlport_vc6_stldebug.lib MG_Matrix.lib VZOutput.lib RobonautAPId.lib ws2_32.lib

    (the mg_matrix, vzoutput, and robonautapid libs are all libs that this thing depends upon; ws2_32.lib apparently contains socket code that robonautapid.lib requires).

    ignore libraries:
    libcd,msvcrt,libc

    I still have yet to comprehend why these libraries have to be explicitly excluded; if they're left in I get warnings about conflicting libraries. again, I'm a linux person :)



    thanks to all the zeroc folks who replied - I really appreciate the help.

    Clay
  • mes
    mes California
    Hi,

    It should not be necessary to explicitly link against the STLport library. If you have a look at the Ice project files, you'll see that they don't do this (which is convenient because it doesn't cause problems when building with Visual Studio .NET).

    If your project settings are correct, the STLport header file automatically selects the correct library via a pragma statement.

    I suspect you're still missing a project setting. For example, to build a program with debugging enabled, you should use /MDd. This corresponds to the Project Settings/C++/Code Generation/Use runtime library setting of "Debug Multithreaded DLL".

    Another option might be to use one of the Ice project files as a starting point for your own project.

    Take care,
    - Mark
  • yes, I'm definitely using the multithreaded DLL here. I would have preferred to start with an ICE demo project, but unfortunately I was adding an ICE servant object to an already-written program. I'll keep poking at it. For now I'm happy that the thing works.

    my project settings are:
    /nologo /MDd /W3 /Gm /GR /GX /ZI /Od /I "." /I "../VZFiles" /I "C:\Program Files\Phoenix Technologies\VZSoft SDK\Inc" /I "..\RobonautAPI\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_AFXDLL" /D "_MBCS" /FR"Debug/" /Fo"Debug/" /Fd"Debug/" /FD /GZ /c
    

    apparently this doesn't include the link line; those project settings are:
    iced.lib iceutild.lib stlport_vc6_stldebug.lib MG_Matrix.lib VZOutput.lib RobonautAPId.lib ws2_32.lib /nologo /subsystem:windows /incremental:yes /pdb:"Debug/VZDaemon.pdb" /debug /machine:I386 /nodefaultlib:"libcd" /nodefaultlib:"msvcrt" /nodefaultlib:"libc" /out:"Debug/VZDaemon.exe" /pdbtype:sept /libpath:"../VZFiles" /libpath:"C:\Program Files\Phoenix Technologies\VZSoft SDK\Lib" /libpath:"..\RobonautAPI\lib" /libpath:"..\rmp\ndds"
    

    Honestly, I think you shouldn't spend too much time helping me debug this (since it works now) -- I just copied the lines above in case anyone is curious.

    (yeah, the program I'm adding the servant to uses NDDS -- the folks who wrote the program use NDDS to ship their data around, and me and the folks I work with want to stay as far from NDDS as possible. but only one process can run which talks to the hardware that computes the info we all care about. so now we've got a single program that makes the same data available via both ndds and ICE).
  • one last snippet

    so if I look at debug/modules while my servant is running, I get a list of the DLL files that are pulled into the executable. if I have the stlport_vc6_stldebug.lib entry in my list of libraries to link against, then I get a big list of DLLs in the runtime. However, if I omit the stlport_vc6_stldebug.lib entry, I get a slightly different list. In particular:
    • both executables have stlport_vc6_stldebug46.dll pulled in at runtime
    • If I don't have that library explicitly in my link line, then I get two additional libraries: stlport_vc646.dll, and msvcp60.dll
    • the additional libraries appear further down the list than the stlport_vc6_stldebug library. I don't know why they're being pulled in.

    it's strange to me that removing a .lib file from my link line causes two additional .dll files to be pulled into the runtime. bizarre. My interpretation is that without explicitly listing the stlport_vc6_stldebug lib, apparently the runtime is pulling in both the debug and non-debug versions of the dll?
  • ok, I think I've got it

    I'm slowly coming to understand vc6... :)

    I'm not sure what the various precompiled header options mean - when I first picked up this project, it was set to "Use precompiled header file" which caused things to not work (apparently when you set it this way, all the .cpp files have to #include "stdafx.h" which the slice2cpp auto-generated .cpp file wasn't doing).

    switching to "Not using precompiled headers" caused the older code to break, because I had to remove all the #include "stdafx.h" everywhere, and all of a sudden things weren't defined. I re-added #include <afx.h> and #include <afxwin.h> to get things working again.

    finally, I started looking at documentation and demo projects (yeah, yeah, rtfm...), to see that several of them have "Automatic use of precompiled headers" using stdafx.h; I changed my stdafx.h to have the stlport debug flags enabled so that .cpp files which don't know about ICE still get the correct stlport symbols defined. However, I managed to not ensure that all the .cpp files once again had #include "stdafx.h" -- in the end, getting that line back into all my .cpp files causes the correct stlport DLL to be pulled into the runtime, without the non-debug stlport DLL, and without me explicitly listing the stlport .lib file on the link line (the slice2cpp-generated file still doesn't have the stdafx.h, but that's ok with this PCH setting). now it all works the way I'd expect it to. I swear I will never touch alt+f7 again. yeah, right.

    thanks again everyone for your help.

    Clay
  • matthew
    matthew NL, Canada
    rdilipk wrote:
    "... which MS unwisely decided to mix"

    Tangential, off-topic and all that.

    To be very fair MS does not advocate mixing C++ exception model with structured exception handling. That much is very clearly stated in the MSDN documentation. There are also list of things you must look out for if you happen to mix C and C++ code and you want to use structured exception for the C part.

    I don't have links handy but the Gods of Google can find anything for you in a matter of nanoseconds.

    They may not advocate it, but they do it :) catch(...) will catch SE's, which in my opinion, is mixing the SE and C++ exception handling mechanisms.
    try
    {
        // something that causes an access violation
    }
    catch(...)
    {
       // This will have caught the access violation structured exception
    }
    

    Matthew
  • matthew wrote:
    They may not advocate it, but they do it :) catch(...) will catch SE's, which in my opinion, is mixing the SE and C++ exception handling mechanisms.
    Matthew

    Once again I apologize for this off topic discussion.
    I agree with you to the extent an ellipsis C++ catch block can catch a SE. However there are well known idioms to take care of such situations. You may just have to install an interceptor function that will simply rethrow all SEs as C++ wrapped objects. You probably already know about it but check out _set_se_translator.