14.04.2015, 21:49
Introduction
Known (or suspected) compiler bugs. Feel free to add more if there are any.
1)
Credits to Y_Less..
Known (or suspected) compiler bugs. Feel free to add more if there are any.
1)
- Code
pawn Code:return "Some string"; - Problem
Returning string literals directly crashes the compiler.
- Solution
Put the string you want to return in to an array. If you use "static const" to declare the array the resulting code is either identical to, or in some cases BETTER THAN, the original version returning a string literal.
pawn Code:static const
szcHi[] = "hi";
return szcHi;
- Code
pawn Code:string = (a == 5) ? "is five" : "is not five"; - Problem
Strings can be concatenated by the compiler, for example this will compile as the single string "Hello World":
pawn Code:string = "Hello" " " "World";
pawn Code:<path>\errors.pwn(11) : error 001: expected token: "-string end-", but found "-identifier-"
Pawn compiler 3.2.3664 Copyright (c) 1997-2006, ITB CompuPhase
1 Error.
- Solution
To fix this, just enclose the strings in brackets, which the commpiler DOES recognise as a valid string end. Note again that the does not affect the generated code in any way so there is no run-time cost associated with this fix.
pawn Code:string = (a == 5) ? ("is five") : ("is not five");
- Code
pawn Code:new gGlobalVariable = SomeFunction(); - Problem
Calling a function to initialise a global variable outside of a function will crash the compiler.
- Solution
Call the function to initialise the variable in "OnGameModeInit", "OnFilterScriptInit", or "main".
4)
- Code
pawn Code:#emit SYSREQ.C fblockread - Problem
When using "SYSREQ.C" to call a native function, the compiler will not add that native function to the list of used native functions stored in the .AMX file. If the function is not already there the compiler will crash.
- Solution
The simplest way to fix this crash is to add a function something like the following BEFORE the function in which "SYSREQ.C" is found:
pawn Code:forward SYSREQ_FIX();
public SYSREQ_FIX()
{
fblockread(File:0, "", 0);
}
pawn Code:MyFunc()
{
fblockread(File:0, "", 0);
#emit SYSREQ.C fblockread
}
- Code
pawn Code:stock Function1()
{
}
stock Function3()
{
#emit CONST.pri Function2
}
stock Function2()
{
} - Problem
It seems that if a function uses "CONST.pri" to get the address of a function, and that function comes after other functions in the same file, and those functions are stock and not included, then "CONST.pri" will get the wrong value.
- Solution
I suspect what is happening here is that the compiler first compiles all the functions in a file, and from there gets the address of any functions used in "CONST.pri". THEN it removes any functions that are not used and shifts all later functions up in memory. This causes the address of the functions to change but any "CONST.pri" (or "CONST.alt") uses are not updated.
The solution is simple - because as far as I can tell the problem only occurs within a file, just move any functions used in "CONST.pri" to near the top of the file.
Note that I am not ENTRELY sure of the circumstances under which this happens yet (I only found it last night). When it happened the function whose address I was getting was AFTER the function in which the address was being got. That may have also contributed to the issue and thus simply moving the target function up should solve the issue.
- Code
Unknown.
- Problem
The compiler has a line length limit of 512. Normaly if this limit is breached you will get a line length error, but it is possible when using macros to push over this limit without the compiler noticing and thus crash the compiler. I have no idea exactly what causes it though.
- Solution
Write shorter lines. Normally this is simpler than people think:
pawn Code:format(str, sizeof (str),
"A long string",
other,
parameters);
- Code
pawn Code:#emit CALL main - Problem
You can't use the "CALL" assembly instruction with "#emit" - it seems to crash the compiler.
- Solution
If you can, just call the function normally:
pawn Code:main();
pawn Code:#emit LCTRL 6
#emit ADD.C 28
#emit PUSH.pri
#emit CONST.pri main
#emit SCTRL 6
- 8 )
- Code
pawn Code:#include <a_samp>
_:operator=(Taggg:a)
{
return _:a + 5;
}
main()
{
new
a = d();
printf("%d", a);
}
forward Taggg:d();
Taggg:d()
{
return Taggg:5;
} - Problem
If you use a custom assignment operator (as "Float:" does) and forward a tag returning function AFTER it is first used instead of before, the compiler can think that the function is both not used and used, so generate code assuming that it exists but never include it and result in the wrong code being called (the example above will endlessly loop "main").
More information can be found here: https://sampforum.blast.hk/showthread.php?tid=425970
- Solution
Place the tag returning function's "forward" above where it is first used (here "main"). Alternatively remove the "forward" all together, that will generate the correct code but with a warning.
- Code
pawn Code:new gVar;
stock SomeFunction()
{
#if defined main
gVar = (gVar ? 0 : 1);
#endif
return 1;
}
main()
{
return SomeFunction() ? 0 : 1;
} - Problem
The code above will generate the first ternary operator on the SECOND compiler pass but not the first (the first time it doesn't yet know that "main" is defined later on). As a result, for some unknown reason, any other ternary operators in your mode will have the wrong code generated and cause a crash.
More information can be found here: https://groups.******.com/forum/?fro...pt/1Cg2C8dn-0A
- Solution
Don't put ternary operators inside condition code generation that relies on "defined".
- Code
pawn Code:new gVar;
stock SomeFunction()
{
if (gSomeVar == SOMETHING)
{
print("In if.");
}
#emit LCTRL 6
#emit STOR.pri gOtherVar
return 1;
} - Problem
When "#emit" assembly comes directly after an "if" statement, the compiler incorrectly assigns the assembly INSIDE the "if" statement instead of after it. The code above will compile as if you wrote this:
pawn Code:new gVar;
stock SomeFunction()
{
if (gSomeVar == SOMETHING)
{
print("In if.");
#emit LCTRL 6
#emit STOR.pri gOtherVar
}
return 1;
}
- Solution
The simplest solution is to place extra empty braces between the end of the "if" statement and the assembly:
pawn Code:new gSomeVar, gOtherVar;
stock SomeFunction()
{
if (gSomeVar == SOMETHING)
{
print("In if.");
}
{}
#emit LCTRL 6
#emit STOR.pri gOtherVar
return 1;
}
- Code
pawn Code:stock VaradicFunction(static_, args, ...)
{
new
str[128];
// Other code here.
return str;
} - Problem
Returning a string from a varadic function causes a run-time crash (not a compiler crash).
- Solution
This code curtesy of Slice:
pawn Code:stock VaradicFunction(static_, args, ...)
{
new
str[128];
// Other code here.
#emit LOAD.S.pri 8
#emit ADD.C 12
#emit MOVE.alt
#emit LCTRL 5
#emit ADD
#emit LOAD.I
#emit STOR.S.pri 24 // 16 + (static_args * 4)
return str;
}
Credits to Y_Less..