Where is maxint defined - duplicate definition? - delphi

I have a projectgroup in which all Win32 programs have the same ..\PatchLibs search path.
This folder contains a patched System.Win.Ctrl.pas containing:
{$IFDEF WIN32}
function _malloc(size: size_t): Pointer; cdecl;
begin
if (size > MaxInt) then
begin
Result := Nil
end
else
begin
try
Result := AllocMem(size);
except
Result := Nil;
end;
end;
end;
[This patch suppresses an error in midaslib (QC 104337)]
The issue:
One of the (smaller) projects gives a W1023 ("comparing signed and unsigned types") compiler warning on the 'MaxInt' line, all others build without warnings.
None of the projects have System.Win.Ctrl in their uses statements or in their project files.
Thinking there might be two typed constant definitions for Maxint I wanted to prefix Maxint with the 'correct' unit name, but can't find its definition.
I have searched through all available c:\program files (x86)\embarcadero\rad studio\9.0\source*.* files, but found no definitions.
System.MaxInt works but does not eliminate the warning.
Typecasting Cardinal(MaxInt) removes the warning, but I'd still prefer the 'fully qualified' solution.
(size_t is defined as ULONG_PTR is defined as NativeUInt)
I found Quality Central issue 102873, 69836 and 53202 but these refer to duplicate definitions C++ .h header files
Is my assumption about more than one definition correct? If so, what would/should the unit prefix be?
And most important: why do I get the compiler warning for that one project build only?

MaxInt is declared in the System unit. I'm pretty sure that's the only MaxInt that is in scope here. The warning you see is accurate. MaxInt is signed and size_t is unsigned. You should suppress the warning. For example you could cast MaxInt to size_t:
if size > size_t(MaxInt) then
That's fine because MaxInt is within the range of values of size_t.
As an aside, I'd probably deal with the underlying issue by hooking the function that needs fixing, rather than re-compiling the entire unit. I personally find that to be less invasive and easier to maintain.
Why do I get the compiler warning for that one
project build only?
Some ideas:
You only have one project that includes that unit.
You have different compiler options in different projects. Perhaps only one of your projects has warnings enabled, or only one project has that specific warning enabled.
You only have one project with WIN32 defined.
This file is only compiled once, but used multiple times. Perhaps because you are making rather building.
It's pretty hard to explain that part of your question. Irrespective, when the code in your question is compiled with warnings enabled, you will get that warning. You really are comparing signed and unsigned. So you really do need to suppress the warning with the method I provide above.
Remember that a warning does not mean that your code is broken. Suppressing that warning will not change the behaviour of the code. When you see that warning you analyse the code to check whether or not there is a problem. In this case, the code works fine and you just need to suppress the warning.

Related

How to handle spurious "H2077 Value assigned to '%s' never used" messages without suppressing all hints?

Delphi (10.3 Rio) emits spurious H2077 warnings for code like:
x := TFoo.Create;
y := nil;
try
y := function_that_can_throw;
// use x and y
finally
x.Free;
y.Free;
end;
Note: the warning would still be unwanted even if the compiler could prove that the function cannot throw, since AFAIK there is no way to lock the function into non-throwingness by declaring it nothrow as in other languages and to assert the nothrow property at the call site. Hence the code must be written under the assumption that the function can throw.
I would like to suppress the unhelpful/erroneous hint, but apparently it is not possible to suppress hint H2077 specifically, only all hints or none. I would like to leave hints enabled if possible, so I'm wondering if there is another option for suppressing H2077 in this situation.
Also, I would like to avoid having to code a redundant second try/finally frame, since it clutters the source and creates unnecessary object code. The simplest and most obvious alternative - calling an empty dummy procedure like pretend_to_use(y) which takes a TObject parameter and does nothing with it - would create an unnecessary global dependency and most likely superfluous function calls as well. Hence I'd like your advice on a better solution...
EDIT: it turns out that Andreas has a point and the above snippet does not create the spurious warning (special coding in the compiler?). Here is an amended snippet that does cause the unwanted hint:
TIdStack.IncUsage;
y := nil;
try
y := function_that_can_throw;
// use y and the Indy stack
finally
TIdStack.DecUsage;
y.Free;
end;
The Indy stack thing is from something I'm currently working on, but entering/leaving critical sections would perhaps be a more common situation.
If you really want to suppress H2077, here's how I do it.
In my "utilities include" unit I have routines like:
procedure preventCompilerHint(I: integer); overload;
procedure preventCompilerHint(S: string); overload;
These are EMPTY routines, consisting simply of begin end; blocks.
I simply call these routines to show the compiler that I am actually "using" the variable in question.
If you're like me & like to be able to do a build and see zero hints and zero warnings... Well, this is how I handle the H2077.
Some may say this is less than elegant. At times that may be true. At other times I simply want to suppress this hint and move on.
Do with this as you will...
NOTE: I removed the sample code as (a) it wasn't related to my suggestion here; and (b) it was generating more interest than the suggestion itself.

