Question

(MS VC++) Could you explain this to me ?

Asked by: andrey_2007

------------| MS VC++ Code |--------------------

typedef union
{
      int            i;
      char            c;
      short            t;
} MY_UNION;

namespace SOME_SPACE { static MY_UNION uni; };

#define MY_TYPE(s,m)   SetType(((s *)&SOME_SPACE::uni)->m)

int SetType(int nValue)
{
  return 5;
}

typedef struct
{
                int                        count1;
      char                        Buffer1[257];
      char                        Buffer2[257];
      char                        Buffer3[257];
      char                        Buffer4[257];
      char                        Buffer5[257];
      char                        Buffer6[257];
      char                        Buffer7[257];
      char                        Buffer8[257];
      char                        Buffer9[257];
      char                        Buffer10[257];
      char                        Buffer11[257];
      char                        Buffer12[257];
      char                        Buffer13[257];
      char                        Buffer14[257];
      char                        Buffer15[257];
      char                        Buffer16[257];
      char                        Buffer17[257];
      char                        Buffer18[257];
      char                        Buffer19[257];
      char                        Buffer20[257];
      char                        Buffer21[257];
      char                        Buffer22[257];
      char                        Buffer23[257];
      char                        Buffer24[257];
      char                        Buffer25[257];
      char                        Buffer26[257];
      char                        Buffer27[257];
      char                        Buffer28[257];
      char                        Buffer29[257];
      char                        Buffer30[257];
      char                        Buffer31[257];
      char                        Buffer32[257];
      char                        Buffer33[257];
      char                        Buffer34[257];
      char                        Buffer35[257];
      char                        Buffer36[257];
      char                        Buffer37[257];
      char                        Buffer38[257];
      char                        Buffer39[257];
      char                        Buffer40[257];
      char                        Buffer41[257];
      char                        Buffer42[257];
      char                        Buffer43[257];
      char                        Buffer44[257];
      char                        Buffer45[257];
      char                        Buffer46[257];
      char                        Buffer47[257];
      char                        Buffer48[257];
      char                        Buffer49[257];
      char                        Buffer50[257];
      char                        Buffer51[257];
      char                        Buffer52[257];
      char                        Buffer53[257];
      char                        Buffer54[257];
      char                        Buffer55[257];
      char                        Buffer56[257];
      char                        Buffer57[257];
      char                        Buffer58[257];
      char                        Buffer59[257];
      char                        Buffer60[257];
      char                        Buffer61[257];
      char                        Buffer62[257];
      char                        Buffer63[257];
      char                        Buffer64[257];
      char                        Buffer65[257];
      char                        Buffer66[257];
      char                        Buffer67[257];
      char                        Buffer68[257];
      char                        Buffer69[257];
      char                        Buffer70[257];
      char                        Buffer71[257];
                int                        mode;

} BIG_STRUCT;


void main()
{

      int res = MY_TYPE(BIG_STRUCT, mode);

}


---------------------End of Code---------------------------


Could you explain the following to me:

If BIG_STRUCT is as big as it is shown above, the program causes an exception (Access Violation).

If we have the BIG_STRUCT structure a few character strings shorter (Buffer strings 67-71 are commented out), the program works fine.  Whats going on?


-andrey

This Question has been solved and asker verified All Experts Exchange premium technology solutions are available to subscription members.

Subscribe now for full access to Experts Exchange and get

Instant Access to this Solution

  • Plus...
  • 30 Day FREE access, no risk, no obligation
  • Collaborate with the world's top tech experts
  • Unlimited access to our exclusive solution database
  • Never be left without tech help again

Subscribe Now

Asked On
2004-07-31 at 21:22:54ID21078263
Tags

access

,

violation

,

what

Topic

Miscellaneous Programming

Participating Experts
4
Points
500
Comments
37

Trusted by hundreds of thousands everyday for fast, accurate and reliable tech support.

  • "The time we save is the biggest benefit of Experts Exchange to Warner Bros. What could take multiple guys 2 hours or more each to find is accessed in around 15 minutes on Experts Exchange." Mike Kapnisakis, Warner Bros.
  • "Our team likes having a resource that is more secure than just using Google and most experts using this service really know their stuff. It's nice to look here first versus using Google." Dayna Sellner, Lockheed Martin
  • "Anytime that I've been stumped with a problem, 9 out of 10 times Experts Exchange has either the accepted solution or an open discussion of the potential solution to the problem." Kenny Red, eBay Inc.

See what Experts Exchange can do for you.

Got a question?

We've got the answer.

