ADC Membership Technical Business Join ADC
Search Advanced Search
NOTE: This Technical Note has been retired. Please see the Technical Notes page for current documentation.

Technical Note TN1025
Driver Loader Library Call GetDriverInformation: A Bug & Workaround

CONTENTS

This Technote describes a workaround to a bug in the first version of the Driver Loader Library in System 7.5.2 and System Update 7.5.3. (The bug should be fixed in later versions of the Mac OS.) As of this writing, the Driver Loader Library is only available on Power Macintoshes that support PCI cards (for example: Power Mac 7200, 7500, 8500 and 9500). There is a bug in the routine GetDriverInformation that can possibly cause an overwriting past the end of the name string that is passed in.

This Technote is directed primarily at writers or family experts and especially applications that get information about drivers.

 [Feb 1 1996]






Defining the Problem

In the Driver Loader Library, there is a bug in the routine GetDriverInformation that can possibly cause an overwriting past the end of the name string that is passed in.

This bug surfaces only when calling GetDriverInformation() for a driver that has had its Device Control Entry fields zeroed when it was closed (the Chooser driver has been observed to exhibit this behavior). The bug occurs because GetDriverInformation() does not check for zeroed fields before using the dCtlDriver field to reference the driver's name; instead, it copies a garbage string from low memory into the name string passed as a parameter to GetDriverInformation().

If the first byte of this garbage string is larger than the number bytes of storage allocated by the caller for the name string, then the caller's data located just past the end of name's storage will be overwritten with garbage.

You can see the zeroing out of fields for the Chooser's driver by following these steps using any version of MacsBug:

1. Open the Chooser.

2. Drop into MacsBug and type:

    drvr      <return>