H2077 inside try finally block with goto - is it Tokyo's compiler defect?

After upgrading to 10.2 Tokyo one of third-party components started throwing a lot of exceptions. Debugging showed problematic part of code, that can be represented by this (hopefully) minimal code:
function foo(i: Integer): Boolean;
label bar;
begin
try
if i=1 then goto bar;
Result:=False;
EXIT;
bar:
Result:=True; //<~~ H2077 Value assigned to 'foo' never used with Optimization on
finally
end;
end;
With Optimization in compiler options set to
True (default for Release configuration) - foo(1) returns False
False (default for Debug configuration) - foo(1) returns True
Such problem does not occur in XE7. This answer explaining changes in Tokyo's compiler is probably related - but maybe fixing some of the problems introduced new.
My question is:
is it Tokyo's compiler defect? I am pretty sure it is, but I am new to programming in Delphi and it would be great to get confirmation from more experienced users.
If it is compiler's defect then I have a follow up question: is there any quick way to fix this code? I know how to remove goto in my MCVE with simple if then else statement, but real code is way more complicated:
if cond1 then goto bar;
if cond2 then goto bar;
if cond3 then goto bar;
...
if condN then goto bar;
And some of the if blocks also contain loops with inner goto. I know how to rewrite all of this logic to nested if then else blocks, but maybe there is an easier way to fix it without waiting for compiler's defect or third-party component to be fixed (I know any of those won't happen soon).
This is a compiler defect. foo(1) should return True.
It looks like the optimiser is confused by this particular use of goto.
Submit a bug report to Embarcadero. To get past the problem in the meantime you can:
Contact the third party component vendor and ask for a workaround, or
re-write the code to avoid the goto which appears to confuse the optimiser, or
revert to an older version of the compiler that is not defective, or
disable optimisation for any functions affected by the defect.

How to determine dependencies for all units? (Estimate refactoring cost)