Experts Exchange has been collecting answers to technology questions since 1996…3 million and counting! If you have a question, chances are we already have your answer.

Screenshot of Experts Exchange Knowledgebase

Need individual assistance?

Our experts are ready to help.

If you can't find the exact answer you're looking for, ask our exclusive community of 50,000 experts. You’ll get a personalized answer from a trusted professional.

Screenshot of Experts Exchange Knowledgebase

Want to learn from the best?

Read articles from industry experts.

Thousands of free tech tips, tricks, how-to’s and tutorials are available in our peer reviewed articles section. See for yourself how smart our experts are, no login required.

Screenshot of an Article

Working on a long term project?

Store your work and research.

Save solutions to your questions, answers you’ve discovered through searching plus helpful articles in your personal knowledgebase for easy future access.

Screenshot of Experts Exchange Knowledgebase

Access the answers to your technology questions today.

Subscribe Now

30-day free trial. Register in 60 seconds.

What Makes Experts Exchange Unique?

Members of the expert community talk about why the experience at Experts Exchange is different than what you will find anywhere else.

Trusted by the world's most respected brands.

image of each brand's logo

Faithfully serving IT professionals since 1996.

Experts Exchange Logo

Try it out and discover for yourself.

Subscribe Now

30-day free trial. Register in 60 seconds.

