From: Jen on
Hi,
I am using MFC to tun SQL queries. I need to create a complex query
based on user defined parameters, and am having some trouble.

The program actually works great, and displays my results perfectly.
However, if the following line of code is executed, I get an error when
I finally close my program.

My code that causes the problem is:

CString ProfileQuery, queryStr;

ProfileQuery = "SELECT ";
int paramNum = GetUserDefinedParamNum();

queryStr.Format("Avg(IIf(E1.Param%d=0,0,(T1.Param%d-E1.Param%d)/(E1.Param%d)*100))",paramNum+1,paramNum+1,paramNum+1,paramNum+1);
//problem line
ProfileQuery += queryStr;


If I remove these lines, the program runs fine. The trouble seems to
be with the line queryStr.Format... If I remove the 4 occurences of %d
from that line, and replace it with an integer (say 1), it works fine.

If I run as shown, I get the following error when closing my program.
Application Error: The instruction at "0x7c809783" referenced memory
at "0x012f93b4". The memory could not be "written". Click on OK to
terminate the program.

Any ideas? I look at the values returned, and they all look fine.
paramNum returns 5 for my latest try, and the string has everything in
it like I want.

I don't know what else to try! Thanks in advance for your help!
Jen

From: Joseph M. Newcomer on
I've never seen CString::Format fail; I would be more inclined to suspect that someone is
damaging a string, and when you have this formatting done, the memory allocation patterns
make something vulnerable to the damage, and when you just have a literal string, the
memory allocation patterns are different so the damage is "harmless".

I just wrote an essay on memory damage, on my MVP Tips site, which you might find useful.

For example, look at my
ASSERT(_heapchk() == _HEAPOK);
and scatter that line around in your code as I describe. Place it before and after the
formatting, for example, and there's a good chance it will reveal nothing. But if you put
it in the OnIdle handler, you might see some interesting problems arise.
joe

On 20 Aug 2006 11:44:16 -0700, "Jen" <leonard522(a)aol.com> wrote:

>Hi,
>I am using MFC to tun SQL queries. I need to create a complex query
>based on user defined parameters, and am having some trouble.
>
>The program actually works great, and displays my results perfectly.
>However, if the following line of code is executed, I get an error when
>I finally close my program.
>
>My code that causes the problem is:
>
> CString ProfileQuery, queryStr;
>
> ProfileQuery = "SELECT ";
> int paramNum = GetUserDefinedParamNum();
>
>queryStr.Format("Avg(IIf(E1.Param%d=0,0,(T1.Param%d-E1.Param%d)/(E1.Param%d)*100))",paramNum+1,paramNum+1,paramNum+1,paramNum+1);
>//problem line
> ProfileQuery += queryStr;
>
>
>If I remove these lines, the program runs fine. The trouble seems to
>be with the line queryStr.Format... If I remove the 4 occurences of %d
>from that line, and replace it with an integer (say 1), it works fine.
>
>If I run as shown, I get the following error when closing my program.
>Application Error: The instruction at "0x7c809783" referenced memory
>at "0x012f93b4". The memory could not be "written". Click on OK to
>terminate the program.
>
>Any ideas? I look at the values returned, and they all look fine.
>paramNum returns 5 for my latest try, and the string has everything in
>it like I want.
>
> I don't know what else to try! Thanks in advance for your help!
>Jen
Joseph M. Newcomer [MVP]
email: newcomer(a)flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
From: Ed Weir (ComCast) on
"Joseph M. Newcomer" <newcomer(a)flounder.com> wrote in message
news:pishe2p7kipbq3f6t1ebip2qf2aftpno9o(a)4ax.com...
| I've never seen CString::Format fail;[snip]

Well I have. I have always traced the problem (IIRC) to strex.cpp, where
Format is attempting to calculate the amount of memory it's going to need
for the formatting operation. The problem is, it cannot very well predict
the length of a %d so it makes an educated guess. Fortunately, the result
is usually OK and the formatting goes on without a hitch (it eventually
calls sprintf!...).

