Monday, June 21, 2004

Roy Nelson is blogging - and Brian Long too

If you are looking for more hacks, you should be subscribing to Roy Nelson's blog. Roy is a great asset of technical info and hacks - in this case he was helping out another great spelunker and Delphi expert, Brian Long.

Wednesday, June 16, 2004

Hack #6:Checking for a valid object instance

I just answered a question in a newsgroup, by simply copying-and-pasting an old post of mine. Reuse is nice, so I decided to put it in my blog as well. Here it is: "Just for the fun of it, I've made some routines to check if a pointer points to a valid object instance. This relies on some types and routines from Ray Lischner's "Secrets of Delphi 2" (the S_VMT unit). Note that this code is D3 specific. Small changes are needed for D1/D2. [Right :)]

uses 
S_VMT;

function ValidPtr(P: pointer; Size: Cardinal): boolean;
begin
Result := not IsBadReadPtr(P, Size);
end;

function ValidObjType(Obj: TObject; ClassType: TClass): boolean;
begin
Result := Assigned(Obj) and
ValidPtr(Pointer(Obj), SizeOf(TObject)) and
ValidPtr(Pointer(Obj), ClassType.InstanceSize);
end;

type
PClass = ^TClass;

function ValidPShortString(S: PShortString): boolean;
begin
Result := ValidPtr(S, SizeOf(Byte)) and
ValidPtr(S, Ord(S^[0])) ;
end;

function ValidClassParent(ClassParent: PClass): boolean;
begin
if ClassParent = nil then
Result := true
else
if ValidPtr(ClassParent, SizeOf(ClassParent^)) then
Result := (ClassParent^ = nil) or ValidClassType(ClassParent^)
else
Result := false;
end;

function ValidClassType(ClassType: TClass): boolean;
var
Vmt: PVmt;
begin
Vmt := GetVmt(ClassType);
Result := ValidPtr(Vmt, SizeOf(Vmt^)) and
(Vmt^.SelfPtr = ClassType) and
ValidPShortString(Vmt^.ClassName) and
ValidClassParent(PClass(Vmt^.ClassParent)) ;
end;

function ValidObj(Obj: TObject): boolean;
begin
Result := Assigned(Obj) and
ValidPtr(PClass(Obj), SizeOf(TClass)) and
ValidClassType(Obj.ClassType) and
ValidPtr(Pointer(Obj), Obj.InstanceSize);
end;

This is probably not foolproof, but it should work in most instances. It works by checking for valid pointers using the Win32 API IsBadReadPtr, checking that the VMT-pointer for the given object is valid. Using this code is not recommended as an alternative to setting instance pointers to nil after freeing them."


Update; I found another old post with a simpler (and probably safer) way of doing it:

function ValidateObj(Obj: TObject): Pointer;
type
PPVmt = ^PVmt;
PVmt = ^TVmt;
TVmt = record
SelfPtr : TClass;
Other : array[0..17] of pointer;
end;
var
Vmt: PVmt;
begin
Result := Obj;
if Assigned(Result) then
try
Vmt := PVmt(Obj.ClassType);
Dec(Vmt);
if Obj.ClassType <> Vmt.SelfPtr then
Result := nil;
except
Result := nil;
end;
end;

Notice that this version is specific to D6 and D7 (IIRC). Other versions might need to update the hardcoded magic number (17).


Update II [June 22, 2007]:
Note that Pierre's "new" FastMM (and thus the D2006/2007 MM) reuses memory blocks more aggressively than the old MM, so you may be false positives from my function if the instance pointer has been freed and just happens to be reallocated by a different object instance (of potentially a different object type).


As always, use this hack with care and a grain of salt or two.

Tuesday, June 15, 2004

Shameless plug: Buy book, get my autograph!

As part of the renumeration for tech editing Xavier Pacheco's excellent book, Delphi for .NET Developer's Guide, I got three copies of the printed version. I don't really need the extra two, so now they are for up for grabs at eBay: Book 1 Book 2 And, yes, I'll sign the books (if the buyer is interested in that). :-)

Wednesday, June 02, 2004

Hack #5: Access to private fields

As your mama taught you, you should protect your private parts, and leave other peoples private parts alone. The same goes for programming, of course. Encapsulation and information hiding is two of the main pillars of object oriented programming, so we better not be messing with those, right? Right. But once in a blue moon, we just have the urge to behave badly and reach into the private fields of another class, defined in another unit.