Related Solutions

  1. VC++ namespace and << stream operator
    When using #include <string> and using namespace std I get error C2872: 'ostream' : ambiguous symbol when trying to overload the << operator. I can fix that by using the scope operator and calling ostream like ::ostream. The only problem is then when I try and...
  2. passing a struct to CreateThread in VC++.Net
    I have a small console program in VC++.NET. I am trying to create multiple threads and pass each one multiple variables, instead of just one. To do this I have a struct that I want to pass: struct my_struct { int Num; int ID; }; So here is what I have: D...
  3. VC++ Compilation Error
    I am trying to use a VB dll in my VC++ project. I compiled the idl into a .h and .c, but when I compile, the MIDL generated files generate the following warnings: c:\program files\microsoft visual studio\myprojects\dtmf tester\dtmf_tone_detector.h(33) : error C2146: syntax...
  4. MS VC++ 6.0
    Hi Experts, In microsoft visual C++ 6.0, which header file is comparable with the <string> in the unix C++. We have the following error messages in MS VC++ 6.0 (#include <string.h>), while it works fine under g++. Which header file should we include ? Thank...

Free Tech Articles

  1. WARNING: 5 Reasons why you should NEVER fix a computer for free.
    It is in our nature to love the puzzle. We are obsessed. The lot of us. We love puzzles. We love the challenge. We thrive on finding the answer. We hate disarray. It bothers us deep in our soul. W...
  2. SCCM OSD Basic troubleshooting
    SCCM 2007 OSD is a fantastic way to deploy operating systems, however, like most things SCCM issues can sometimes be difficult to resolve due to the sheer volume of logs to sift through and the dispe...
  3. Migrate Small Business Server 2003 to Exchange 2010 and Windows 2008 R2
    This guide is intended to provide step by step instructions on how to migrate from Small Business Server 2003 to Windows 2008 R2 with Exchange 2010. For this migration to work you will need the fo...
  4. Create a Win7 Gadget
    This article shows you how to create a simple "Gadget" -- a sort of mini-application supported by Windows 7 and Vista. Gadgets can be dropped anywhere on the desktop to provide instant information, ...
  5. Outlook continually prompting for username and password
    There have been a lot of questions recently regarding Outlook prompting for a username and password whilst using Exchange 2007. There are a few reasons why this would happen and I will try to cover t...
  6. Backup Exchange 2010 Information Store using Windows Backup
    There seems to be quite a lot of confusion around the ability to backup Exchange 2010 using the built in Windows Backup feature. This stems from the omission of this feature prior to Exchange 2007 s...

Cloud Class Webinars

  1. Avoiding Bugs in Microsoft Access
    Alison Balter takes and in-depth look at avoiding bugs in Access. In this webinar you will learn about using the immediate window to debug your applications, invoking the debugger, using breakpoints to troubleshoot, stepping through code, setting the next statement to execute, ...
  2. Top 10 Best New Features in Visio 2010
    Scott Helmers gives live demonstrations of the top 10 new features in Visio 2010. This webinar will teach you how to create compelling diagrams by adding shapes to the page with a single click, linking the shapes in a diagram to data in Excel (or SQL Server, or SharePoint), ...
  3. IT Consultant Business Secrets Revealed
    Michael Munger, Experts Exchange tech pro and IT consultant, pulls back the curtain on his very successful businesses and answers question on every IT consultant and business owner should know about. He shares secrets on what he did to solve the 5 most common problems in IT, ...
  4. Disaster Recovery and Business Continuity
    Quest CTO, Mike Billon, gives an overview of the steps involved in building a dunamic disaster recovery plan. Through case studies and an examination of software/hardware tooles for monitoring and testing, you'll gain a better understandin of where you are, where you want ...
  5. Organize Your Visio Diagrams with Containers and Lists
    Scott Helmers uses cross functional flowcharts, wireframe diagrams, data graphic legends and seating charts to teach you: how to ustilize all three new structured diagram components in Visio 2010, the best practices for organizeing shapes in previous version of Visio, how to organize ...
  6. How to Us Objects, Properties, Events and Methods in Microsoft Access
    Alison Dalter gives an in-depbth look at objects, properties, events and methods in Microsoft Access. In this webinar you will learn about using the object browser, referring to objects, working with properties and methods, working with object variables, understanding the ...

Join the Community

Give a Little. Get a Lot.

Join the community of experts here and help other tech pros by answering question in your area of expertise. You can earn FREE access to all Experts Exchange's premium features and resources.

Join the Community

Answers

 

by: rpzPosted on 2004-08-01 at 03:22:17ID: 11687294

You're typecasting a 4 byte variable into a 18 kb struct and returning the last member? That would put you about 18247 bytes beyond what you allocated memory for. I guess you hit a valid pointer by accident when commenting out parts of the struct. What is the purpose of this code exactly?

 

by: andrey_2007Posted on 2004-08-01 at 09:17:33ID: 11688461

I am affraid that it is incorrect. The code above has worked in production for ~ 10 years for a smaller structure.
The purpose of the macro MY_TYPE is to translate the type of a member of the structure into the argument of the function SetType(...). In real life there are a bunch of overloading functions SetType(...) with different types of argument, and the union  MY_UNION represents all possible types. I believe that the difference for smaller and bigger structure is more understanble when you look at the Assembly code but I still cannot completely explain it.

Thanks.

 

by: grg99Posted on 2004-08-01 at 11:25:57ID: 11689051

It looks like you've inherited some "working", but horribly-designed code.

Any time one does wild-casting into a structure, there's lots of possibilities for errors.  Especially in a language like C, with no intrinsic array-bounds checking.


*Usually* when a program "works" but breaks when you change the size of something that should be completely unrelated, it tends to be that the program originally "worked" by pure dumb luck-- i.e. the struct member selections or array indexes just happened to point to valid memory by pure arithmetic chance.   Changing the size of something else changed the arrangement of things in memory just enough to cause the bad code to wipe out something.

 

by: andrey_2007Posted on 2004-08-01 at 12:42:50ID: 11689274

Sorry. My understamding is that you did not not look at the assembly code. Sorry again but I don't need a "general" explanation.

 

by: andrey_2007Posted on 2004-08-01 at 12:49:40ID: 11689285

grg99,

By the way, what kind of luck we are talking about , if you can copy and paste this code,shorten the number of strings in the structure BIG_STRUCT to 65  (instead of 71), this code will work perfectly  for you every time.

 

by: grg99Posted on 2004-08-01 at 13:11:42ID: 11689340

>grg99,By the way, what kind of luck we are talking about , if you can copy and paste this code,shorten the number of strings in the structure BIG_STRUCT to 65  (instead of 71), this code will work perfectly  for you every time.


"Works perfectly" in most environments usually means "hasnt crashed or made any obvious errors".

It's more than likely that some of those addressing macros/functions/casts are going awry, and not indexing to the addresses you expect.  For example, if you accidentally use an index on a pointer, instead of its base type, it may be indexing by 4 bytes, instead of your expected 1, 2, or some other size.  This will end up addressing some unexpected spot in your BIG_STRUCT, which is soo big, that the wildly incorrect  address may be still inside the structure and with a little more luck unused at that time.  Soo the program may "work", but it's using unexpected memory locations.  Any minor change in the size of the structure, or the indexing, or program data may end this honeymoon.    Been there, done that, have the tee shirt, the CD, and trophy.  

I've seen this many many a time.  Anytime a program is sensitive to minor changes in structure sizes, or adding debug lines, it's very very very very very very very very very very very very very very very very very very very very very very very very very very very very very often a case of wild pointers.



 

by: andrey_2007Posted on 2004-08-01 at 13:31:45ID: 11689388

OK, you did not try this code. Thank you for your time. "Works perfectly" means that the code always produces the right result for you and for me and for all people on the Earth. In this particular case the result should be 5. This code (certainly not this sample, but the idea was the same) was written ~ 10 years ago by a recognized C++ guru. I personally don't like this code (I 've been 12+ years in C++ and 20 years in C). But the question is straight. Could you explain why this particular code ALWAYS works for the structue shorter than 66 string's fields and ALWAYSs causes Access Violation work if we have biger structure?
Please, don't respond if you don't know this particular answer.

