- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
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.
Link Copied
5 Replies
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I'd have to see an actual and complete code sample - can you try attaching it to a reply here?
Steve
Steve
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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:
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:
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:
Here's a little bit of the c-code:
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.
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*64character 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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
Also, null terminate all your string literals that are passed to the C routines as in
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
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.
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
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.

Reply
Topic Options
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page