In your case, you can try the workaround I used; malloc a buffer sure to be
big enough (like 2048 or whatever) and sprintf into it. No need to worry
about UNICODE; sprintf is mapped to the correct function in UNICODE builds
for you. Then assign or add the result to the CString and free the buffer.
Messy, but it circumvents the AV or ASSERT without having to rewrite
strex.cpp (where the actual corruption had occurred). Of course, you could
also try deriving from CString... if you have the time.

-- Ed.

-----------------------------------------------------
In dictatorships, you need courage to fight evil; in the free world, you
need courage to see the evil."
Natan Sharansky

F9E7707A2AF502D0A899C6ACB43A2D35EB7E->bin->b64

From: Joseph M. Newcomer on
In VS.NET, strex.cpp has something to do with hash code computations, but nothing to do
with strings. In the case of VS.NET, it calls vcsprintf to compute the actual number of
bytes required; no guessing is involved, and the computation is precise.

In VS6, strex.cpp does "guess", but it "guesses" by assuming the value is 32 if there is
no explicit width given, in which case an explicit field width that is > 32 will give that
exact width, otherwise it overguesses at 32. I just read the code:

switch (*lpsz)
{
// integers
case 'd':
case 'i':
case 'u':
case 'x':
case 'X':
case 'o':
if (nModifier & FORCE_INT64)
va_arg(argList, __int64);
else
va_arg(argList, int);
nItemLen = 32;
nItemLen = max(nItemLen, nWidth+nPrecision);
break;

Given his integer value is "1", then a 32-character buffer allowance for each %d seems
adequate.

I've done vastly more complex formatting without a problem; can you demonstrate, in a
single CString::Format call, that this problem actually exists?

sprintf is not mapped to the "correct function in Unicode". I looked at the code; sprintf
(see c:\Program Files\Micrsoft Visual Studio\vc98\crt\src\sprintf.c, for c: the drive on
which you installed VS) handles 8-bit character formatting only; the formatting string is
8-bit and %s assumes 8-bit string arguments. swprintf handles Unicode only (see
c:\Program Files\Microsoft Visual Studio\vc98\crt\swprintf.c), which uses a WCHAR
formatting string and %s is assumed to refer to Unicode strings. _stprintf (defined in
tchar.h) is mapped according to the compilation mode. Look at output.c in the CRT; its
code is common (compiled separately) for ANSI and Unicode builds, and I don't see where
sprintf is magically transformed in any way in how these functions are called.
joe

On Sun, 20 Aug 2006 18:16:08 -0700, "Ed Weir \(ComCast\)" <Anon(a)Maus.duh> wrote:

>"Joseph M. Newcomer" <newcomer(a)flounder.com> wrote in message
>news:pishe2p7kipbq3f6t1ebip2qf2aftpno9o(a)4ax.com...
>| I've never seen CString::Format fail;[snip]
>
>Well I have. I have always traced the problem (IIRC) to strex.cpp, where
>Format is attempting to calculate the amount of memory it's going to need
>for the formatting operation. The problem is, it cannot very well predict
>the length of a %d so it makes an educated guess. Fortunately, the result
>is usually OK and the formatting goes on without a hitch (it eventually
>calls sprintf!...).
>
>In your case, you can try the workaround I used; malloc a buffer sure to be
>big enough (like 2048 or whatever) and sprintf into it. No need to worry
>about UNICODE; sprintf is mapped to the correct function in UNICODE builds
>for you. Then assign or add the result to the CString and free the buffer.
>Messy, but it circumvents the AV or ASSERT without having to rewrite
>strex.cpp (where the actual corruption had occurred). Of course, you could
>also try deriving from CString... if you have the time.
>
>-- Ed.
>
>-----------------------------------------------------
>In dictatorships, you need courage to fight evil; in the free world, you
>need courage to see the evil."
>Natan Sharansky
>
>F9E7707A2AF502D0A899C6ACB43A2D35EB7E->bin->b64
Joseph M. Newcomer [MVP]
email: newcomer(a)flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
From: Ed Weir (ComCast) on
"Joseph M. Newcomer" <newcomer(a)flounder.com> wrote in message
news:a5jie2l7sqgf0gjl0j5c7jenng2hoio42g(a)4ax.com...
| In VS.NET, strex.cpp has something to do with hash code computations, but
nothing to do
| with strings. In the case of VS.NET, it calls vcsprintf to compute the
actual number of
| bytes required; no guessing is involved, and the computation is precise.
|
| In VS6, strex.cpp does "guess", but it "guesses" by assuming the value is
32 if there is
| no explicit width given, in which case an explicit field width that is >
32 will give that
| exact width, otherwise it overguesses at 32. I just read the code:

[code snipped]

I bugged this problem while I was at MS years ago. Even still, I have had
this ugly beast rear its head once more while formatting a .eml package with
embedded modifiers. IIRC it was a problem with the form
StringOfSomeLength%d (or other token) where the recursive descent parser (as
you pasted from strex.cpp) actually miscalculated the length in certain
cases. Sorry, I don't have the cases. The cases were clearcut and
reproducable however.

| Given his integer value is "1", then a 32-character buffer allowance for
each %d seems
| adequate.
|
| I've done vastly more complex formatting without a problem; can you
demonstrate, in a
| single CString::Format call, that this problem actually exists?
|
| sprintf is not mapped to the "correct function in Unicode". I looked at
the code; sprintf

Sorry, it's _stprintf. My bad... see tchar.h for details

| (see c:\Program Files\Micrsoft Visual Studio\vc98\crt\src\sprintf.c, for
c: the drive on
| which you installed VS) handles 8-bit character formatting only; the
formatting string is
| 8-bit and %s assumes 8-bit string arguments. swprintf handles Unicode
only (see
| c:\Program Files\Microsoft Visual Studio\vc98\crt\swprintf.c), which uses
a WCHAR
| formatting string and %s is assumed to refer to Unicode strings.
_stprintf (defined in
| tchar.h) is mapped according to the compilation mode. Look at output.c in
the CRT; its
| code is common (compiled separately) for ANSI and Unicode builds, and I
don't see where
| sprintf is magically transformed in any way in how these functions are
called.
| joe

You will have to look at TCHAR.H. A small correction: the generic mapping
for MBCS/UNICODE is actually _stprintf, not sprintf. To wit:
/* Formatted i/o */

#define _tprintf wprintf
#define _ftprintf fwprintf
#define _stprintf swprintf
#define _sntprintf _snwprintf
#define _vtprintf vwprintf
#define _vftprintf vfwprintf
#define _vstprintf vswprintf
#define _vsntprintf _vsnwprintf
#define _tscanf wscanf
#define _ftscanf fwscanf
#define _stscanf swscanf

for UNICODE.

| On Sun, 20 Aug 2006 18:16:08 -0700, "Ed Weir \(ComCast\)" <Anon(a)Maus.duh>
wrote:
|
| >"Joseph M. Newcomer" <newcomer(a)flounder.com> wrote in message
| >news:pishe2p7kipbq3f6t1ebip2qf2aftpno9o(a)4ax.com...
| >| I've never seen CString::Format fail;[snip]
| >
| >Well I have. I have always traced the problem (IIRC) to strex.cpp, where
| >Format is attempting to calculate the amount of memory it's going to need
| >for the formatting operation. The problem is, it cannot very well
predict
| >the length of a %d so it makes an educated guess. Fortunately, the
result
| >is usually OK and the formatting goes on without a hitch (it eventually
| >calls sprintf!...).
| >
| >In your case, you can try the workaround I used; malloc a buffer sure to
be
| >big enough (like 2048 or whatever) and sprintf into it. No need to worry
| >about UNICODE; sprintf is mapped to the correct function in UNICODE
builds
| >for you. Then assign or add the result to the CString and free the
buffer.
| >Messy, but it circumvents the AV or ASSERT without having to rewrite
| >strex.cpp (where the actual corruption had occurred). Of course, you
could
| >also try deriving from CString... if you have the time.
| >
| >-- Ed.
| >
| >-----------------------------------------------------
| >In dictatorships, you need courage to fight evil; in the free world, you
| >need courage to see the evil."
| >Natan Sharansky
| >
| >F9E7707A2AF502D0A899C6ACB43A2D35EB7E->bin->b64
| Joseph M. Newcomer [MVP]
| email: newcomer(a)flounder.com
| Web: http://www.flounder.com
| MVP Tips: http://www.flounder.com/mvp_tips.htm