3. Look down the list of drivers in the Driver column of the drvr display and see the Chooser (on my machine it's at dNum 0xF). To see what the Chooser's DCE fields look like before the zeroing type:

    dm    xxxxx    dctlentry    <return>

(where xxxxx is the hexidecimal number in the Chooser's row in the "DCE at" column in the drvr display)

4. Exit Macsbug by hitting Command-G.

5. Close the Chooser window.

6. Drop into MacsBug and type:

    drvr   <return>

You'll see that name Chooser is replace by blanks in the row that it was in.

7. To see the zeroing of DCE fields type:

    dm    xxxxx    dctlentry    <return>

(again, where xxxxx is the hexidecimal number in the Chooser's row in the "DCE at" column in the drvr display).

You'll see that all fields except the RefNum field have been zeroed.

It's doubtful that any expert code will encounter this problem if the expert code executes pre-Finder; applications that execute after the Finder boots are the most likely victims. If your code calls GetDriverInformation() after a user has a chance to close one of these "zeroed-out" drivers (and the DCE fields are thus zeroed), then you will need this workaround. If you call GetDriverInformation only for a driver that you know doesn't have its Device Control Entry fields zeroed upon closing, then you don't need this workaround because the bug will not appear. It is only when you traverse the unit table, calling GetDriverInformation for unknown drivers, that you need to be aware of the workaround.

GetDriverInformation

Here is the declaration for GetDriverInformation as gleaned from the universal headers file, Devices.h:

extern OSErr
GetDriverInformation (DriverRefNum refNum,
            UnitNumber *unitNum,
            DriverFlags *flags,
            DriverOpenCount *count,
            StringPtr name,    // ** this is the field we are
                            concerned with//
            RegEntryID *device,
            CFragHFSLocator *driverLoadLocation,
            CFragConnectionID *fragmentConnID,
            DriverEntryPointPtr *fragmentMain,
            DriverDescription *driverDesc);

It is the StringPtr name parameter that we are concerned with. If you allocate, for example, a Str31 to use to pass in as the StringPtr, then (if the erroneous byte GetDriverInformation thinks is the length byte of the garbage string is greater than 0x1f, or 31 decimal) GetDriverInformation will unwittingly copy all the garbage bytes to your code without regard to the actual location of the end of the name string.

Back to top

Solving the Problem

The workaround is simple: allocate a String255 for the name parameter passed into GetDriverInformation() rather than some shorter-length string. This means any garbage copied to the string will be contained in that string rather than any other data. If you're familiar with GetDriverInformation, that's all you need to know: use a Str255 for the name parameter rather than a shorter string and you're protected. If you're not familiar with GetDriverInformation and would like to see some code to traverse the unit table, sample code is provided here for your information. You also have to take precautions about using the garbage string data as well (if you were going to display the driver name in an application, you would probably want to check for non-printing characters if displaying them would cause problems in your code. You might want to make sure the garbage length of the name string isn't too long for your code to handle).

Back to top

Sample Code Using GetDriverInformation To Iterate Over the Driver Unit Table

To drive the point home about using a Str255, and also to alert you to another mandatory initializing of the FSSpec field of the driverLoadLocation struct, (another input of GetDriverInformation), here is some barebones sample code. Note that traversing the unit table using GetDriverInformation() is not the most efficient way to discover which units are empty and which are full. Use the Driver Loader Library routine, LookupDrivers() for that.

void TraverseDrivers()
{

    OSErr                err = noErr;
    DriverRefNum            refNum;
    UnitNumber            unitNum;
    DriverFlags            flags;
    DriverOpenCount            count;
    RegEntryID            device;
    CFragHFSLocator            driverLoadLocation;
    DriverDescription        driverDesc;
    // Str63            theName; // BAD, not long enough
    Str255                theName;  // GOOD: THIS IS THE WORKAROUND!
    FSSpec                loadLocSpec;
    short i;

//  this is another caveat about using GetDriverInformation();  you must
//  initialize the FSSpec ptr field of the driverLoadLocation struct to
//  point to an allocated FSSpec because GetDriverInformation assumes you
//  have.  This is done is the next line below.
      driverLoadLocation.u.onDisk.fileSpec = &loadLocSpec;

    for( i = 0;  i <= HighestUnitNumber(); ++i ){
        refNum = ~i;  // convert the unit number to a driver refNum.
        err =     GetDriverInformation(    refNum,
                        &unitNum,
                        &flags,
                        &count,
                        theName,
                        &device,
                        &driverLoadLocation,
                        &fragmentConnID,
                        &fragmentMain,
                        &driverDesc);
        if( err != noErr ){ // there's a driver for this refNum

            // Do whatever it was you wanted to do with the information
            //  BEWARE: If the driver is a non-native driver, that is a
            //  68k driver of pre-PCI-supporting Macintosh, the device,
            //  driverLoadLocation, fragmentConnID, fragmentMain, and
            //  driverDesc inputs above will be set to nil after the call
            //  because these fields don't apply to 68k drivers.
        }
    } // for
}  //  end  TraverseDrivers()

Back to top

Reference for GetDriverInformation

GetDriverInformation

GetDriverInformation returns a number of pieces of information about an installed driver.

OSErr GetDriverInformation
    (DriverRefNum        refNum,
    UnitNumber        *unitNum,
    DriverFlags        *flags,
    DriverOpenCount        *count,
    StringPtr        name,
    RegEntryID        *device,
    CFragHFSLocator        *driverLoadLocation,
    CFragConnectionID    *fragmentConnID,
    DriverEntryPointPtr    *fragmentMain,
    DriverDescription    *driverDesc);
refNum                refNum of driver to examine
unit                resulting unit number
flags                resulting DCE flag bits
count                number of times driver has been opened
name                resulting driver name
device                resulting Name Registry device specification
driverLocation        resulting CFM fragment locator (from which the driver
                     was loaded)
fragmentConnID        resulting CFM connection ID
fragmentMain        resulting pointer to DoDriverIO
driverDesc            resulting pointer to DriverDescription
DESCRIPTION

GetDriverInformation is used by driver experts in PCI-bus-supporting machines, software that makes decisions about which driver to load for a particular device -- or by any software that needs to get information about a driver for a device.

Given the Unit Table reference number of an installed driver, GetDriverInformation returns the driver's unit number in unit, its DCE flags in flags, the number of times it has been opened in count, its name in name, its RegEntryID value in device, its CFM fragment locator in driverLocation, its CFM connection ID in fragmentConnID, its DoDriverIO entry point in fragmentMain, and its Driver Description in driverDesc.


Note:
With 68K drivers, GetDriverInformation returns meaningful information in only the unit, flags, count, and name parameters.



Warning:
You must allocate the FSSpec field of the CFragHFSLocator * driverLocation before passing it in to GetDriverInformation().


RESULT CODES
    noErr          0    No error
    badUnitErr    -21    Bad unit number
    unitEmptyErr    -22    Empty unit number

Back to top

Summary

To protect yourself against having GetDriverInformation copy garbage into the passed StringPtr name parameter when a driver has its Device Control Entry (DCE) fields zeroed upon closing (the Chooser, for example), allocate a large enough string (for example, String255) for the name parameter. This will assure that any garbage copied to the string will be contained in that string.

See Designing PCI Cards and Drivers for Power Macintosh Computers for further documentation on GetDriverInformation or any other Driver Loader Library calls.

Back to top

Downloadables

Acrobat gif

Acrobat version of this Note (64K).

Download



Back to top


Technical Notes by Date | Number | Technology | Title
Developer Documentation | Technical Q&As | Development Kits | Sample Code




Gray line

Contact ADC |  ADC Site Map |  ADC Advanced Search
For information about Apple Products, please visit Apple.com.
Contact Apple | Privacy Notice
Copyright © 2002 Apple Computer, Inc. All rights reserved.
1-800-MY-APPLE