From: Jen on 20 Aug 2006 14:44 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 20 Aug 2006 19:41 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 20 Aug 2006 21:16 "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 21 Aug 2006 02:25 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 21 Aug 2006 07:04 "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
|
Next
|
Last
Pages: 1 2 3 4 5 6 Prev: CRichEditCtrl usage Next: What to do with First-Chance exception |