Thanks.

 

by: rpzPosted on 2004-08-01 at 14:46:27ID: 11689610

After reading this conversation, I decided to try to run your code. In my case (VC++ 7.1), the AV occured when having 59 or more strings. Why then? I checked with the debugger, and here is what I found after having exactly 59 strings.

The variable displayed below is SOME_SPACE::uni dereferenced as a BIG_STRUCT. As you can see, it happens to have valid pointers to all but the last member, but the memory pointed to is absolute rubbish.

-      (BIG_STRUCT*)ptr      0x00428500 uni      BIG_STRUCT *
      count1      0      int
+      Buffer1      0x00428504 ""      char [257]
... .and it goes on like this...
+      Buffer43      0x0042af2e ""      char [257]
+      Buffer44      0x0042b02f ""      char [257]
+      Buffer45      0x0042b130 ""      char [257]
+      Buffer46      0x0042b231 "çwü§çw1 çw~ÞçwTÉæwÈàçwaçw›¢çwß§çwéhçwæwžæwý·çwbsçw.ðçw èwYSçw"      char [257]
+      Buffer47      0x0042b332 "ress"      char [257]
+      Buffer48      0x0042b433 "tringsW"      char [257]
+      Buffer49      0x0042b534 "oseHandle"      char [257]
+      Buffer50      0x0042b635 "StringTypeA"      char [257]
+      Buffer51      0x0042b736 ".dll"      char [257]
+      Buffer52      0x0042b837 ""      char [257]
+      Buffer53      0x0042b938 ""      char [257]
+      Buffer54      0x0042ba39 ""      char [257]
+      Buffer55      0x0042bb3a ""      char [257]
+      Buffer56      0x0042bc3b ""      char [257]
+      Buffer57      0x0042bd3c ""      char [257]
+      Buffer58      0x0042be3d ""      char [257]
+      Buffer59      0x0042bf3e ""      char [257]
      mode      CXX0030: Error: expression cannot be evaluated      int


So, what happens at 58 strings? It ends like this
+      Buffer55      0x0042bb3a ""      char [257]
+      Buffer56      0x0042bc3b ""      char [257]
+      Buffer57      0x0042bd3c ""      char [257]
+      Buffer58      0x0042be3d ""      char [257]
      mode      0      int

