Software Archive
Read-only legacy content
17061 Discussions

character variable initialization, static property

dws
Beginner
956 Views
This subject has been touched upon before in this forum, but I think this is a new question.

It often happens that I declare a character variable and then pass it to a routine written in c to initialize it. The c routine uses the hidden length specifer to make sure it does not overwrite the variable and that it is padded with blanks. I do this hundreds of time throughout thousands of lines of code in various programs.

Now I have an instance that causes a segmentation fault and crashes. The errors occurs in a different, nominally unrelated part of my code.

Either of the following fixes the problem:
* Initializing the variable: character :: tok80*80 = ' ' ! = ''
* Making it static: character, static :: tok80

None of the following prevent the crash:
* Initializing the variable using an executible statment:
tok80 = ' '
* Compiling the code with the -static option
* Using the save attribute: character, save :: tok80*80

I don't know what is getting overwritten. Everything looks fine. The fault occurs in a different c routine of mine when it uses strncpy() on some other string variable.

I take this as a chance to learn something. Any ideas what is going on? Why would using the static specifier fix things? No matter where and when tok80 is allocated, and no matter if its address is stored in a register, doesn't the compiler has to give the call'ed routine an address to a valid memory location?

Also, if requiring static storage is the solution I don't see why I had to do anything since static storage is the default. I also tried the '-static' compile option. I also used the save specifier and the manual states: "Variables that are data-initialized, and variables
in COMMON and SAVE statements are always static."

No recursion is involved. The c-routines all have interfaces. The interfaces do not use any extensions to make the c-fortran connection, however. That is taken care of by the c-routine.

I'm using DIGITAL Fortran 90 V5.2-705 on Digital Unix. I also use this code with DVF 6.1a on a PC, but I haven't had a problem there yet.

Thanks,
Douglass.
0 Kudos
5 Replies
Steven_L_Intel1
Employee
956 Views
I'd have to see an actual and complete code sample - can you try attaching it to a reply here?

Steve
0 Kudos
dws
Beginner
956 Views
I could extract just the code sections that manipulate my character
variable, tok64, but even that would be large if I included the c
code. Let's see...

The fortran code that seems relevent is pretty minimal:


  
logical function analcmd_analysis(token, OKAY)  
use main_analysis_module  
  
character*(*) token  
logical OKAY  
  
character  filename*64, helpctrl*64  
  
character tok1*1, tok8*8, tok64*64, tok80*80  
  
  
elseif (testtok2(token, 'crash', 5, .TRUE., 'crash - test command'))  
then  
    if (.not. getto1(tok64, 'keep or delete (ABORT): ')) return  
  
elseif (...)  
  


analcmd_analysis() is called by the main program and is stand-alone -
not in a module. testtok2() is a c-routine that tests if
token contains the command 'crash'. The important routine is getto1()
which loads tok64 with the user's response. (These routines do more
than this. I'm just giving the gist.) The program does not crash right
away. If the if...elseif...elseif...else...endif structure of which this code
segment is a part reaches a clause near the end, it crashes. That clause is:


  
elseif (HelpPrint(0, 'Data Analysis Commands:', helpctrl, 1)) then  
    continue  
else  
    analcmd_analysis = .FALSE.  
    return  
endif  
OKAY = .TRUE.  
end function analcmd_analysis  


It crashes in HelpPrint(), another c-routine. Interestingly,
getto1() doesn't seem to crash if I use any other string variable,
filename for example, unless it is one of the variables defined in the
same line as tok64. Using tok80 crashes, for example.

If I can get an explanation of all this I'll be delighted, but I would be
content just to understand a few things.

Am I correct that use of the 'static' qualifier, as in 'character, static
:: tok64', should be superfluous since static is the default? Is there
a difference between making a variable static beause you've initialized it
versus using the save attribute? How does the compiler handle passing
an uninitialized variable whose first use is to be passed to another
routine? I somehow suspect that if getto1() were a fortran routine, you
would never get into this kind of trouble.

Thanks for looking at this.
Douglass.

-------------
I feel guilty over the length of this post, but in the name of
completeness, here is some information about getto1(). The interface
for it is:


  
logical function getto1(token, prompt)  
character*(*) token, prompt  
end  



Here's a little bit of the c-code:


  
int getto1_(char *token, char *prompt, int ilen1, int ilen2) {  
    int istat;  
  
    istat = getto1(token, Fprompt2c(prompt, ilen2));  
    Cstr2f(token, ilen1);  
    return istat;  
}  


and getto1() calls another routine... Fprompt2c() returns a null
terminated version of prompt. Cstr2f() removes the null termination in
token and pads with spaces. getto1() does not test for overflow of
token,
but is not overwriting it as near as I can tell usign the dbx debugger.
0 Kudos
Intel_C_Intel
Employee
956 Views
Hi,

I can't comment too specifically because there's not enough code to know for certain and I am not familiar with your platform. But I can make some general comments.
  • Always initialize variables (even strings) before passing them to C routines. Don't just rely on the C routine to initialize them.

  • And always null terminate strings going to C routines. Including literals.


  • So, for example, make sure that tok64 is null terminated even if you're using the passed length in some of the C routines. Hmmm, but notably not in 'getto1'. Maybe that should read
    istat = getto1(Fprompt2c(token, ilen1), Fprompt2c(prompt, ilen2));

    Also, null terminate all your string literals that are passed to the C routines as in
    HelpPrint(0, 'Data Analysis Commands:'C, helpctrl, 1)


    Somebody somewhere is stomping on some memory. Your two changes that 'fix' the problem may in fact not actually fix things. Kind of like when adding a print statement makes a crash stop occurring - it just changes where in memory the stomping happens.

    Anyway, hth,
    John
    0 Kudos
    dws
    Beginner
    956 Views
    Thanks John. I meant to write fix as "fix" since I was most likely just covering up the real bug. In fact, I was. The problem was in the Fprompt2c() routine.

    Any comments from anyone on the questions I had regarding the 'static' attribute? It's not part of the standard. When might you want to use this?

    Thanks,
    Douglass.
    0 Kudos
    dws
    Beginner
    956 Views
    Oh, I meant to ask. Why should one always initialize variables in the fortran part of the code, rather than let a c-routine take care of it? Isn't this more likely to cover up a mistake as avoid one? Had I initialized my character variable to begin with, my coding error would not have revealed itself in this case.

    At first I thought the answer might be that you don't know the state of a variable when its first use is to pass it to another routine. How will the compiler allocate it?Or, will it keep it in a register?

    Initializing it in the declaratio might force it be allocated in regular memory in some implementations (the DEC manual suggests this is the case for their compiler). I'd hate to have to rely on that kind of assumption, however.

    I don't think this is a concern, now. The compiler still has to pass an address in memory to the routine (I would think) so the routine, even a c-routine, needn't concern itself with this. All it has to do is return the result in the indicated memory location and the compiler will issue instructions that use the result.

    Douglass.
    0 Kudos
    Reply