Advocacy

  Myths
  Press

Dojo (HowTo)

  General
  Hack
  Hardware
  Interface
  Software

Reference

  Standards
  People
  Forensics

Markets

  Web

Museum

  CodeNames
  Easter Eggs
  History
  Innovation
  Sightings

News

  Opinion

Other

  Martial Arts
  ITIL
  Thought


Memory Protection
What is it? (The Basics)

By:David K. Every
©Copyright 1999


Most aspects of computing are complex enough that they don't fit well into "sound-bites" -- but that doesn't stop the press from smashing complex ideas into such brief stories, in which all value (and balance) is lost.

Memory management is one of those areas. People now (incorrectly) believe that Protected Memory cures all evils, and makes computers stable. The truth is that it is only ONE variable (though an important one) in a complex equation.

This article should help you understand what the different types of memory protection are, and how (why) they work.

Memory Maps

A computer has RAM (temporary memory) that is used to store programs and your data while working. The OS is always running, as may be one or more applications -- and these must be resident in different areas of RAM. The problem is that bad Applications can not only stomp on themselves -- but also on other Apps, or the system itself.

Memory is just a loooong series of addresses (locations) that have values (code or data) stored in it (usually 4 Gigabytes). Most representations of a "memory map" are two dimensional.

A simplified memory map would show just Applications and the system --

Notice that a lot of memory (most) is "free-mem". Now RAM is used for Apps and the System -- and there is always lots of empty space.

If a Memory map is usually 4 Gigabytes, and you have 32 Megabytes of Physical RAM (and double that used by "Virtual Memory") or 64 Megabytes of total memory -- you are still only using 1.6% of the memory map. If you were to select a location at random, there is a 98.4% chance that you would NOT hit anything. The results are even more dramatic because programs are usually NOT using the RAM they have allocated to them (there are lots of "gaps" inside each Apps space). So at random, there is a very unlikely chance that you will ever stomp on anything of value -- for a single instance (mistake). However, computers are very fast -- so mistakes can come in very quick succession. Furthermore, most errors are NOT random, and don't just go anywhere. They often error to predictable places -- that is very important because predicting where things will error can allow you to catch 90% of the errors by only protecting a few locations -- but more on this later.

So what are the different types of memory protection?

System-Wide Protection --

