Thanks for the question, Dhruba.
Asked: January 07, 2005 - 10:45 am UTC
Last updated: January 10, 2005 - 2:08 pm UTC
Version: 8.1.7
Viewed 1000+ times
You Asked
Hi Tom,
Hope you are well.
Following is a piece of code in our billing program .
---------------------------------------------------------------
varchar g_systemdate[8];
......
EXEC SQL SELECT to_char(gnvgen.systemdate,'YYYYMMDD')
INTO :g_systemdate
FROM DUAL;
g_systemdate.arr[g_systemdate.len]='\0';
......
billsummaryfile=(char *)malloc(512);
.......
sprintf(billsummaryfile,"%s/xml/%s/%s/%s_%s_%s.xml",
l_output_dir.arr,
g_systemdate.arr,
g_bill_batch_seq.arr,
l_frrec_account_num.arr,
bill_seq_str.arr,
bill_req_seq_str.arr);
l_billsummaryfile = fopen(billsummaryfile, "w");
if (!(l_billsummaryfile))
{
printf("File Open error - File Name :%s\n",billsummaryfile);
}
------------------------------------------------------------------
Obviously g_systemdate[8] should be g_systemdate[9] - it's a big mistake, I accept.
I have a question though.
This program ran for few years and billed million of customers
and did not fall over .
Once this program was modified and compiled in another environment and while executed it created extra characters at the end of g_systemdate and fallen over.
Now if we run this executable - every time it falls over.
If we run the previous executable it never falls over.
In both cases we use Pro*C/C++: Release 8.1.7.3.0 in Oracle 8.1.7
and gcc .
Is there any explanation of this behaviour ?
thanks,
dhruba.
and Tom said...
<quote>
Obviously g_systemdate[8] should be g_systemdate[9] - it's a big mistake, I
accept.
</quote>
it is not a mistake, you are using the varchar2 type -- which is NOT null terminated. So, YYYYMMDD fits in a varchar2 [8] rather nicely. The mistake you made is that:
g_systemdate.arr[g_systemdate.len]='\0'
is NOT YOUR MEMORY SPACE -- YOU DO NOT HAVE ANY RIGHT TO PUT ANYTHING THERE.
The problem is in your C code, it is relying on a null terminated string but VARCHAR types are NOT null terminated. In other words -- you got EXCESSIVELY lucky in the past and there just happened to be a binary zero in memory after your variable!!
The immediate correction you MUST MAKE to all of your code is:
a) either make darn sure your varchar's are one bigger than they need to be so you can actually stuff the null terminator in there or
b) use the standard C formatting stuff to print out only the characters that you have the right to touch:
sprintf(billsummaryfile,"%.*s/xml/%.*s/%.*s/%.*s_%.*s_%.*s.xml",
l_output_dir.len, l_output_dir.arr,
g_systemdate.len, g_systemdate.arr,
g_bill_batch_seq.len, g_bill_batch_seq.arr,
.......
I do b) regularly. %.*s will expect you to send two things
a) the max number of characters to print
b) the pointer to the string
this has ABSOLUTELY NOTHING to do with the version of Oracle -- it has everything to do with a really bad memory overwrite that is probably all throughout your code!
Rating
(2 ratings)
Is this answer out of date? If it is, please let us know via a Comment