Why do i get an "EPrivilege - Privileged instruction" when I execute this procedure instead of Access Violation?
{$Warnings OFF}
procedure TFrmMyTest.mnuCrashMeClick(Sender: TObject);
var t: TStringList;
begin
FreeAndNil(t);
end;
{$Warnings ON}
I know that I try to free an object that points randomly in memory. But I expect to get an access violation and not "Privileged instruction".
(Don't worry I don't intend to use the code above in a real program.)
FreeAndNil calls the non virtual method Free. Which first checks for nil(the variable likely isn't nil) and then calls the virtual destructor Destroy.
Calling a virtual method means looking at the beginning of an object to get the virtual-method-table(VMT). This can throw an access violation. But if the object is in allocated memory, it will instead return an undefined pointer as VMT.
Next a pointer sized value is read at a certain offset from the VMT. This once again can throw an access violation or return an undefined pointer.
Finally the memory where this pointer points is executed. And if it happen to contain invalid code, you get some variant of an invalid instruction exception.
Sometimes you will get an access violation and sometimes you will get EPrivilege and no doubt there are other modes of failure. And even sometimes the code will appear to work and the crash will happen later. It all depends on what value happens to be in t when you call Free on it.
Related
Why if I skip object creation, my code is still working ?
AbUnzipper1.FileName := 'C:\MyFile.zip'; never raises an access violation at runtime.
This (simplified) code is from a DLL, without form to put components on.
uses AbArcTyp, AbUnZper,...
...
var
AbUnZipper1: TAbUnZipper;
begin
// AbUnZipper1 := TAbUnZipper.Create(nil); COMMENTED !!!!!!!!
AbUnzipper1.FileName := 'C:\MyFile.zip';
AbUnzipper1.BaseDirectory := 'C:\temp\MyFolder';
AbUnzipper1.ExtractOptions := [eoCreateDirs, eoRestorePath];
AbUnzipper1.ExtractFiles('*');
AbUnZipper1.Free;
end;
With your code AbUnZipper1 is an undefined reference (i.e. a pointer). Behaviour when you access it is undefined. It may point to valid memory, or it may point to invalid memory.
If the latter, when you attempt to use the reference you will encounter a runtime error, an access violation. If the former, then you will succeed in accessing the memory, but that memory belongs to something else in your program and you will corrupt it.
If your program runs without error then that is by chance. You will likely have corrupted memory elsewhere along the way.
Your code is wrong, and you should fix it by restoring AbUnZipper1 := TAbUnZipper.Create(nil).
You should also make sure that you use try / finally in this code to avoid memory leak in case of exceptions.
I am trying to free Tlist within a Tlist in a onDestroy event and FastMM4 is raising an access violation error. Here is the code snippet.
procedure TSignalFrm.FormDestroy(Sender: TObject);
var
x,y: integer;
begin
for x := 0 to signalList.Count - 1 do
begin
for y:=0 to TSignal(SignalList.Items[x]).alarmList.Count-1 do
begin
TAlarm(TSignal(SignalList.Items[x]).alarmList.Items[y]).Free;
end;
TSignal(SignalList.Items[x]).AlarmList.Free;
TSignal(SignalList.Items[x]).Free;
end;
SignalList.Free;
end;
I get access violation error at TSignal(SignalList.items[x]).Free; line. Freeing AlarmList items before freeing SignalList items raises the access violation error, but WHY?
Update: I am using Delphi 7.0 on Windows XP. The actual FastMM4 messages is as follows.
FastMM has detected an attempt to call a virtual method on a freed object. An access viloation will now be raised in order to abort the current operation.
Freed Object class: TList
Virtual method: Destroy
Virtual method address:427CF0
The allocation number was: 80055
Followed by a lots of memory dump.
According to this FastMM4 error, if you free an object within an another object, you automatically free the owner as well. I know that can't be true, but correct me if I am wrong.
Does TSignal not free its AlarmList member in its destructor? (That’s how I would do this).
Update: does it work if you remove the TSignal(SignalList.Items[x]).AlarmList.Free; line?
Second update:
Each TList's items need to be freed, if it contains pointers to objects.
Your problem was that TSignal is not a TList. Since it takes care of freeing its members (such as the Alarmlist), that Alarmlist should not be freed explicitly.
Since TAlam and TSignal are both objects (not records) I believe you should use TObjectList instead of TList. TObjectList has a special property calld OwnsObjects that allows it to free it's contents properly as it is being freed. Check this out http://docwiki.embarcadero.com/VCL/XE/en/Contnrs.TObjectList.OwnsObjects
As an advice do not use TList unless you need to store pointers not objects.
I'm working with Delphi XE, and writing an application that is using RemObjects SDK to communicate (in case that may be relevant). I have FastMM debug on, and sometimes (not always) when I close it gives a warning about a single "Unexpected Memory Leak". "An unexpected memory leak has occurred. The unexpected small block leaks are: 117-124 bytes: UnicodeString x 1". Very occasionally, I get x2 reported.
Now, my understanding is that Strings are reference counted, and since there is no other object involved to cause the leak, what might be the situation that could cause this to happen? In this StackOverflow question people cannot find a way to make a leak.
If there is no obvious way, then I will download the latest FastMM source (it appears not to be included with the XE source).
[Edit once resolved] The solution to finding this was to install FastMM source, and enable the FullDebugMode to get the stack trace.
When using typed constants and depending on finalization order, it used to be possible for FastMM to report a leak when there really isn't.
FastMM: Leaked memory reported where I believe it shouldn't.
In short, when the FinalizedFirst unit
get's finalized, the SString constant
get's freed. After finalization of the
unit is done, the finalization of
FinalizedLast get's called. In it is
finalization, it call's the method
LeakMemory of the FinalizedFirst
method. The SString variable gets
initialized again and doesn't get
freed as the finalization of
FinalizedFirst has already run.
FinalizedLast Unit
unit FinalizedLast;
interface
uses FinalizedFirst;
implementation
initialization LeakMemory;
finalization LeakMemory;
end.
FinalizedFirst Unit
unit FinalizedFirst;
interface
procedure LeakMemory;
implementation
uses FinalizedLast;
procedure LeakMemory;
const
SString: string = '';
begin
//***** SString will get initialized once or twice depending on the
// finalization order of units. If it get's initialized twice,
// a memory leak is reported.
if SString = '' then
SString := 'FooBar';
end;
end.
Project LeakMemory
program LeakMemory;
uses
FastMM4 in 'FastMM4.pas',
Forms,
FinalizedFirst in 'FinalizedFirst.pas',
FinalizedLast in 'FinalizedLast.pas';
{$R *.RES}
begin
Application.Initialize;
Application.Run;
end.
You can leak strings by freeing records on the heap using FreeMem instead of Dispose or if you overwrite a record using System.Move or FillChar. In the first case the finalization code isn't run and in the second if the string field was filled with a nil it will think it's already cleared it.
If you want to find the location for the leak download FastMM and turn on FullDebugMode. It will include a stack trace of where the leak occurred.
The only way that comes to mind where you can leak a string without deliberately breaking it (like manually incrementing the ref count or doing some messy pointer operation) is by using threadvar.
Like the help file states,
Dynamic variables that are ordinarily
managed by the compiler (long strings,
wide strings, dynamic arrays,
variants, and interfaces) can be
declared with threadvar, but the
compiler does not automatically free
the heap-allocated memory created by
each thread of execution. If you use
these data types in thread variables,
it is your responsibility to dispose
of their memory from within the
thread, before the thread terminates.
Beside that, there's nothing that comes to mind that wasn't already stated.
[Edit by questioner] This was indeed the issue, and the specific code was as follows:
threadvar
g_szAuthentication : String;
procedure TMyBase.SetAuthentication(szUserName, szPassword: String);
begin
g_szAuthentication := '?name=' + szUserName + '&pass=' + szPassword;
end;
I usually see string leaks when they are contained inside other objects that have not been destroyed properly. For example an object that has not been freed. However, you would expect to see that object reported too.
The way to resolve this is to download and use the full version of FastMM and configure it to report stack traces when it detects leaks. When you do that you will get a full stack trace of the code that allocated the leaked object and at that point it is usually clear what the problem is.
type
TTest = class
a: integer;
end;
TTest2 = class(TTest)
b: integer;
end;
var c:TTest;
begin
c:=TTest2.Create();
c.Free;
end;
No, it will not.
A variable of a base class type can be used for instantiating objects from its child classes (they are type compatible), but take note that using such a variable, you will have access only to TTest members, not TTest2 members. That means; you can access "a", but not "b".
Also, if you face any exception during TTest2.Creation execution, Create won't return a partially built object.
However, if you have some other codes between TTest2.Create and c.Free calls, raising an exception in those codes can cause memory leak; because C.Free might not execute. In such a case you should use a try-finally block.
No, there is no memory leak here. The constructor only returns a new resource if it succeeds. You can only leak if the constructor succeeds and you fail to call Free. Since you do nothing in between the constructor and the call to Free, there can be no leak.
If a constructor fails then:
The destructor is called to free any resources.
An exception is raised.
The constructor does not return because the exception changes program flow.
The assignment to the object variable, c in your example, does not happen.
Note that the answer from #vcldeveloper which you have accepted is incorrect in stating that nil is returned. Nothing is returned from a constructor that raises.
You should always wrap Create/Free pairs with try/finally as follows:
obj := TMyClass.Create;
try
obj.DoSomething;
finally
obj.Free;
end;
You only need to protect the resource once it has been assigned. So you place the try after the assignment.
If you place the try before the constructor that is an error:
try
obj := TMyClass.Create;
obj.DoSomething;
finally
obj.Free;
end;
If the constructor fails then obj is not assigned and then when Free runs (and it will run thanks to the finally!) it is called on an uninitialized variable which results in undefined behaviour.
I have a simple record type. I allocate an new instance of this record and use a procedure ("_clone") to copy values from an existing record to the new one. I obtain an access violation only when assigin a string value.
Any ideas? Help is much appreciated.
TYPE Definition:
TPointer = ^TAccessoryItem;
TAccessoryItem = Record
Id : Integer;
PartNumber : String;
Qty : Integer;
Description : String;
Previous : Pointer;
Next : Pointer;
end;
Procedure TAccessoryList._clone (Var copy : TAccessoryItem; Var original : TAccessoryItem);
begin
copy.Id := original.Id;
copy.Qty := original.Qty;
copy.Partnumber := original.Partnumber; **// Access errors happens here**
copy.Next := Nil;
copy.Previous := Nil;
end;
Calling application below:
procedure TAccessoryList.AddItem(Var Item : TAccessoryItem);
Var
newItem : ptrAccessoryItem;
begin
GetMem(newItem, sizeOf(TAccessoryItem));
_clone(newItem^, Item);
end;
You need to initialize your new structure with zeros. GetMem does not zero the allocated memory, so the fields of your record initially contain random garbage. You need to call
FillChar(newItem^, sizeof(TAccessoryItem), 0)
after the GetMem, before using the record.
Here's why: When you assign to the string field of the newly allocated but uninitialized record, the RTL sees that the destination string field is not null (contains a garbage pointer) and attempts to dereference the string to decrement its ref count before assigning the new string value to the field. This is necessary on every assignment to a string field or variable so that the previous string value will be freed if nothing else is using it before a new value is assigned to the string field or variable.
Since the pointer is garbage, you get an access violation... if you're lucky. It is possible that the random garbage pointer could coincidentally be a value that points into an allocated address range in your process. If that were to happen, you would not get an AV at the point of assignment, but would likely get a much worse and far more mysterious crash later in program execution because this string assignment to an uninitialized variable has altered memory somewhere else in your process inappropriately.
Whenever you're dealing with memory pointers directly and the type you're allocating contains compiler managed fields, you need to be very careful to initialize and dispose the type so that the compiler managed fields get initialized and disposed of correctly.
The best way to allocate records in Delphi is to use the New() function:
New(newItem);
The compiler will infer the allocation size from the type of the pointer (sizeof what the pointer type points to), allocate the memory, and initialize all the fields appropriately for you.
The corresponding deallocator is the Dispose() function:
Dispose(newItem);
This will make sure that all the compiler-managed fields of the record are disposed of correctly in addition to freeing the memory used by the record itself.
If you just FreeMem(newItem), you will leak memory because the memory occupied by the strings and other compiler managed fields in that record will not be released.
Compiler managed types include long strings ("String", not "string[10]"), wide strings, variants, interfaces, and probably something I've forgotten.
One way to think about is this: GetMem/FreeMem simply allocate and release blocks of memory. They know nothing about how that block will be used. New and Dispose, though, are "aware" of the type you're allocating or freeing memory for, so they will do any additional work to make sure that all the internal housekeeping is taken care of automatically.
In general, it's best to avoid GetMem/FreeMem unless all you really need is a raw block of memory with no type semantics associated with it.
Also records are value types (as opposed to reference types like tObject) so you can just do
AccessoryItem1 := AccessoryItem2;
(or AccessoryItem1^ := AccessoryItem2^ if they are pointers)
and it will copy all the fields over for you.
For the same reason you should be careful when passing them around as method parameters - unless you use a pointer delphi will create a new copy of the record everytime you call a method with it as a parameter.