Unfortunately I have inherited a piece of unlucky design based on a {$IFDEF} "hell".
What I have roughly looks like this (where MyDbSystemB is what I want to add)
unit MyTable;
interface
uses
// ...
{$IFDEF MyDbSystemA}
DbSystemA ,
{$ENDIF}
{$IFDEF MyDbSystemB}
DbSystemB ,
{$ENDIF}
type
TMyTable = class(
{$IFDEF MyDbSystemA}
TSystemATable
{$ENDIF}
{$IFDEF MyDbSystemB}
TSystemBTable
{$ENDIF}
)
// A public interface implementation
end;
implementation
// ...
end.
A number of units reference TMyTable, but rely on specific functions provided with TSystemATable:
unit oldUnit;
interface
uses MyDbTable;
type
TXy = class(TXyz)
public
procedure Foo();
end;
implementation
procedure TXy.Foo();
var
table : TMyTable;
begin
table := TMyTable.Create();
table.SomeSystemASpecificFunction;
end;
I'd like to find all of these references within a single reference/syntax check. But as I read here that's apparently not really possible
Find all compilation errors in a Delphi project.
What would be the best strategy to go for finding these files to estimate the efforts of porting?
A plain file grep over all *.pas files (there may be a lot of either dead code, or just poorly decoupled stuff)?
I'm also able to provide a surrogate implementation of
TMyTable = class( { ... like above } )
{$IFDEF MyDbSystemB}
public
procedure SomeSystemASpecificFunction; deprecated;
{$ENDIF}
end;
with the implementation of TMyTable, but I'd need to estimate the refactoring cost to do that properly anyways.
Regarding that I also could add a deprecated attribute along with the SomeSystemASpecificFunction surrogate, that will at least give me warnings.
If you know the names of the members of TMyTableA that code takes a dependency on then use Find in Files... (or your favorite alternative grep-like tool) to identify references to those members in the files in your project.
This is likely to be more reliable than any compilation based check anyway.
Any tool which claims to find "all compilation errors in a project" is more often than not lying to you since there is no reliable way to discriminate between errors that have not arisen as a result of some other error earlier in the compilation.
e.g. in a C# solution it is quite common for a simple change to result in dozens if not hundreds of compilation errors which are fixed by resolving only the first error.
i.e. the compiler reports (e.g.) 224 errors when in fact there is only 1 error with 223 errors as a side-effect.
For the same reason, you cannot be sure that the list of errors contains all of the genuine errors you might eventually uncover. In some cases the compiler might yet be defeated to the point of not even attempting to compile some code that contains the errors you are looking for, as a consequence of those side-effect errors.
Certainly, in the list of dozens or hundreds of errors you might then be able to grep to find ones that appear to be candidates for the "genuine" errors you are looking for (i.e. that reference the specific members you know to be involved in your change). But all that does is change the data set you are searching for to locate those references. i.e. the compilation error list rather than your project sources.

Does Delphi compiler perform optimization?

I am using Delphi 7 IDE. Does Delphi compiler optimize codes, just like what the C++ compiler is doing in this following link?
http://msdn.microsoft.com/en-us/library/aa366877(VS.85).aspx
WCHAR szPassword[MAX_PATH];
// Retrieve the password
if (GetPasswordFromUser(szPassword, MAX_PATH))
UsePassword(szPassword);
// Clear the password from memory
SecureZeroMemory(szPassword, sizeof(szPassword));
If ZeroMemory were called in this example instead of SecureZeroMemory, the compiler could optimize the call because the szPassword buffer is not read from before it goes out of scope. The password would remain on the application stack where it could be captured in a crash dump or probed by a malicious application.
Yes, of course Delphi performs optimizations. However, it does not perform the optimization that the SecureZeroMemory function is meant to circumvent. There is no need to use that function in Delphi; just use plain old ZeroMemory, or even FillChar. They're not macros, and they don't do anything that Delphi recognizes as being unused assignment statements that could get optimized out.
Delphi performs code optimization by default, you can disable it in Project > Options > Compiler.
The Delphi help provide a few tips of what type of optimizations are used:
The $O directive controls code optimization. In the {$O+} state, the compiler performs a number of code optimizations, such as placing variables in CPU registers, eliminating common subexpressions, and generating induction variables.
It also states that "the compiler performs no "unsafe" optimizations", but in the sense that they won't alter the execution path, not from a security point of view.
Delphi certainly optimizes code (it is a modern, and excellent, compiler). Another example of optimization deleting lines is:
SomeFunction(); // Set breakpoint here, then step (F10)
myInt := 7; // Next line will not hit this...
myInt := 13; // ...but will instead skip to here
I like to ensure optimization is in the correct state (and not accidentally left switched on or off) by adding {$I MyProjectOptions.inc} in every .pas file in my project. This goes just below the unit name (right at the top of the file). In "MyProjectOptions.inc" you simply add this code:
// Is this a debug or non-debug build?
{$IF Defined(DEBUG)}
{$O-} // Turn optimization off
{$ELSEIF Defined(NDEBUG)}
{$O+} // Ensure optimisation is on
{$IFEND}
Finally, ensure you have defined "DEBUG" and "NDEBUG" (or your equivalent in older versions of Delphi) in the Conditional defines section of Project > Options > Diectories/Conditionals.
I don't believe the compiler will ever eliminate apparently dead code like this. I have never had trouble setting breakpoints on code that could have been eliminated as redundant.
For some scenarios, the compiler can detect if the code is unreachable and eliminate the code.
For instance, the compiler correctly eliminates the "unreachable" portion of the code below.
It will not generate code for that line so:
So there are no blue bullets indicating there is code
Breakpoints put on that line will be marked visually as 'not reachable'
Just tested in Delphi XE, but older Delphi versions have similar behaviour.
program Project1;
{$APPTYPE CONSOLE}
uses
SysUtils;
procedure Test;
begin
if (True = False) then
Writeln('Unreachable')
else
Writeln('Reachable');
end;
begin
try
Test();
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
It takes quite some while to learn when (or when not) the optimizer on code level and liker level kicks in.
For instance: When you have optimizations turned on, the compiler will also eliminate variables as soon as they are not used.
Sometimes, it even eliminates global symbols.
Danny Thorpe (former Delphi Compiler engineer and Chief Scientist) once wrote a magic method Touch that prevents this.
Just call this Touch method at the end of your method to fool the optimizer during debugging:
procedure Touch(var arg);
begin
end;
--jeroen