Voilà, the "mode" member is now valid (although the memory is certainly not what you alllocated for). If you want more evidence of this, let's have a look at the hex dump from a part within the structure:
...
0x0042B56E  48 65 61 70 56 61 6c 69 64 61 74 65 00 00 fc 00 47 65 74 43 50 49 6e 66 6f 00 f5 00 47 65 74 41 43 50 00 00 8b 01 47 65 74  HeapValidate..ü.GetCPInfo.õ.GetACP..&#139;.Get
0x0042B597  4f 45 4d 43 50 00 00 73 03 56 69 72 74 75 61 6c 41 6c 6c 6f 63 00 00 10 02 48 65 61 70 52 65 41 6c 6c 6f 63 00 7b 03 56 69  OEMCP..s.VirtualAlloc....HeapReAlloc.{.Vi
0x0042B5C0  72 74 75 61 6c 51 75 65 72 79 00 00 1f 02 49 6e 74 65 72 6c 6f 63 6b 65 64 45 78 63 68 61 6e 67 65 00 e1 02 53 65 74 43 6f  rtualQuery....InterlockedExchange.á.SetCo
0x0042B5E9  6e 73 6f 6c 65 43 74 72 6c 48 61 6e 64 6c 65 72 00 6b 02 4d 75 6c 74 69 42 79 74 65 54 6f 57 69 64 65 43 68 61 72 00 3a 02  nsoleCtrlHandler.k.MultiByteToWideChar.:.
0x0042B612  4c 43 4d 61 70 53 74 72 69 6e 67 41 00 00 3b 02 4c 43 4d 61 70 53 74 72 69 6e 67 57 00 00 b2 01 47 65 74 53 74 72 69 6e 67  LCMapStringA..;.LCMapStringW..².GetString
0x0042B63B  54 79 70 65 41 00 00 b5 01 47 65 74 53 74 72 69 6e 67 54 79 70 65 57 00 00 97 02 51 75 65 72 79 50 65 72 66 6f 72 6d 61 6e  TypeA..µ.GetStringTypeW..&#151;.QueryPerforman
0x0042B664  63 65 43 6f 75 6e 74 65 72 00 d5 01 47 65 74 54 69 63 6b 43 6f 75 6e 74 00 00 3e 01 47 65 74 43 75 72 72 65 6e 74 54 68 72  ceCounter.Õ.GetTickCount..>.GetCurrentThr
0x0042B68D  65 61 64 49 64 00 00 3b 01 47 65 74 43 75 72 72 65 6e 74 50 72 6f 63 65 73 73 49 64 00 c0 01 47 65 74 53 79 73 74 65 6d 54  eadId..;.GetCurrentProcessId.À.GetSystemT
0x0042B6B6  69 6d 65 41 73 46 69 6c 65 54 69 6d 65 00 79 03 56 69 72 74 75 61 6c 50 72 6f 74 65 63 74 00 00 bb 01 47 65 74 53 79 73 74  imeAsFileTime.y.VirtualProtect..».GetSyst
....

Looks like a DLL import table or something.

I still believe you were just lucky those ten years.

 

by: rpzPosted on 2004-08-01 at 14:52:45ID: 11689628

Sorry, I forgot to show the disassembly for the call in question. This is the version that fails:

     int res = MY_TYPE(BIG_STRUCT, mode);
00411A85  mov         eax,dword ptr ds:[0042C040h]
00411A8A  push        eax  
00411A8B  call        SetType (4111B3h)

And this version does not:
     int res = MY_TYPE(BIG_STRUCT, mode);
00411A85  mov         eax,dword ptr ds:[0042BF40h]
00411A8A  push        eax  
00411A8B  call        SetType (4111B3h)

And the memory looks as this in the area of interest:

0x0042BFAE  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  .........................................
0x0042BFD7  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  .........................................
0x0042C000  ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ??  .........................................
0x0042C029  ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ??  .........................................

As you can see, this string (in my case #59) just passes the border to the unallocated memory.

 

by: andrey_2007Posted on 2004-08-01 at 15:31:17ID: 11689740


It is exactly what I have for VC++ 6.0. The difference is the number of strings: I am OK with 66 strings. Moreover, when I look at dissassembly code I can see that compiler's table __cfltcvt_tab is used for small structure (I tested 3 member structure ) and __except_list table for bigger structure when the code still works (66 string fields for my VC++ 6.0). At this point of time I still believe that the problem is still related to some internal compiler's ot LINKEDIT limitations. What is lucky about this? The original C++ code is not very good, but it is still legitimate. What is wrong with it? Why does it work on all machines for structures with the size less than 16000 bytes or so? I don't think that the luckiness is a proper explanation. I need to decide what to do with the code that perfectly works for about 100 production systems and does not work for one new developer that happened to increase the length of the structure tremendously.

Thanks.

 

by: rpzPosted on 2004-08-01 at 16:07:35ID: 11689857

> What is lucky about this? The original C++ code is not very good, but it is still legitimate. What is wrong with it?
If you look at the disassembly in my previous comment, you see that the code tries to access an invalid memory location, in this case 0x0042BF40. The reason the code works with the fewer number of strings on your production machines is simply that the memory pointed to by the last member is then unused by whatever allocated it. "Luck" doesn't necessarily mean the errors fluctuate. As long as your compiled code remains the same, a faulty program could very well work "flawlessly", but even a very slight change to it could cause it to break down completely, as has already been pointed out in a previous comment. It could be dangerous to say that this code is "legitimate". It is, at best, a hack that uses the internal workings of the compiler to hide problems with invalid pointers.

I am still quite unclear with what the code should really do, but one way to get your sample program not to crash is allocating more memory to the MY_UNION union, like this:
typedef union
{
     int          i;
     char          c;
     short          t;
     char bigdata[8+257*71];
} MY_UNION;

 

by: andrey_2007Posted on 2004-08-01 at 16:58:34ID: 11690073

Unfortunetely, you did not understand what the code does. I really don't have time to explain this to you in detail. But the point is in the union, only those types should be presented that we are going to point to, in the structure. For my example you can point to int, char or short in the structure. You cannot point to the string. I hope now it will be clearer for you. So your suggestion about union is obvious but completely useless (Sorry.)  

 

by: adgPosted on 2004-08-01 at 17:12:20ID: 11690116

 static MY_UNION uni;

This allocates four bytes of space. It is a static structure, so it will be located in the uninitialized data area.

And the macro

  #define MY_TYPE(s,m)   SetType(((s *)&SOME_SPACE::uni)->m)

Takes the address of the four bytes mentioned above, and *pretends* that the four bytes are instead the huge structure of arrays. it then calculates offset of the "mode" member, which is WAY past the end of "uni".

The code is completely and utterly wrong. If it worked, it was pure luck, as the other experts have tried to tell you.

 

by: adgPosted on 2004-08-01 at 17:22:22ID: 11690143

If you want an explanation for why you get the access violation, it is simple:

uni is 4 bytes. You are then calculating this pointer WAY past the end of uni. If you comment out a few of those arrays, your pointer ends up pointing to some weird area of the executable, like the import section or debug info. If you put those arrays back in, your pointer is so far past the uni structure, it is *past the end of the executable*. You are trying to access the mode member (which is not there), and your pointer is way out in space accessing memory that was never allocated or reserved, out past the end of the program.

 

by: andrey_2007Posted on 2004-08-01 at 17:37:03ID: 11690172

adg,

It is not so obvious. When the program works (also for huge structures, like 16,000 bytes ), the value of int mode  goes as the argument of SetType(...). You can check it through a debugger. So basically not the whole structure's chunk of memory , but just integer "mode" goes to the 4 bytes that was reserved by static MY_UNION uni;

 

by: adgPosted on 2004-08-01 at 17:40:36ID: 11690179

The executable is constructed from several sections:

.text: assembly code
.data: initialized data
.bss: uninitialized data (filled with zeros before program start)
.idata: import data
.rsrc: resources such as dialogs and icons
etc....

each of these sections is rounded up to the next higher multiple of 4KB. Now, your (4 byte) uni structure gets placed in the .bss section. If that is the only data in the program, .bss will probably end up being 4KB.

Now, if I access, say, 18248 bytes past the END of uni, my pointer will end up pointing to some garbage, probably so far ahead that it is past the end of the memory image. rpz demonstrated that it points well into the "idata" section, way past the end of "bss".

Reassuring us how good the original programmer was will NOT somehow magically make this code valid. It is completely wrong. It might be right in context (in the actual app), but the code listed here is completely invalid. Perhaps he obfuscated the code to buy some job security? Forgive me for being blunt, but myself and all the other people who posted here are trying to tell you that the code is not valid! :)

Here is an example of what you are doing:

----

static char aSmallArray[500];

int main()
{
    printf("This is going to crash!\n", aSmallArray[80000]);

    return 0;
}

----

See how it tries to read data WAY past the end of aSmallArray?

 

by: adgPosted on 2004-08-01 at 17:48:36ID: 11690198

We don't need to convince you, your CPU attempts to lookup the address of the data (way off the end of the executable). The CPU finds that the paging tables say the memory (way off in space) is not allocated to any process. The CPU raises a paging exception, windows handles it, your program dies, end-of-story.

 

by: andrey_2007Posted on 2004-08-01 at 18:01:27ID: 11690241

adg,

You did not respond my previous comment. Please talk from yourself, not from the whole community. Please try not to be rude. Don't take it personally.

 

by: adgPosted on 2004-08-01 at 18:02:59ID: 11690245

If you can show me where it is ALLOCATING 16000+ bytes, then your code might be valid. You code allocates a 4-byte union, then accesses memory that is over 18000 bytes PAST the end of the union.

 

by: adgPosted on 2004-08-01 at 18:04:30ID: 11690247

You were not entirely polite to rpz. (saying his suggestion was "useless")

 

by: andrey_2007Posted on 2004-08-01 at 18:07:09ID: 11690254

adg,

Do you agree that only integer "mode" goes into static uni or not?

 

by: adgPosted on 2004-08-01 at 22:27:12ID: 11691012

When you use a struct, each member has a name, size, and offset.

When I do this:

typedef struct {
    char aBuf1[8];
    int nSomeNum;
    char aBuf2[8];
} Something;

Then the compiler interprets that to mean:

At offset 0 there is an array of 8 chars named aBuf1.
At offset 8 there is an int named nSomeNum.
At offset 12 there is an array of 8 chars names aBuf2.

Each member of a struct has a certain "offset".

In BIG_STRUCT, the offset of "mode" is 18252.

I can do this:
  int x = ((Something*)p)->nSomeNum;

In this case, the compiler will take the value of p (and PRETEND that it is an address of a Something structure) and it will add the offset of nSomeNum, 8.

So if p was 0x00402000, it will take that and add the offset of nSomeNum, which is 8. The actual addres that is read is 0x00402008.

Now back to your code...

It takes the address of "uni".

(BIG_STRUCT*)&uni

This tells the compiler to take the address of uni, and PRETEND that it is the address of a BIG_STRUCT.

The second macro parameter says to access the "mode" member of the structure. The MY_TYPE macro expands to this:

((BIG_STRUCT*)&uni)->mode

So it says, "Take the address of uni, pretend that it is a BIG_STRUCT, add 18252 to that, and read the int stored there."

But at uni, only 4 bytes are allocated. If I access 18252 bytes from the beginning of uni, I am accessing something out in space, extremely far past the end of uni.

 

by: adgPosted on 2004-08-01 at 22:38:03ID: 11691034

The real error is this line:

namespace SOME_SPACE { static MY_UNION uni; };

If you were to replace it with:

namespace SOME_SPACE { static BIG_STRUCT uni; };

and move it below the "typedef struct" it will work. It will allocate 18256 bytes for uni, and then the computer can add 18252 to the base address of uni and actually read uni!

 

by: adgPosted on 2004-08-01 at 22:39:23ID: 11691039

....below the entire typeef struct, after the ;

 

by: adgPosted on 2004-08-01 at 22:39:50ID: 11691040

I mean, after "} BIG_STRUCT;"

 

by: adgPosted on 2004-08-01 at 22:56:14ID: 11691095

Why not use an array of arrays:

typedef struct
{
    int                    count1;
    char                 Buffers[71][257];
    int                    mode;
} BIG_STRUCT;

 

by: grg99Posted on 2004-08-02 at 04:34:33ID: 11692584

To the other experts:

A long time ago a VERY SMART fellow, an excellent programmer,  asked me for advice: his car stereo was blowing fuses at peculiar times.   I thought over the problem and gave him three plausible explanations of what could be wrong; each explanation was a bit subtle, but they were each logically consistent, fit all the known facts, and matched my experience with other similar situations.

All he could say is "BUT HOW CAN THAT BE?".   He was very smart, but had some mental block, he thought if every connection LOOKED okay, and he thought every wire went to the right place, and no speaker had a little thought balloon saying "I MAY LOOK OKAY FROM THE OUTSIDE, BUT I HAVE A SHORTED CROSSOVER CAPACITOR", he thought everything HAD to be okay.

There's not much you can do for such folk, they're stuck  in a mental logjam.



 

by: jungesPosted on 2004-08-03 at 06:45:16ID: 11704324

hi andrey,

This code serves to read data from memory, begining at the address of SOME_SPACE::uni. I testes it on my enviroment(XP SP1, VC7.1), it works without access violation, my be because i have 512mb of memory. Probably it cause an exception when (BIGSTRUCT)SOME_SPACE::uni contains some readonly memory blocks. If it runs since 10 years on a system, then probably this OS os very old and have more tolerance that newers OS's.

regards junges

 

by: adgPosted on 2004-08-04 at 04:43:52ID: 11714253

andrey_2007:
>> Do you agree that only integer "mode" goes into static uni or not?

uni is a union, and the largest member of that union is 4 bytes. Therefore uni is four bytes.

If you want proof, step into the program with the MSVC debugger, press Shift+F9, and type sizeof(uni) and press enter. It says 4, meaning uni is 4 bytes.

To get the address of uni in the debugger, you press Shift+F9 and type

&uni

I get 0x00427C50. That is the address where uni is stored.

Now, if you step into the assembly, you see that it reads address 0x0042C39C.

So if the beginning of uni is 0x00427C50 and uni is four bytes, then uni ends at 0x00427c54.

Your program is reading address 0x0042C39C, which is 18248 bytes past the end of uni, exactly what I calculated in previous postings.

The MY_TYPE macro accesses memory that is 18248 bytes past the end of uni. It is accessing something, but it is not accessing uni. On your compiler and my compiler, that just HAPPENS to be past the end of the executable. Apparently junges libraries are larger, so it doesn't crash there, but it is still accessing some crazy memory location, not uni.

So, to answer that question: No, there is no space in uni that is 18248 bytes from the beginning of uni, because uni is 4 bytes.

uni doesn't even have a "mode" member.

There is nowhere in that program listing where it stores any information. It *reads* a memory location, but that crashes it before it even touches "res". The memory address that the MY_TYPE macro calculates is so high that it is outside the entire program image, in unallocated space, causing a crash.

So integer 'mode' never goes into static uni.

 

by: grg99Posted on 2004-08-04 at 05:21:35ID: 11714529

Another possibility:

It's quite possible the program has been running "perfectly" for 10 years due to address-wraparound.

If the program was compiled in any of the old 16-bit real modes for the PC, then it's quite possible for address calculations to:

(1)  End up past the end of the "legally allocated" segment, but still within physical, perhaps unallocated for any other purpose,  memory.

(2) Or "wrap around" over the top of the physical segment end, and end up somewhere very different, but still in the 64K data segment.  With a little luck, some unused address.

-------------

This often shows up as a crash when you move any data around, or when you port the program to some addressing mode that has more segment limit checks.

--------------

Don't feel too bad if this is the case:  It's happened to others, including the famous case that's cost $many many Millions of $:

One bit of very old program loader code from Microsoft only worked if segments wrapped within the 16-bit addressing space.   The problem wasnt detected until the 286 chip was in development.  By then there were millions of copies of programs that used this bad loader, so something drastic had to be done to all future "PC compatibles":  The A20 kludge was added.  Every PC since then has had extra hardware to enable/disable address wrapping.  This took extra explicit hardware on the early PC's, costing maybe $2 each, now it's subsumed into the CPU support chips.  

So don't feel TOO bad if you have old code that works only due to the vaguaries of 16-bit addressing, you're far from alone in this.

 

by: adgPosted on 2004-08-04 at 18:22:41ID: 11722540

The A20 kludge is a wraparound at the 1MEG line, not a segment wraparound. Even if it were running under a segmented architecture, it would still be accessing some random memory address, it would just be some random address within a given 64K area.

 

by: adgPosted on 2004-08-04 at 18:45:04ID: 11722622

Since the program accesses memory that is way past the structure it is trying to read, if you add data after "uni", add at least 18252 bytes, then your accesses of "uni" will actually be reading some area of the variables after uni, and it won't crash. If you *write* to that pointer calculated by MY_TYPE, you will be corrupting the content of the variables declared after uni. If by chance your corruption of memory doesn't happen to disturb anything important, it might actually run. This is a type of bug that happens sometimes when working with pointers, where you calculate a completely wrong address and read/write the wrong address, causing extremely weird bugs to occur elsewhere in the program because you are corrupting unrelated variables. But you would never deliberately do that. You should allocate memory properly and calculate pointers to data areas you own.

 

by: grg99Posted on 2004-08-05 at 12:14:25ID: 11729710

>The A20 kludge is a wraparound at the 1MEG line, not a segment wraparound.

Thats right, it was expected that using a segment of > $F000 with high offsets would wrap around to low memory.
Same basic idea, only with the segment part, not the offset part.  What a weird world.

Way back in ancient days, whenever we ran BASIC on a PDP-8, afterwards one of the disks would be unreadable until a reboot.   Turned out BASIC was trying to write a flag of #0001 to the right offset, but the wrong memory bank (sort of like a segment).  That bashed address just happened to be smack dab in an important system disk info table.   Nobody  noticed the problem until they got enough disk devices to reach table entry #7, which was the one that got bashed.  The flag it was trying to set was a rather unimportant one, having to do with system swapping, so nobody noticed the flag wasnt getting set.   This stuff goes waaaaaay back, folks.





 

by: andrey_2007Posted on 2004-08-27 at 13:52:49ID: 11917550

I have not abondoned this question. Do no delete or close.

 

by: rpzPosted on 2004-08-29 at 05:33:29ID: 11925351

I think the original question has been answered many times over (Q: Why does the program crash? A: You write outside of allocated memory). If you have additional questions, you should post it as a new question.

20120131-EE-VQP-002

3 Ways to Join

30-Day Free Trial

The Experts

98% positive feedback on 31,087 answers since March 2000. angeliii is a Microsoft Most Valuable Professional for his work with MS SQL Server & Develoment.

He has also proven his knowledge of Visual Basic Programming, PHP Scripting and Oracle Databases.

The Experts

97% positive feedback on 10,752 answers since July 2000. lrmoore has more than 18 years experience in the networking industry.

The six-time Mircosoft MVPs specialties include firewalls, virtual private networking, and network management.

Testimonials

"...and excellent source for support... Kind of like having your very own IT dept." Electriciansnet

Testimonials

"I was apprehensive at signing up at first. However... it has already made my life as an IT administrator much easier." JaCrews

Testimonials

"WOW! You guys have great, active, and knowledgeable people on here." moore50

Business Clients

Business Clients

In the Press

"If you’ve got a question... Experts Exchange can supply an answer.”

In the Press

"...an invaluable aid for both IT professionals and those who require tech support."

In the Press

"where IT professionals provide quick answers on just about any topic"

Business Account Plans

Loading Advertisement...