I have a Java application that launches a c++ helper application to retrieve information from a database (long story involving old 32 bit drivers). When I run the application manually, everything works perfectly, the c++ app runs and the Java app consumes the output. But when the java app runs as a launchd daemon the c++ helper app is returning with an exit value of 138, which I am pretty sure is a bus error 10.
After some pretty painful debugging, I have been able to determine that the signal is happening inside the ODBC driver itself. Since I don't have access to the source for the ODBC driver, my debugging options are limited.
My question is, am I missing anything in my launchd plist setup that could help explain what is happening or is there some sort of sandboxing going on that could be causing my problem?
I am an OSX novice, so I have very little experience with launchd in general.
Here is my current plist setup.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.my.package.name</string>
<key>ProgramArguments</key>
<array>
<string>java</string>
<string>-cp</string>
<string> my classpath</string>
<string> my main class</string>
</array>
<key>KeepAlive</key>
<true/>
<key>WorkingDirectory</key>
<string>my working directory</string>
</dict>
</plist>
Edit: I was able to get a crash file. Here is the error and stack trace. The dsn does appear to be set up correctly in the ini file, but I will keep digging.
I was able to get a crash file for it and here is the error and stack trace.
Exception Type: EXC_BAD_ACCESS (SIGBUS)
Exception Codes: KERN_PROTECTION_FAILURE at 0x0000000000000000
VM Regions Near 0:
--> __PAGEZERO 0000000000000000-0000000000001000 [ 4K] ---/--- SM=NUL /Users/*
VM_ALLOCATE 0000000000001000-00000000000f7000 [ 984K] ---/--- SM=NUL
Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0 libsystem_c.dylib 0x905c47f0 strlen + 16
1 com.4D.odbcdriver.v13 0x00308c14 _LoadOdbcIni() + 257
2 com.4D.odbcdriver.v13 0x00309546 _GetStringFromSystemDSN(char const*, char const*, char*, int) + 60
3 com.4D.odbcdriver.v13 0x0030967e SQLGetPrivateProfileStringW + 99
4 com.4D.odbcdriver.v13 0x002f0ec9 CHConnection::CreateStringFromDSN(wchar_t const*, wchar_t const*, wchar_t const*) + 225
5 com.4D.odbcdriver.v13 0x00307e4a internalSQLDriverConnectW(CHConnection*, void*, wchar_t*, short, wchar_t*, short, short*, unsigned short) + 311
6 com.4D.odbcdriver.v13 0x002fcafb SQLDriverConnectW + 129
7 org.iodbc.core 0x0025802d SQLDriverConnect_Internal + 2381
8 org.iodbc.core 0x00259373 SQLDriverConnect + 323
It's fairly obvious from the stack trace (when formatted for legibility ☺) what's going on here.
That's apparently the 4D ODBC driver. It's calling strlen()
. It has hit a NULL
pointer. strlen()
was called by a library-internal _LoadOdbcIni()
function.
My educated guess is that that ODBC driver uses an .INI
file, and that it gets the location of that file from an environment variable. You've got that environment variable set in your desktop configuration/shell profile/whatever. But it's not in your plist and not set when launchd
invokes your dæmon.
The code in the driver calls std::getenv()
to get the environment variable, which returns NULL
. The library wasn't written to expect the environment variable to be missing. It's simply calling strlen()
on that NULL
pointer without checking for it. And — bang! — SIGBUS
and KERN_PROTECTION_FAILURE
when trying to access address 0x0000000000000000
.
Find out from the 4D doco, whatever that is, or from 4D technical support, or from some other source, what environment variables are needed by the driver for that .INI
file (and anything else); and set it in your plist. man launchd.plist
for how to do that, by the way.