When possible, the previously described hack of accessing a private field through a published property's RTTI is preferred to the technique presented in this article. However, sometimes that hack is not very practical or even possible. Using RTTI is relatively slow (although the RTTI access to retrieve field offsets could be cached) and the private field you need access to may not be exposed as a property. In addition, if you need access to all or most of a class's internal private fields, the solution described here may be preferable.

As mentioned earlier, Delphi's concept of private (in contrast with D8/D2006-2007's strict private) still allows other code in the same unit full access, while excluding access to external units. So all classes and routines in the same unit are intimate friends of each other.

Have you noticed how promiscuous some of the VCL classes are with each other? For instance, the abstract base class of the component streaming system, TFiler, defines a number of private fields. The actual worker classes TReader and TWriter (both descending from TFiler) are both defined in the same unit, and blatantly access the private fields defined in TFiler (for instance the all-important FStream field).

If you should wish to write your own application-level streaming system (with the ability to stream and auto-create non-TComponent classes) that still participates in the TPersistent DefineProperties system, you would have to extend TReader and TWriter. It looks like these classes have been designed to be extended, considering the virtual protected methods they introduce. Your own TMyReader and TMyWriter classes would not have access to the TFiler private fields, nor to the private fields defined in TReader and TWriter. This could(*) severely limit what your descendant classes could do.

Ok, enough talk already - on to the meat. To get access to the private fields of TFiler, declare a shadow class that exactly matches the private declaration from Classes.pas:

type   
TFilerHack = class(TObject)
private
FStream: TStream;
// other private fields here
end;

Given a TFiler instance, you can now simply cast to TFilerHack to get access to the fields:

procedure Foo(Filer: TFiler); 
var
Stream: TStream;
begin
Stream := TFilerHack(Filer).FStream;
end;

Notice that I still use the private visibility directive for the field - this still gives access to all code in the same unit. Normally, this kind of cracker classes should be declared in the implementation section of the unit. This hack is of course extremely version sensitive to changes in the cracked class. Compared to other solutions of using magic field offsets it has the benefit of having the compiler computing the offset for you and from being protected against changes in the base class (TObject in this case). Still, if you ever use this hack, make sure you {$IFDEF} or {$IF} protect the code against changes in compiler and RTL version (or 3rd party component set version).


(*) A few years ago (using D5), I actually implemented an application-level streaming system by writing my own TReader and TWriter classes and using hacks similar to the ones described in this article. Since then TFiler, TReader and TWriter have been improved with regards to extensibility - providing protected read-only properties to get to some of the private fields, for instance (kudos to Borland CodeGear on that one). It may well be that a functional application-level streaming system could be built without using this hack in D7, but I wouldn't count on it. I still use TFiler as an illustrative example.

Saturday, May 29, 2004

What is a hack?

Before we move on to even dirtier and more dangerous hacks, lets first define what constitutes a hack. IMO, a programming hack must fulfil the following criteria:

A hack uses a non-sanctioned way of performing a task - it bypasses official and documented APIs. It uses a "clever" and non-intuitive method to perform a task that would otherwise be hard or impossible to do.