Trouble with THTML file GDIPL2A.pas

Running a project and was getting an error saying
"Not enough actual parameters"
The error is in "C:\Program Files\PBear\HTMLComponents\package\GDIPL2A.pas".
The mistake pointed three times to "inherited Create;" lines 260,270 and 278 . In the file "GDIPL2A.pas".the Code is:-
var
err: integer;
begin
inherited Create;
err := GdipCreateBitmapFromScan0(W, H, 0, PixelFormat32bppARGB, nil, fHandle);
if err <> 0 then
raise EGDIPlus.Create('Can''t create bitmap');
end;
I was wondering why it would show an error in "THTML" files, WHICH ARE NOTHING BUT FILES FROM THE INSTALLATION of THTML.I did not even touch THTML files.
Kindly help
Thanks and Regards
Vas
A "Not enough actual parameters" error on "inherited Create;" means that you're trying to call an inherited constructor but it not supplying any parameters. Check the class you're inheriting from and you'll see a Create that requires some parameters. (If the base class doesn't have one, check its parent, and its parent and so on. You'll find one eventually.) It should be pretty obvious once you find the constructor declaration what you need to pass to it.
Your call needs to look something like:
inherited Create(param1, param2);
I have THTML, and it indeed includes GDIPL2A.pas, which is a wrapper around GDIPlus; apparently THTML uses GDIPlus to display embedded images or something.
A quick look at the declaration of TGPImage and TGpBitmap shows the constructor declarations of each:
// TGpImage
public
constructor Create(FileName: string; TmpFile: boolean = False); overload;
constructor Create(IStr: IStream); overload;
// TGpBitmap
public
constructor Create(W, H: Integer); overload;
constructor Create(IStr: IStream); overload;
You'll see that all of the constructors takes at least one or two parameters; your call to inherited Create passes none. However, since the call to inherited is in another constructor it should work (and indeed does on my machine; I just tried rebuilding one of the demos from THTML and it recompiled GDIPL2A.pas fine), You've got something else going on, like a different version of GDIPL2A in your path that the compiler is using instead of the one you're seeing in the IDE's editor.
As to your question, I answered it in the first paragraph above. It's reporting the error in THTML because that's the copy of GDIPL2A that the compiler is using, which may not be the one your code is expecting it to use.
You can fix that by either:
Reordering units in the uses clause of your code so that all calls that cause GDIPL2A to compile are using the same one;
Copy the GDIPL2A your code thinks it's using into your project's source folder, so it will be compiled from there. This will probably break THTML if you're using it in that same project, so be ready for that;
Find and resolve the competing copies of GDIPL2A so that there's only one copy available on the compiler's search path;
Remove the THTML path from your project's search and library paths, if you're not using it in your problem project. You can also, using Project|Options|Packages, prevent THTML from even being loaded when you open the project if you'd like, to make your project load faster.
I don't know if anybody read this anymore but my problem occurred during installing of ThtmlViewer. My solution was to edit the GDIPL2A.pas file. I just added an emty string and a false boolean, so the 3 create statements looked like this:
inherited Create('', False);
And then everything worked fine (at least so far)
(I have an old Delphi 4 on an old Windows Xp on an old PC, not connected to internet)
Kindly
Erling

Resources