Imagine that App1 (Application #1) makes a error, and instead of making a change inside itself, it makes a change to App2 (or the System) (1). The results are quite likely to mess up someone elses data, and cause App2 (or the System) to eventually crash, because of that "unauthorized" change. Or another common error is for App2 to overrun the end of itself and walk on App3 -- again resulting in App3 (and likely App2) crashing.


(1) Remember, memory is just one big array of addresses -- so a simple math error, or (most commonly) a failure to clean something up (initialize a location) before working with it, can easily result in a "bad address".

Imagine that every time you mis-dialed a phone number (or mis-wrote an address on a letter) it cause the recipients house to explode! Boom! Oops, there went another one!

Programmers have to deal with hundreds or thousands of addresses in small programs, an error in calculating any one of them is often fatal!


These programmer errors are what memory protection helps protect against. Each App can access ONLY its OWN memory. As soon as an App writes (or reads) outside of its own area, the system immediately crashes (quits) that offending App. This means the user loses whatever data they were working on at that time -- but at least that App is prevented from writing out bad data (and corrupting the file) or from hurting another App or the System itself. The results are that the System itself is more stable, and Apps are safe from each other -- but that Apps themselves often crash more often (quit unexpectedly). If you've seen an App quit for no reason (with some System error), then this is likely a form of memory protection kicking in.

Protecting an App from itself

Some forms of memory protection not only want to protect apps from each other, but they can try to help protect an Application from themselves.

An App has many different areas inside its own memory map that may be storing different things. The App has its code (the instructions to the computer on what to do), and its data (the information, in-memory copy of the file, and other temporary storage).The Data is further broken up into the stack (variables) and the heap (structures the programmer allocates -- usually the memory resident parts of the file).

Stack-Heap Collision: The stack grows towards the heap (and vise versa), but if they meet then that App has run out of memory. If a programmer isn't paying attention, one of them (stack/heap) can stomp on the other. Once an Application has stomped on itself, it is just a matter of time before it crashes. It is far better for the System to detect the stack-heap collision, and bring the program down "gracefully" and quickly (before it has time to corrupt its own data), rather than to allow the program to keep running, and corrupt its data-files or maybe even crash the System.

Read-Only Code: Since your code (the program) is only going to be executed, and your data is supposed to be held somewhere else (in the stack or heap) -- a good system will guarantee that a program can never writes into its own (or other apps) code space. Otherwise a simple math error can allow a program to alter its own code -- which is likely to result in an application crash later on.

NOTE: Code Protection (Read-Only code) can not be done if programmers use a bad programming technique called self-modifying code. (This is where programs change themselves as they are executing).

Protecting the System from itself

The Operating System is just a very complex program that all the other programs use and work with. Because of its importance, we want to do a lot to make the System safe from other Apps and from itself.

The System can be broken into its parts -- and then by protecting those parts from each other (and other Applications), the System can be made more stable. The basic parts of the system are the Core System (Kernel), the Drivers, and Services.

Core: the supervisor (also called the core or Kernel) is the part that will "supervise" and give others memory, and send messages and play traffic-cop (prevent collisions).

Drivers: these are small programs meant to control a piece of Hardware. Video Cards, Printers, Scanners, Joysticks, Microphones, Speakers, etc., all have "drivers." Many come with the System, some have to be added on (with extra pieces of hardware that you buy).

Services: these are larger built-in libraries and functions that allow programmers to do things. They could handle the fonts, display windows, or control the graphics.

NOTE: The Video Driver handles things like sending commands to and from the video card (low-level functions)--- but the graphics services handles higher level things like drawing lines, images, etc.

If all the rest of the System (drivers and services) are forced to go through the Kernel to send messages, or to access memory (other than their own space), then the Kernel is called a MicroKernel. (Micro for small, Kernel for "central part or core"). This MicroKernel Architecture helps protect parts of the System from each other, and helps this code be as small and clean as possible.

If parts of the System (drivers and apps) are not protected from each other, and can send messages to Apps (or each other) directly, or they can access each others memory directly, then this system is considered a monolithic system (all one combined unit).

NOTE: WinNT is not a MicroKernel, Rhapsody and Mac OS 9 may both use the Mach MicroKernel (for the developers release, Rhapsody uses Mach2.x which is not a MicroKernel -- later versions will use the Mach 3.0 version ,which IS a MicroKernel).

Trade-offs: Parts of the System might be sped up (slightly) if they don't go through the traffic-cop (MicroKernel) -- but it is harder to achieve stability. Drivers (3rd party or not) can also be sped up (sans MicroKernel) if they can directly access memory and send messages -- but again, the cost is more risk. Far more of the performance-reliability equation has to do with the quality of the code and drivers (and the testing), rather than just "whether it is a MicroKernel or not." There are many engineering religious wars fought over these design choices. Also note that few Systems are "pure" (one way or another) and often have some compromises.

Remember, your Apps are still only as safe as the System itself and all drivers you put on it. Memory protection can not cure against bad System Software, or bad drivers. So you are not just relying on a Kernel / System or memory protection -- but all other parts of the System, including 3rd party drivers.

Other Memory Techniques

There are other techniques for the System to detect that something has "gone awry" with memory in a program.

Localized Data: Imagine that many Apps have a piece of System code that they all use. That code could store its data in a "global" (system wide, shared) pool. The problem is that the pool has to be big enough to store ALL of the possible data, of ALL of the possible programs that could be run all at one time. Not only that, but if any programs have access to that pool, then one program could still walk on the other programs data. This is why it is a good idea to put all of a programs data in its own localized area.

Address Errors: Some processors (like the 68000 and PowerPC) addresses are paired into larger groups (groups of 2, 4 or 8), if the program tries to jump to an "odd" address, or access an uneven block of data, then the System can detect this "addressing or data error" and stop the program. Since this is not supposed to be done, any program that does this has bad code (and should be stopped before it hurts other apps or its own data).

Guard Pages: Most of the time, when a programmer makes a mistake it is likely to be one of a few types. So we can predict WHERE those errors are likely to go and put up a guard page (a guard that watches for an unauthorized access of that area, and quits the App when it access that area). This protect against the most common programmer errors like:

  • Accessing an undeclared pointer -- a pointer which has a zero in it. (A pointer is just a variable that tells the programmer where to find its data). So when the programmer loads or stores data to an undeclared pointer (which points to location 0 by default) -- he is going to walk over location 0, and stomp on some of the System Memory (known as low-mem because it is in the lowest locations). By always making this low-mem "out of bounds" for programs (by putting up a guard page), the system can detect probably 30-40% of all memory related errors.
  • Another common error, is walking off the end of the space that was allocated. So a programmer expects that he will only need 20 of something -- and it turns out that he accesses 21 of them. That 21st element has to go somewhere -- and usually it just goes stomping on top of something else. The System can wrap the whole array with a guard page and detect the programmer mistake. This is probably another 30% of all memory related errors.

So even without full memory protection, with just the two partial protection techniques, the System can stop most of the memory related errors.

Stability is more than memory protection!

There are still many other things to System stability than just memory protection.

Parameter Verification

Imagine I mess up a command I give to the System (this is usually parameters that I give a System Subroutine) -- the System may not know that I am telling it to do something bad. Since the System itself has access to other Apps memory (and all the hardware), it is possible to really screw things up without ever violating memory protection. There is a technique that can protect against this -- the technique is called parameter verification (also called Sanity Checking)-- it is where you verify that all parameters are valid before executing a routine.

Quality of System Code

There are many millions of lines of instructions in the System -- there are errors in there. Fortunately most System Errors require a complex set of event to find (otherwise they would have already been found). But the fewer errors the better. The company that values quality the most (and tests the most, and has the fewest variables), is the one likely to produce the more stable System. Programs are only as stable as the system as a whole.

There are many other issues like configurability, easy of use, quality of documentation, quality of tools, and more that all contributes to System and Application stability. [Read MythsWhat is Stability for more].

Newer Tools / Languages

Assembly, C, and C++ suck for general programming. They are primitive "unsafe" languages. Java is a safe language. In fact, it is impossible (without a bug in the Java Environment itself) for one Application to crap in another appliactions memory space (there are other modern tools that are also "safe"). So as better tools become available, OS level memory protection becomes far far less important.

Conclusion

If you read this entire article, and understand it, then you have a far better understanding of memory protection than many programmers (and most of the press). You will also realize that memory protection is not a single thing. It is a collection of different techniques to HELP make the System more stable. No one technique is a panacea and can cure all the evils that a programmer (or what a poorly written/tested Application) might do.

So what is protected memory? Who has protected Memory (1)? Theoretically it is either a System that uses any one of these techniques -- or -- it is a System that uses ALL of them! MacOS uses many (most) of these techniques (and adding more all the time) -- but some say that the Mac doesn't have memory protection. Some say that Win95 has memory protection, yet Win95 uses a few of these techniques (some of the time) -- and arguably less than the Mac has.I think we need to learn to measure using the same yardstick! WinNT uses a few more techniques, and Unix/Mach (Rhapsody and MacOS 9 and MacOS X) uses the even more. But it still comes down to how WELL each System uses the techniques it has. So it is an issue of degrees and not absolutes.

(1) Common usage is that if you have the first element of memory protection (System Wide Protection) than you have protected memory. But a System that does System-Wide Protection only, and fails in most of the rest of the areas, is not likely to be that stable. Much of the issue falls onto the quality of the apps and how bad your System NEEDS protection.

Never forget that memory protection helps System stability, but is not all there is to it -- just like seat belts can help in an auto-accident. But there are many other things that help protect a person in a car, or to help prevent an accident in the first place.

You can read Memory Protection: MacOS vs Win95 for how those two OS's compare.


Created: 10/8/97
Updated: 11/09/02


Top of page

Top of Section

Home