0

On AIX 6.1, I have a piece of code where the argv is getting set to NULL somehow after a call to strdup. The exact same code was working on Linux, HPUX and Solaris.

Here's the excerpt from production code where I am getting core dump:

Makefile    
....
    CFLAGS += -I$(SERVER)/shared/interfaces \
              -DADAPTER_BUILD_DATE="\"$(shell date)\"" 
....

global.c

...
char *z_adapter_build_date = NULL;
...

shared.c

...
extern char *z_adapter_build_date;
...

test.c

   int main(int l_argc, char **l_argv)
{

    char                *lbasename;
    char                *ltmp;
    z_adapter_build_date = (char *)ADAPTER_BUILD_DATE;

    ltmp = strdup(l_argv[0]);
    lbasename = basename(ltmp);
    if ((zprogname = strdup(lbasename)) == NULL)
    {
        printf("strdup failed:\n");
        exit(1);
    }

....


$ dbx ./test
warning: tpm_builtin_fn.cc is newer than /xps/ceal_800/rel/server/lib/libsql.so
warning: trans_tux.cc is newer than /xps/ceal_800/rel/server/lib/libsql.so
warning: varmap.cc is newer than /xps/ceal_800/rel/server/lib/libsql.so

(dbx) [1] stop in main
(dbx)
(dbx) r 1
[1] stopped in main at line 113 in file "/u01/xps/800/src/test.c" ($t1)
  113       z_adapter_build_date = (char *)ADAPTER_BUILD_DATE;
(dbx) p l_argv[1]
"1"
(dbx) n
stopped in main at line 115 in file "/u01/xps/800/src/test.c" ($t1)
  115       ltmp = strdup(l_argv[0]);
(dbx) p l_argv[1]
(nil)

However, may be a red herring, there are mismatches in the version of cc files above which I guess could be one reason. I am not quite sure what is causing the value to become NULL.

Phalgun
  • 1,181
  • 2
  • 15
  • 42
  • 1
    Have you included the header file that declares `strdup()`? – Barmar Sep 13 '16 at 19:06
  • Show the complete code. – Roland Illig Sep 13 '16 at 19:16
  • 1
    It appears the problem occurs during execution of line 113... Your example doesn't show how "z_adapter_build_date" is defined, or how "ADAPTER_BUILD_DATE" is defined... – TonyB Sep 13 '16 at 19:37
  • I think you're misreading the gdb results. When gdb stops at line 115, that's *before* it executes the `strdup()` at that line. The change to the value of `l_argv[1]` thus happened as a result of the previous line (113). I'm inclined to guess, therefore, that there's some kind of screwy aliasing going on with `z_adapter_build_date`. – John Bollinger Sep 13 '16 at 19:54
  • @john Bollinger, dbx result changes after execution of line 115, l_argv + 1 becomes null. Also the necessary headers have all been included. – Phalgun Sep 13 '16 at 20:00
  • @Phalgun, sorry, I wrote `gdb` when in fact you're using `dbx`. I'm not prepared to study its manual for this purpose, but I find your assertion very surprising. Surely when `dbx` is "stopped in main at line 115" that means that the code on line 115 (the `strdup()`) is what it will execute *next*, not what it just finished executing. At least that is the behavior of all source-level debuggers I have ever used. – John Bollinger Sep 13 '16 at 20:08
  • @john Bollinger, you are right. It was before the execution of line 115. – Phalgun Sep 13 '16 at 20:16
  • @TonyB I've updated the description with definition for ADAPTER_BUILD_DATE – Phalgun Sep 13 '16 at 20:22
  • 2
    There are nowhere near enough quotes in `-DADAPTER_BUILD_DATE=$(shell date)` for it to be compiling. You should be using `-DADAPTER_BUILD_DATE='"$(shell date)"'` so that `make` expands the `$(shell date)`, the C compiler command line sees `-DADAPTER_BUILD_DATE='"Tue Sep 13 13:33:12 PDT 2016"'` and the code sees `z_adapter_build_date = (char *)"Tue Sep 13 13:33:12 PDT 2016";` (where the cast is mostly superfluous, but `z_adapter_build_date` should be a `const char *` anyway — most likely). You've not produced an MCVE ([MCVE]) yet, what's the real problem? Please update the question (again). – Jonathan Leffler Sep 13 '16 at 20:35

2 Answers2

1

This looks highly suspicious:

-DADAPTER_BUILD_DATE=$(shell date)  

, especially when combined with

z_adapter_build_date = (char *)ADAPTER_BUILD_DATE;

You evidently want to inject a date string, but I don't see how what you present will give you that, as I don't see from where will come the quotation marks needed to make the expansion of ADAPTER_BUILD_DATE be a string literal. I don't think it would compile at all on Linux, but if the date command on AIX returns an all-numeric date then it might compile there. You could consider capturing the preprocessed output to see what is actually going on there.

Note, by the way, that if -DADAPTER_BUILD_DATE did expand to a string literal, then you oughtn't to need to cast it to char *. After the literal decays to a pointer, that should be its type already.

Anyway, if you're trying to inject a string literal via that macro, then you probably wnat something more like this in your makefile:

-DADAPTER_BUILD_DATE='"$(shell date)"'

The double quotes need to be carried through into the macro definition, but the option needs to pass through shell quote removal. The single quotes protect the double quotes from quote removal, themselves being removed instead. make itself ignores all the quotation marks.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
  • I agree with that diagnosis of trouble — and the provisional solution — but I regard it as something of a missing MCVE and 'question must be updated (again)', and hence comment-worthy rather than answer-worthy. But I'm glad someone agrees with my diagnosis. – Jonathan Leffler Sep 13 '16 at 20:37
0

If z_adapter_build_date is some C++ object such that the assignment to it triggers function calls (assignment operator from const char *, etc) it could be that some of those functions work with string buffers on the stack which are being overrun, thus clobbering the local variables in main that happen to be spilled out of registers and into the stack frame.

Kaz
  • 55,781
  • 9
  • 100
  • 149