XE7 and more With weirdness
XE7 and more With weirdness
100% reproducable fail: Access violation at address 00B5464D in module 'MyApp.exe'. Read of address 00000040.
Fails:
tpLot := Tp.Add;
with tpLot do
begin
LotId := Lot.Id; // <--BANG
LotNo := Lot.LotNumber;
ExpiryDate := Lot.ExpireDate;
ProducedDate := Lot.ProducedStartTime;
ArticleId := ArtSum.ArticleId;
ArticleNo := ArtSum.ArticleNumber;
OriginalArticleId := ArtSum.ArticleId;
Quantity := NumDPacks * ArtSum.BaseUnitsPerKPack;
NetWeight := Quantity * ArtSum.NetWeightPrBaseUnit;
GrossWeight := NetWeight +
(ArtSum.TaraWeightPrFPack * Quantity);
LotLockState := Lot.LockStateCode;
end;
Works:
tpLot := Tp.Add;
tpLot.LotId := Lot.Id;
tpLot.LotNo := Lot.LotNumber;
tpLot.ExpiryDate := Lot.ExpireDate;
tpLot.ProducedDate := Lot.ProducedStartTime;
tpLot.ArticleId := ArtSum.ArticleId;
tpLot.ArticleNo := ArtSum.ArticleNumber;
tpLot.OriginalArticleId := ArtSum.ArticleId;
tpLot.Quantity := NumDPacks * ArtSum.BaseUnitsPerKPack;
tpLot.NetWeight := tpLot.Quantity * ArtSum.NetWeightPrBaseUnit;
tpLot.GrossWeight := tpLot.NetWeight + (ArtSum.TaraWeightPrFPack * tpLot.Quantity);
tpLot.LotLockState := Lot.LockStateCode;
Lot and ArtSum are properly initated and readable (inspected in debugger), so I assume it is the assignment that fails.
The problem is, I cannot reproduce in a mini-example.
If I wasn't set at eradicating all with statements before, I surely am now.
#sigh
100% reproducable fail: Access violation at address 00B5464D in module 'MyApp.exe'. Read of address 00000040.
Fails:
tpLot := Tp.Add;
with tpLot do
begin
LotId := Lot.Id; // <--BANG
LotNo := Lot.LotNumber;
ExpiryDate := Lot.ExpireDate;
ProducedDate := Lot.ProducedStartTime;
ArticleId := ArtSum.ArticleId;
ArticleNo := ArtSum.ArticleNumber;
OriginalArticleId := ArtSum.ArticleId;
Quantity := NumDPacks * ArtSum.BaseUnitsPerKPack;
NetWeight := Quantity * ArtSum.NetWeightPrBaseUnit;
GrossWeight := NetWeight +
(ArtSum.TaraWeightPrFPack * Quantity);
LotLockState := Lot.LockStateCode;
end;
Works:
tpLot := Tp.Add;
tpLot.LotId := Lot.Id;
tpLot.LotNo := Lot.LotNumber;
tpLot.ExpiryDate := Lot.ExpireDate;
tpLot.ProducedDate := Lot.ProducedStartTime;
tpLot.ArticleId := ArtSum.ArticleId;
tpLot.ArticleNo := ArtSum.ArticleNumber;
tpLot.OriginalArticleId := ArtSum.ArticleId;
tpLot.Quantity := NumDPacks * ArtSum.BaseUnitsPerKPack;
tpLot.NetWeight := tpLot.Quantity * ArtSum.NetWeightPrBaseUnit;
tpLot.GrossWeight := tpLot.NetWeight + (ArtSum.TaraWeightPrFPack * tpLot.Quantity);
tpLot.LotLockState := Lot.LockStateCode;
Lot and ArtSum are properly initated and readable (inspected in debugger), so I assume it is the assignment that fails.
The problem is, I cannot reproduce in a mini-example.
If I wasn't set at eradicating all with statements before, I surely am now.
#sigh
I thought we all agreed "with" was a Bad Thing. ;) I have, in other versions, seen errors thrown when you qualify a member inside the "with" with the item assigned in the "with". Messy writing about that...
ReplyDeleteWe did agree, and it still is. It just takes time to get rid of all that has accumulated over the years. But a single with reference failing? That's bad!
ReplyDeleteLars Fosdal Be wary you might just be getting rid of the canary, or shooting the messenger, or breaking the thermometer ;)
ReplyDeleteEverything else being correct, this failure could just be a sign of other memory corruption/stack overwrites, and removing the "with" hides that issue under the carpet.
The fact you cannot reproduce it in a simpler case is another hint in that direction.
Inspect in the asm/CPU view, and debug the state there: if there is a memory corruption of some sort, the higher level debugger is unreliable.
Then, once that's solved, get rid of the "with".
Lars Fosdal Welcome to my world... I am removing them nearly every day. Big legacy project.
ReplyDeleteMight be worth a shot to try recompiling with FastMM with all checks enabled (double free etc etc) and see if that throws up anything.
ReplyDeleteWalter Prins - Did that, and it's solid.
ReplyDeleteIt was the assignment side that was broken.
One thing I just noted - tpLot.LotNo had duplicates in the procedure parameters, but the with parameter should "out-scope" those.
procedure SomeClass.DoThis(const ArticleNo, LotNo: String);
var
Lot: TLot;
ArtSum: TArticleSummary;
tp: TPack;
tpLot: TPackLot;
begin
ArtSum := ArtSummaries.Locate(ArticleNo);
Lot := Lots.Locate(LotNo);
tp := TPack.Create;
tpLot := tp.Add;
with tpLot
do begin
LotId := Lot.Id;
LotNo := Lot.LotNumber;
ExpiryDate := Lot.ExpireDate;
ProducedDate := Lot.ProducedStartTime;
ArticleId := ArtSum.ArticleId;
ArticleNo := ArtSum.ArticleNumber;
OriginalArticleId := ArtSum.ArticleId;
...
If you assign Lot to a local variable named something else and use that inside with, does the with still bomb?
ReplyDeleteGiven that Lot already is a local var, and not in duplicate with anything else, and found and returned by the locator - that seems far fetched.
ReplyDeleteI'd give it a spin, but I've consumed all the testable data I received. I'll check with the warehouse peeps if they can send me more pallet labels.
Lars Fosdal Well was just thinking if the With pulled in a different Lot.
ReplyDeleteWhat you state doesn't tally with my understanding of scope. The variables brought into scope by that with are searched first. So the code emitted should be identical. The fact that you cannot make a repro suggests that the issue is on your end.
ReplyDeleteDavid Heffernan - When I put a breakpoint on the first assignment, I can inspect all properties of Lot, but when I do F8 to step to next line - I get the exception. If the right side of the assignment was the issue, why does the problem go away when I take out the left side With?
ReplyDeleteUnless the code generated is for assigning to a const LotNo string, and that somehow fails - which also would be a compiler error.
Have you had a look at the generated asm code yet? It usually helps me tracking down what the actual problem is.
ReplyDeleteTo make progress, cut it down. Do you need all of the assignments? Or is one enough? Make a repro.
ReplyDeleteBill Meyer I agree. With is evil. The small optimizations perhaps generated by the compiler are not worth the frustrations. Having manned Borland's help desk. I could testify...
ReplyDelete