Cons:
  • Usually makes your code harder to maintain

  • Fragile code, breaks easily when the code it depends upon changes

  • Hard to port to other platforms

  • Refactoring, improving the design, is often a better solution


  • Pros:
  • No other way to perform a task - the alternative is to rewrite or re-implement OPC (Other People's Code)

  • Potential for improved performance

  • Curiosity, gaining a better understanding of the system

  • Its great fun!


  • The general advice is to avoid hacks in production code. Hacks can be very useful as short-term solutions during research and development, but is best replaced with refactored code and design before going to production. That said, most real-world software contain the odd hack or two.

    Friday, May 28, 2004

    Why blogging - a waste of time?

    There have been various discussions about the blogging phenomena and some worries that too much sensitive company information could bleed out to the public. Other people worry about the time "wasted" in writing and reading blogs. As Captain Jake put it over in delphi.non-tech:

    > Who has the time to write it all?

    Good point, actually. I'm geeky enough to (admit that) I use a laptop on the tram back-and-forth to work. That's about 1 hour per day. For some time now, I've spent that tram-time (and some evenings, I must admit) in writing TDM articles and tech editing Xavier's and Jon's books. As Jon was taking a hike in the Grand Canyon (great pictures! - well worth a look), I had some idle time between chapters.

    I wasn't up to writing a complete magazine article, so I decided to try and join this blogging craze. This means that as new chapters start dropping into my inbox, the rate of my blog articles will most certainly decline. Still, I like the persistence of a blog and the fact that I can write anything I like (within the limits of law). And the conformity of RSS and Atom feeds means that it is easy for readers to know when there is something new to read, without having to poll a web page manually.

    Newsgroups are nice, but the signal-to-noise ratio for interesting information is irritatingly low. It is much more productive to monitor a selected list of relevant and high quality blogs. I was talking to a friend, showing him the hack to gain write access to the Screen.PixelsPerInch property. He just shook his head and said;

    "Hack is your middle name".

    Thus the idea of writing about some of the hacks I've played with over the years materialized. Hopefully, I'll find the time to write about less suspicious programming techniques and more about higher level topics some time in the future... :-).

    Wednesday, May 26, 2004

    Hack #4: Access to protected methods

    As we saw earlier, it is possible to gain write access to a read-only property, or rather to its backing field (am talking about native code Delphi here, Win32 and Kylix, - the situation is quite a bit stricter and cleaner in .NET land). You can promote protected properties to public or published to gain access to them, but there is no corresponding promotion syntax for fields or methods. Often you absolutely need to call a protected method of some class - most often method in a VCL component or a 3rd party utility class. This is usually the sign of a badly design class. The author didn't think that application level code would need access to the method. A mock-up example would be:

    unit Utility;

    interface

    type
    TUtility = class
    protected
    procedure Useful;
    public
    constructor Create;
    procedure Boring;
    end;

    We want to call the protected Useful method, but all we got access to is the public Boring method. Typical, right? ;) If you are lucky, you have control over the type of the instance you are using, and can write your own descendent that promotes the method the clean way, like this:

    type
    TMyUtility = class(TUtility)
    public
    procedure Useful;
    end;

    procedure TMyUtility.Useful;
    begin
    inherited Useful;
    end;

    Now you can use TMyUtility instead of TUtility and you'll have the Useful method available as a public method. A final twist is to use the same class name, like this:

    unit MyUtility;

    interface

    uses
    Utility;

    type
    TUtility = class(Utility.TUtility)
    public
    procedure Useful;
    end;

    Now you only need to add the MyUtility reference in the uses clause after the Utility reference. However, sometimes you cannot control the type of the instance used - it is created inside a body of 3rd party code, for instance.


    As many experienced Delphi programmers will know, you can easily gain access to the protected members of a class instance, simply by casting the instance to a descendent class type declared in the same unit as the cast-expression. For instance, to call the protected Useful method of an instance of the TUtility class you can just:

    type
    TUtilityEx = class(TUtility)
    end;

    procedure Foo(Instance: TUtility);
    begin
    // Fails to compile, cannot call protected method
    Instance.Useful;
    // compiles fine, calls protected method
    TUtilityEx (Instance).Useful;
    end;

    The way the Delphi visibility directives work, all code in the same unit as the declared class will gain full public access to all members. It is a kind of implicit friend concept as known from C++.


    Thanks to the ingeniousness of Borland's compiler developers this common hack even works in .NET with Delphi 8 - as long as the caller and method is in the same assembly - it does not work across assemblies, because protected maps to the family-or-assembly method attribute in the CLR.


    One very prominent component vendor even routinely hides away truly useful (and sometimes essential) methods of their component and helper classes into the protected section, seemingly only in an attempt to hide complexity from naïve users. Then in all their own units that need access to the methods, they turn around and perform this local-descendent-cast hack and their own classes. Shudder! This hack should only be used to get access to other people's code, and not used between your own units!


    Interestingly, the compiler only uses the local hack-class to get access to the protected method. Although the TUtilityEx class is mentioned in the source code, nothing from that class (the VMT, RTTI, classname info etc.) is needed or referenced in the compiled code, so the smart linker removes it from the executable code. Otherwise this hack would be very expensive with regards to code-size.


    Thanks again, Danny & co!



    Copyright © 2004-2007 by Hallvard Vassbotn