compuphase / pawn Goto Github PK
View Code? Open in Web Editor NEWPawn is a quick and small scripting language that requires few resources.
Home Page: http://www.compuphase.com/pawn/
License: Other
Pawn is a quick and small scripting language that requires few resources.
Home Page: http://www.compuphase.com/pawn/
License: Other
From "pawn language guide"
If an argument in the replacement text has a “#” immediately in front of it, the argument is converted to a packed string constant —meaning that double quotes are tagged at the beginning and the end.
so, this code
#include <console>
#define STR(%1) #%1
main()
{
printf(STR("TEST"));
}
has compile error. Maybe "stringize" has to involves more than putting double-quote characters around the fragment (backslash-escapes the quotes surrounding embedded string constants) ?
Is it alright that I request Pawn to have standalone references like C++ does?
new i = 5;
new &p = i;
p = 9; // i is now 9
Perhaps denote it by giving it a different operator?
modified example above
new i = 5;
new @p = i;
p = 9; // i is now 9
Same example above but with floating point.
new float:f = 5.02;
new &float:p = f;
p = 3.14; // f is now 3.14
The simple garbage collector in amxgc.c
appears to have a few issues which lead to loops never terminating. If the table has filled up and gc_mark
is called, then the condition if (SharedGC.count>=(1<<SharedGC.exponent))
in gc_mark
, which is for enlarging the table, is never true because it appears that SharedGC.count
is always zero. The only assignments to SharedGC.count
set it to 0. (The naming of count
is perhaps unfortunate because there are two of them, one in GCPAIR
and one in GCINFO
and both appear to have totally different uses.) Since the table is not enlarged the while loop in gc_mark
cannot find a free entry and never terminates.
Furthermore, scansection
has two while loops and the inner one will loop forever if the table is full and the value in *start
cannot be found (which is likely) and the table has no free entries.
I am unsure what the search algorithm is trying to achieve, i.e. with the "folding" etc. It appears to be trying to implement something that is faster than a simple linear search but without more information on the algorithm I don't feel like modifying the while loop in scansection.
Not a bug but just out of curiosity, what is the point of the inverse array? What does *minorbyte=inverse[*minorbyte]
do that *minorbyte=~(*minorbyte)
or *minorbyte=255 - *minorbyte
does not?
"hdr" isn't initialized while checking file_version
int AMXAPI amx_InitJIT(AMX *amx, void *reloc_table, void *native_code)
{
int res;
AMX_HEADER *hdr;
if ((amx->flags & AMX_FLAG_JITC)==0)
return AMX_ERR_INIT_JIT; /* flag not set, this AMX is not prepared for JIT */
if (hdr->file_version>MAX_FILE_VER_JIT)
return AMX_ERR_VERSION; /* JIT may not support the newest file version(s) */
/* the JIT does not support overlays, but this is already checked in VerifyPcode()
* the same goes for macro instructions: not supported in the JIT, but already
* checked in VerifyPcode()
*/
Instead of requiring a #pragma pack 1 in source, it would be more useful
for us to have a -Pack option to globally pack all strings in our script(s).
Original issue reported on code.google.com by [email protected]
on 2 Jan 2007 at 4:52
Original credit goes to @oscar-broman for discovering this bug.
Test code:
#include <console>
#include <string>
main()
{
const cellbytes = cellbits / charbits;
static const substring{} = "012";
static buffer1{} = "3456789";
static buffer2{4 * cellbytes} = {255, 255, ...};
strins(buffer1, substring, 0);
new bool: overrun_detected = false;
for (new i = 0; i < sizeof(buffer2) * cellbytes; ++i)
if ((overrun_detected = (buffer2{i} != 255)) == true)
break;
printf("buffer1 contents:");
for (new i = 0; i < sizeof(buffer1) * cellbytes; ++i)
printf(" %d", buffer1{i});
printf("\n");
printf("buffer2 contents:");
for (new i = 0; i < sizeof(buffer2) * cellbytes; ++i)
printf(" %d", buffer2{i});
printf("\n");
printf(overrun_detected ? "Buffer overrun detected!\n" : "Test passed\n");
}
Output:
buffer1 contents: 48 49 50 51 52 53 54 55
buffer2 contents: 56 57 0 255 255 255 255 255 255 255 255 255 255 255 255 255
Buffer overrun detected!
Unrelatedly, at the beginning of amxexec_arm7_gas.s
and amxexec_thumb2_gas.s
I found this:
This file assembles with GUN's AS (GAS).
This is just a grammar mistake, not a real bug, so I guess it's better to mention it here instead of creating a new issue.
I'm not sure is this right place to ask, but where can I find PAWN coding convention references for PAWN coding standards?
Like naming of variables, functions, consts, arrays, folders, files etc...
for (i=0; list[i].name!=NULL && (i<number || number==-1); i++)
Checks list[i].name
before checking i < number
, which is OOB when using an exact count and no sentinel entry. See:
Edit: Not an overflow, since nothing is written, but still OOB.
Please export pawnscript to GitHub.
Google Code:
"August 24, 2015 - The site goes read-only. You can still checkout/view project
source, issues, and wikis.
January 25, 2016 - The project hosting service is closed. You will be able to
download a tarball of project source, issues, and wikis. These tarballs will be
available throughout the rest of 2016."
Original issue reported on code.google.com by [email protected]
on 30 Jun 2015 at 3:08
my platform is 64-bit but I need Pawns cell size to stay 32-bit. How can I pass 64-bit C pointers to Pawn as 32-bit cell?
Hello,
Because pc_indentbits is a char, if a line is 256 bytes long, Pawn will freeze on compile.
pawn-4.0.5749
in file "amx.c"
amx_Init()
{
...
#if BYTE_ORDER==BIG_ENDIAN
if ((hdr->flags & AMX_FLAG_COMPACT)==0) {
ucell *code=(ucell *)((unsigned char *)program+(int)hdr->cod);
while (code<(ucell *)((unsigned char )program+(int)hdr->hea))
amx_SwapCell(code++);
} / if */
#endif
...
}
Originally discovered at pro-pawn.ru by a forum member nicknamed Blood:
http://pro-pawn.ru/showthread.php?14157
The compiler allows to make labels with the same name within a function scope.
If one defines two or more labels with identical names and use goto
to one of those labels, the compiler will make a jump at the last label with that name.
Sometimes this can lead to unexpected (or unintuitive) results.
Example:
#include <console>
main()
{
goto test_label;
test_label:
print("test_label 1\n");
return;
test_label:
print("test_label 2\n");
}
One might expect it to print "test_label 1", but it actually outputs "test_label 2".
The compiler warns about unreachable code (even though goto test_label
leads right to that code), but it doesn't even tell anything about the second test_label
shadowing the first one.
Normally I'd ask if this is a bug or it's intended to be so, but since Pawn is designed to be a robust language, I guess this should be considered a bug. The compiler should either disallow using the same name for labels more than once per function or at least give a warning message.
This bug was originally discovered by @ziggi.
#include <console>
#include <float>
stock PrintInt(i)
printf("int: %d\n", i);
stock PrintFloat(Float:f)
printf("float: %f\n", f);
stock PrintBool(bool:b)
printf("bool: %s\n", (b)?("true"):("false"));
stock Print({_, Float, bool}:arg, arg_tag=tagof(arg))
{
switch(arg_tag)
{
case tagof(Float:): // Line 17
PrintFloat(Float:arg);
case tagof(bool:):
PrintBool(bool:arg);
default:
PrintInt(_:arg);
}
}
main()
{
print("--Function overloading emulation test--\n");
Print(1);
Print(1.0);
Print(true);
}
When I try to compile this the compiler shows a bunch of error messages:
test.p(17) : error 081: expression with tag override must appear between parentheses
test.p(17) : error 029: invalid expression, assumed zero
test.p(19) : warning 217: loose indentation
test.p(19) : error 014: invalid statement; not in switch
test.p(19) : warning 215: expression has no effect
test.p(19) : error 001: expected token: ";", but found ":"
test.p(19) : error 029: invalid expression, assumed zero
test.p(19) : fatal error 107: too many error messages on one line
6 Errors.
Compilation aborted.
But if I put the tagof expressions into parentheses...
case (tagof(Float:)): // Line 17
PrintFloat(Float:arg);
case (tagof(bool:)):
PrintBool(bool:arg);
... the code compiles and works normally.
What steps will reproduce the problem?
1. Acquire a 64-bit GNU/Linux installation
2. Attempt to compile PAWN
3. Behold the error log
What is the expected output? What do you see instead?
I expect to see the program build, but instead I see numerous errors regarding
integers of one size being assigned to integers of a smaller size, which is a
classic 64-bit portability problem.
What version of the product are you using? On what operating system?
PAWN 4.0.4733 and PAWN SVN July 27, 2012 on Arch Linux (rolling-release).
Please provide any additional information below.
This problem seems to indicate that PAWN is not portable to 64-bit
architectures (or, at least, 64-bit GNU/Linux).
Original issue reported on code.google.com by Luiji99
on 28 Jul 2012 at 4:39
When multiple automations are created only the entry and exit functions can be used for a single automation. For example:
entry() <s1: A1> { print("A1"; }
entry() <s1: A2> { print("A2"; }
entry() <s2: B1> { print("B1"; }
entry() <s2: B2> { print("B2"; }
Results in error 084: state conflict: one of the states is already assigned to another implementation ( symbol "entry").
It would be nice to use the automation rather than formulate a custom framework.
native printf(const str[], ...);
operator=(Tag:x)
{
return _:x:
}
main()
{
new a = Tag:5;
printf("%d", a);
}
This code should define a custom assignment operator for Tag:
, and call it. Instead, it gives an unused symbol warning for the operator=
and generates no code at all. Compiling with -a
gives:
CODE 0 ; 0
;program exit point
halt 0
STKSIZE 1000
Literally a totally blank AMX.
Note: This took a while to spot. I found the original bug here pawn-lang/compiler#387 and attributed it to the operator somehow, but @YashasSamaga was the one who noticed my typo, the root cause. I wrote _:x:
instead of _:x;
- a colon not a semi-colon, and very hard to spot. This should give a syntax error and not compile, but somehow messes up. I do know some errors are ignored when the function isn't used, which should be the case were it not, but it is. I think the fact that its an operator overload confuses that part of the compiler as well.
Hi
I tried different versions of Pawn under Ubuntu 16.04 64-bit: latest from github, 4.0.57.49 ZIP arvhive.
Compile OK with just issuing commands: cmake . && make
When I try simple examples like "Hello World!" - all works fine.
But when I try to add to my Pawn code <args> or <datagram> it falls with segmentation fault and gdb backtrace shows the following:
Program received signal SIGSEGV, Segmentation fault.
0x00000000f75fe004 in ?? ()
(gdb) bt
#0 0x00000000f75fe004 in ?? ()
#1 0x0000000000403933 in amx_Callback ()
#2 0x0000000000407a80 in amx_Exec ()
#3 0x0000000000403280 in main ()
What I'm doing wrong?
Thanks!
1. Compile the attached pawn_sub_bug.pawn with option -O2:
$ pawncc -O2 pawn_sub_bug.pawn
2. Run it:
$ pawnrun pawn_sub_bug.amx
Return value: -160
Expected value was +160.
Apparently the semantics of sub and sub.inv were changed sometime before Pawn
4, but the peephole optimizer was not updated to match. Here is a complete
patch, which is quite messy as I re-ran scpack:
https://github.com/PetteriAimonen/QuadPawn/commit/a80179d4e171203930cb9066b0511c
dd29b43392
The core of the patch is around line 1530 in sc7.scp:
* --------------------------------------
- * const.alt %1 add.c -%1
+ * const.pri %1 add.c -%1
* sub -
(Thanks to David Schwartz for finding this bug.)
Original issue reported on code.google.com by Petteri.Aimonen
on 2 Jun 2012 at 8:13
Attachments:
In 'when aborting inside an include file' section of the compiler, fclose is called where pc_closesrc should be.
"compiler/sc1.c" requires <process.h>, but linux doesn't contain process.h.
Compiler prints error log with "implicit declaration for spawnl()".
The repo only has the pdf versions of Pawn_Language_Guide
etc. It would be nice to be able to update those as well.
I am getting a segmentation fault on 64-bit Linux Mint on this file:
#include <console>
main()
{
printf("hello\n");
}
Compile string is pawncc -C:64 hello.p
, pawncc is compiled with -DHAVE_I64 -DPAWN_CELL_SIZE=64
, pawnrun is compiled with AMX_ALTCORE
(GNU extensions). This segfault traces back into amx_Exec->amx_exec_run->first NEXT instruction, it executes 7 times then crashes. Corresponding macro expansion is
#define NEXT(cip,op) goto *amx_opcodelist[(op=*cip++) & ((1 << sizeof(cell)*4)-1)]
My knowledge of underlying procedures ends here.
When compiling without AMX_ALTCORE, the same behaviour occurs: execution reaches the main for ( ;; )
loop, does 7 iterations and crashes successfully.
If I substitute printf with print in pawn code, it crashes after 13 iterations.
It seems that the segfault occurs with every native function that *.inc files in pawn toolkit provide (even with clamp; some other functions cause just run-time errors).
This problem arises in 32-bit pawn codes too, so I moved this post out of 64-bit thread into a new one.
Could you, please, show how to get process exit code?
My attempt (does not work):
#include <process>
main()
{
new PID:pr = procexec("7z t \"archive.zip\"")
printf "PID:%d\n", pr
if (pr != 0)
{
procwait(pr)
new ec = 0
libcall("kernel32", "GetExitCodeProcess", "uu", pr, ec)
printf "Exit Code:%d\n", ec
}
}
Can you add something like #error but for creating user warnings? And something like #pragma warning for adding new warnings and disabling/enabling existing.
This implemented in fork of Pawn 3.2.3664 by Zeex: https://github.com/Zeex/pawn/wiki/What's-new#pragma-warning
Print a user warning.
This works similar to the #error
directive. For example, compiling a file
that contains
#warning Don't include this file
would result in
warning 237: user warning: Don't include this file
This directive comes in two forms:
#pragma warning (enable|disable) XXX
Enable or disable a warning by its number.
Useful for hiding unwanted warnings that otherwise cannot be fixed.
#pragma warning (push|pop)
Save or restore the list of currently disabled warnings.
This can be used in conjuction with the previous form to toggle warnings
for a piece of code:
#pragma warning push
#pragma warning disable XXX
// some code here
...
#pragma warning pop
It could be very useful to make a Dependency/Package Manager for PAWN...
It's missing
OP_STACK is defined as:
STACK | value | ALT = STK, STK = STK + value
That means the current stack position is placed in to alt
, then the stack is adjusted. This is used in two ways:
To shrink the stack after some usage. This will mean that after the call alt
now points below the stack to invalid memory.
To expand the stack for more data. This will mean that after the call alt
will point to the old data that was already on the stack.
I have never ever seen a good use for this behaviour - it makes perfect sense for OP_HEAP
because that grows up, and so after expansion alt
will point to the start of the new data. In this opcode it is entirely useless. Much better would be:
STK = STK + value, ALT = STK
When growing the stack, that will mean ALT
now points to the start of the newly allocated data, ready for use. When shrinking the stack, that will mean ALT
still points to valid memory.
I very frequently have to do:
#emit STACK 20
#emit STACK 0
Just to adjust the stack then get the new pointer. I've never once needed the old pointer (and on the rare case I did, could just swap those over). I know #emit
isn't used, but I think it would benefit the compiler as well to already have the new memory locations.
Current versions of pawnscript (through 4.0-4733) do not build cleanly using
CMake on OS X due to a number of issues:
- libraries built as part of AMX aren't using modern visibility attributes, and depend on the -K argument to strip, which is not compatible with the way the OS X toolchain handles exports.
- neither amx nor the compiler are 64-bit clean, and OS X defaults to building 64-bit binaries
- there are many missing ifdef __APPLE__ cases in the code
- directory separator is / not :
- assorted other minor issues (stime vs. settimeofday, __T, etc.)
Attached is a port to 4733 of a patch that worked in light testing on 4548.
Original issue reported on code.google.com by [email protected]
on 12 Aug 2012 at 5:42
Attachments:
I tried building the compiler using Alpine and Ubuntu linux. Both output the following warning:
/home/pawn/compiler/sc1.c: In function 'posix_spawnl':
/home/pawn/compiler/sc1.c:460:5: warning: implicit declaration of function 'waitpid' [-Wimplicit-function-declaration]
460 | waitpid(pid,&stat,0);
| ^~~~~~~
If one of the strings is empty, strcmp
returns the difference of their lengths, but the documentation (String_Manipulation.pdf) says that strcmp
can only return 1, 0 or -1.
Example:
#include <console>
#include <string>
main()
{
static const test_strings[4]{12} = ["", "123", "abc", "hello world"];
for (new i = 0; i < sizeof(test_strings); ++i)
for (new j = 0; j < sizeof(test_strings); ++j)
printf("strcmp(\"%s\" \"%s\"): %d\n",
test_strings[i], test_strings[j],
strcmp(test_strings[i], test_strings[j]));
}
Output:
strcmp("" ""): 0
strcmp("" "123"): -3
strcmp("" "abc"): -3
strcmp("" "hello world"): -11
strcmp("123" ""): 3
strcmp("123" "123"): 0
strcmp("123" "abc"): -1
strcmp("123" "hello world"): -1
strcmp("abc" ""): 3
strcmp("abc" "123"): 1
strcmp("abc" "abc"): 0
strcmp("abc" "hello world"): -1
strcmp("hello world" ""): 11
strcmp("hello world" "123"): 1
strcmp("hello world" "abc"): 1
strcmp("hello world" "hello world"): 0
Is this a bug or just an undocumented feature?
Is there any such instruction to do so?
I have give it a try
first, alloca.h
is reported to be missed in amx.h
, so I leave #include <malloc.h>
in amx.h
.
then,
$ make
[ 3%] Built target pawndisasm
[ 32%] Built target pawncc
[ 37%] Built target stategraph
[ 38%] Linking C shared library ../amxString.dll
gcc.exe: error: /export:amx_StringInit: No such file or directory
gcc.exe: error: /export:amx_StringCleanup: No such file or directory
make[2]: *** [amx/CMakeFiles/amxString.dir/build.make:115: amxString.dll] Error 1
make[1]: *** [CMakeFiles/Makefile2:218: amx/CMakeFiles/amxString.dir/all] Error 2
make: *** [Makefile:84: all] Error 2
Reported by Alex Cole on the forum.
The following code generates invalid code on Pawn 3 and makes the compiler drop into an assertion on Pawn 4.
new gVar;
stock SomeFunction()
{
#if defined main
gVar = (gVar ? 0 : 1);
#endif
return 0;
}
main()
{
return SomeFunction() ? 0 : 1;
}
The cause turns out to be that the assignment of gVar is skipped on the first pass that the compiler makes through the code (because "main" is undefined at that point), but it is included on the second pass (because "main" has been seen since). It is usually not a problem when the second pass sees different code than the first pass, but there are exceptions, and this is one of them.
The suggested change is that the first pass is repeated in a case like the above, so that on the next iteration of that "first" pass, the compiler sees exactly the same code path as what the second pass goes through.
Not really a bug, but a feature request: would like an option like the MS
compilers - /nologo - to hide the initial banner that displays during a
compile.
Original issue reported on code.google.com by [email protected]
on 2 Jan 2007 at 4:50
Since commit 57f7de9
, the #emit instruction has been removed from Pawn. Is there any equivalent to insert AMX Assembly instructions directly in compile-time?
Thanks.
Using Pawncc 4.0.4733 compiling attached script gives following assertion
output:
Assertion Failed: cval!=NULL && cval->next!=NULL, function hier1, file sc3.c,
line 1870.
ABNORMAL TERMINATION
Original issue reported on code.google.com by [email protected]
on 7 Dec 2012 at 10:26
Attachments:
In Pawn 3.2 it was possible to "hook" a function using a compiler bug. Preprocessor handled "#if defined" statements in a second-round of preprocessing, read more here.
Now it's not working, because the bug was fixed. Please, return that behaviour, because ALS hooking is a critical functionality.
when you build a pawn script with -C64 and set PAWN_CELL_SIZE to 64 the program crashes. This worked fine before the most recent patch.
Recently I encountered a bug with 2-dimensional array initialization. The compiler seems to insert extra cells before the array contents.
Here's a reproduction:
#include <console>
main()
{
static const my_array[3][3] =
[
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
];
for (new i = 0; i < sizeof(my_array); ++i)
for (new j = 0; j < sizeof(my_array[]); ++j)
printf("my_array[%d][%d] = %d\n", i, j, my_array[i][j]);
}
Normally the output should be:
my_array[0][0] = 1
my_array[0][1] = 2
my_array[0][2] = 3
my_array[1][0] = 4
my_array[1][1] = 5
my_array[1][2] = 6
my_array[2][0] = 7
my_array[2][1] = 8
my_array[2][2] = 9
But instead I got this:
my_array[0][0] = 0
my_array[0][1] = 1
my_array[0][2] = 2
my_array[1][0] = 3
my_array[1][1] = 4
my_array[1][2] = 5
my_array[2][0] = 6
my_array[2][1] = 7
my_array[2][2] = 8
I decided to disassemble the .amx with pawndisasm
, but before doing that I added the __start
and the __end
arrays so it would be easier to track the contents of my_array
in disassembler output.
static const __start{} = "___";
static const my_array[3][3] =
[
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
];
static const __end{} = "___";
#pragma unused __start, __end
And here's what the data section contains:
;DATA
00000000 5f5f5f00 0000000c 00000014 0000001c ___
00000010 00000000 00000001 00000002 00000003
00000020 00000004 00000005 00000006 00000007
00000030 00000008 00000009 5f5f5f00 6d795f61 ___ my_a
00000040 72726179 5b25645d 5b25645d 203d2025 rray[%d][%d] = %
00000050 640a0000 d
5f5f5f00
is obviously the __start
array and 00000001 00000002 ... 00000009
are the contents of my_array
, but there are four cells between those two arrays: 0000000c 00000014 0000001c 00000000
- where do they come from?
This bug exists in both 4.0.4733 and the latest development version.
Pawn's build system doesn't use FindCurses from cmake, and instead attempts to find ncurses itself. This leads to an error if ncurses has been built with a separate terminfo library (libtinfo). The FindCurses module from cmake copes with this by checking for a specific function to determine whether libtinfo has been split into a separate library or not (the cbreak
function), and if so sets the libraries to link against appropriately.
Pawn doesn't make use of cbreak
, but does use nodelay
, however the cbreak
check should still be sufficient.
Ideally this would be fixed by making use of cmake's pre-packaged FindCurses module, rather than custom implementing similar functionality. Failing that, the curses finding cmake code should take into account the potential need to link against libtinfo.
If you have any further question, please just let me know. For more information please see:
Originally was reported and discussed here and here.
main()
{
printf(true ? f() : "Hello World!\n")
}
f() {
new arr[256];
return arr;
}
Assertion:
pawn/compiler/sc3.c:1296: hier13: Assertion `sc_status!=statWRITE || heap1==heap2' failed.
Online proof.
If I place the definition before call point then there is no assertion: online proof.
f() {
new arr[256];
return arr;
}
main()
{
printf(true ? (true ? f() : "Hello World!\n") : "Something")
}
Assertion:
pawn/compiler/sc3.c:1296: hier13: Assertion `sc_status!=statWRITE || heap1==heap2' failed.
Online proof. true ? (true ? "Hello World!\n" : f()) : "Something"
and true ? (true ? "Something" : "Hello World!\n") : f()
produce an assertion too. Cases where there are two f()
also produce an assertion. Only the case where there are three f()
have no assertions: proof.
I am having an issue on 4.0.4733 with properly initializing multi-dimensional arrays. The following example will demonstrate the problem.
main()
{
new dropDownStrings[][]{} = [ ["Never","Niemals"] , ["Warning_Only","Nur Warnung"] ,["Reject_Only","Nur_Toleranz"] , ["Warning_or_Reject","Warnung_oder_Toleranz"] ] ;
for(new a = 0; a < 4; a++)
for(new b = 0; b < 2; b++)
{
print dropDownStrings[a][b];
print "\n";
}
}
I would expect the output:
Never
Niemals
Warning_Only
Nur Warnung
Reject_Only
Nur_Toleranz
Warning_or_Reject
Warnung_oder_Toleranz
but instead I get this:
Never
Niemals
Warning_Only
Only
Nur Warnung
ung
Nur_Toleranz
It looks like the compiler sees the first entry is (in my case) 2 cells long and makes some assumptions about the rest of the initializer. Making the first string very long fixes this. Another quick workaround was to explicitly state a length of the last dimension of the array:
dropDownStrings[][]{25}
Is this a bug or am I dong something wrong?
I originally reported this vulnerability back in May through E-Mail because I didn't want to make the information about it publicly available, but apparently no actions were taken to fix it. And since there are other unfixed vulnerabilities some of which are known for years (see issue 26), I guess now there's no harm in reporting it here.
So...
Since Pawn 4.0 there are new PUSHR* opcodes that push a physical address of a cell instead of a "virtual" address in the VM as it was done previously with the PUSH* opcodes.
PUSHR* opcodes are used to pass variadic function arguments, pass-by-reference arguments and arrays. For all of the other cases Pawn Compiler still generates PUSH* opcodes.
But there's a way to trick the compiler to make it use PUSHR* opcodes where it should actually use PUSH* and vice versa.
// native valstr(dest[], value, bool:pack=true);
native GetArrPhysAddrAsStr(dest[], const value[], bool:pack=true) = valstr;
In this example I made an "alternate" definition for valstr
. Note that the value
argument is an array, not a single cell, so instead of the value of a given cell the array address is passed to valstr
and the function returns that address as a string.
Retrieving the address of a single variable is possible as well:
native GetVarPhysAddrAsStr(dest[], const &value, bool:pack=true) = valstr;
And since addresses in Pawn 4.0 are passed with the PUSHR* opcodes, they're physical, not virtual.
After retrieving the address as a string it can be converted back to an integer:
native GetArrPhysAddrAsStr(dest[], const value[], bool:pack=true) = valstr;
stock GetArrPhysAddr(const arr[])
{
// min value for a 64-bit cell: −9223372036854775808 (20 characters)
new str{21};
GetArrPhysAddrAsStr(str, arr, true);
return strval(str);
}
It's also possible to utilize memcpy
for read/write operations:
#include <console>
#include <string>
native GetDataByPhysAddr(dest[], src_addr, index=0, numbytes, maxlength=sizeof dest) = memcpy;
native SetDataByPhysAddr(dest_addr, const src[], index=0, numbytes, maxlength) = memcpy;
native GetArrPhysAddrAsStr(dest[], const value[], bool:pack=true) = valstr;
stock GetArrPhysAddr(const arr[])
{
new str{21};
GetArrPhysAddrAsStr(str, arr, true);
return strval(str);
}
main()
{
static const test_string{128} = "Hello";
printf("Before: %s\n", test_string);
static const new_string{} = "Hell no";
new test_string_phys_addr = GetArrPhysAddr(test_string);
SetDataByPhysAddr(
test_string_phys_addr, new_string,
0, sizeof(new_string) * (cellbits / charbits), 16
);
printf("After: %s\n", test_string);
}
Output:
Before: Hello
After: Hell no
That way it's even possible to write outside of the script memory and probably execute arbitrary bytecode by modifying the contents of the code section.
Removing the syntax for "alternate" function prototypes (like GetDataByPhysAddr
, SetDataByPhysAddr
and GetArrPhysAddrAsStr
in the examples above) won't solve the problem because it still would be possible to do something like this:
#pragma library String // instead of including string.inc
native memcpy(dest_phys_addr, const src[], index=0, numbytes, maxlength);
#define SetDataByPhysAddr memcpy
Also in this function prototype
native SetDataByPhysAddr(dest_addr, const src[], index=0, numbytes, maxlength) = memcpy;
note that the dest_addr
argument is a single cell so the write address will be passed with one of the PUSH* opcodes, not PUSHR*. This means that adding address checks to all of the PUSHR* opcodes is pointless as well.
The only good fix I can think of is completely removing all of the PUSHR* opcodes from the instruction set, but that would require bringing back the amx_GetAddr function and probably some other actions to take.
These vulnerabilities are rather hard to exploit since the #emit directive was removed long ago, but it's still possible to modify a compiled script with a hex editor or make a some kind of AMX assembler by reusing parts of code from the Pawn compiler.
Also I don't take credit for discovering all of the abovementioned vulnerabilities. The LREF.S.*/SREF.S one is already long known in the SA-MP community and used in several works (e.g. in the YSI includes for reading misc. AMX info) and the other ones were relatively easy to find.
What steps will reproduce the problem?
1. Include amxexec_arm7.s in a RealView project
2. Compile
3. See errors below (PUSH and POP already known by armasm)
What is the expected output? What do you see instead?
Warning : A1480: Macro cannot have same name as a directive or instruction
amxexec_arm7.s line 255
Warning : A1480: Macro cannot have same name as a directive or instruction
amxexec_arm7.s line 260
Error : A1215: Bad register list symbol
amxexec_arm7.s line 586
Error : A1215: Bad register list symbol
amxexec_arm7.s line 590
Error : A1215: Bad register list symbol
amxexec_arm7.s line 595
Error : A1215: Bad register list symbol
amxexec_arm7.s line 601
Error : A1215: Bad register list symbol
amxexec_arm7.s line 607
Error : A1215: Bad register list symbol
amxexec_arm7.s line 611
Error : A1215: Bad register list symbol
amxexec_arm7.s line 615
Error : A1215: Bad register list symbol
amxexec_arm7.s line 635
Error : A1215: Bad register list symbol
amxexec_arm7.s line 641
Error : A1215: Bad register list symbol
amxexec_arm7.s line 642
Error : A1215: Bad register list symbol
amxexec_arm7.s line 652
Error : A1215: Bad register list symbol
amxexec_arm7.s line 653
Error : A1215: Bad register list symbol
amxexec_arm7.s line 670
Error : A1215: Bad register list symbol
amxexec_arm7.s line 675
Error : A1215: Bad register list symbol
amxexec_arm7.s line 1188
Error : A1215: Bad register list symbol
amxexec_arm7.s line 1244
Error : A1215: Bad register list symbol
amxexec_arm7.s line 1315
Error : A1215: Bad register list symbol
amxexec_arm7.s line 1348
Error : A1215: Bad register list symbol
amxexec_arm7.s line 1353
Error : A1215: Bad register list symbol
amxexec_arm7.s line 1358
Error : A1215: Bad register list symbol
amxexec_arm7.s line 1363
Error : A1215: Bad register list symbol
amxexec_arm7.s line 1366
Error : A1215: Bad register list symbol
amxexec_arm7.s line 1372
Error : A1215: Bad register list symbol
amxexec_arm7.s line 1377
Error : A1215: Bad register list symbol
amxexec_arm7.s line 1382
Error : A1215: Bad register list symbol
amxexec_arm7.s line 1387
Error : A1215: Bad register list symbol
amxexec_arm7.s line 1390
Error : A1215: Bad register list symbol
amxexec_arm7.s line 1395
Error : A1215: Bad register list symbol
amxexec_arm7.s line 1399
Error : A1215: Bad register list symbol
amxexec_arm7.s line 1403
Error : A1215: Bad register list symbol
amxexec_arm7.s line 1407
Error : A1215: Bad register list symbol
amxexec_arm7.s line 1409
Error : A1215: Bad register list symbol
amxexec_arm7.s line 1416
Error : A1215: Bad register list symbol
amxexec_arm7.s line 1422
Error : A1215: Bad register list symbol
amxexec_arm7.s line 1428
Error : A1215: Bad register list symbol
amxexec_arm7.s line 1434
Error : A1215: Bad register list symbol
amxexec_arm7.s line 1438
armasm : 37 Errors, 2 Warnings
Error : armasm Compile exit status = 2
What version of the product are you using? On what operating system?
Windows XP compiler for ARM7TDMI
Please provide any additional information below.
I was able to change all occurances of "PUSH" to "PUSHON" and "POP" to
"POPOFF" and then it compiled ok.
Original issue reported on code.google.com by [email protected]
on 29 Dec 2006 at 6:39
Version of compiler is 4.0.5749.
OS Windows 10, compiler is MS Visual C++ 2019.
Code will be looping infinitely, slowly growing in memory,
while (!matchtoken('}')){ /* repeat until compound statement is closed */
file sc1, line 5900
Couse is, file fib1.p is UTF8 with UNIX LF line termination, after changing it to CR LF - compiled just fine.
Another fix is to add semicolon at the and of the string
print "Enter a value: "
in fib.p
I wasnt able to identify what kind of fix can be applied to pawn complier itself.
Hello!
I try to use amxexec_thumb2_gas.s with AMX_TOKENTHREADING option
In macro NEXT your switch to next instruction processing by load pc
ldr pc, [r14, r11, LSL #2]
Value extracted from amx_opcodelist table:
.word .OP_NOP
.word .OP_LOAD_PRI
.word .OP_LOAD_ALT
But values in this table is even, so load this value in PC switch processor in ARM mode instead of Thumb
Solution:
.word .OP_NOP + 1
.word .OP_LOAD_PRI + 1
.word .OP_LOAD_ALT + 1
Using Pawncc 4.0.4733 compiling attached script gives following warning output,
although tag for fields .key and .value are correctly set:
array.p(5) : warning 213: tag mismatch
array.p(5) : warning 213: tag mismatch
array.p(6) : warning 213: tag mismatch
array.p(6) : warning 213: tag mismatch
array.p(7) : warning 213: tag mismatch
array.p(7) : warning 213: tag mismatch
array.p(8) : warning 213: tag mismatch
array.p(8) : warning 213: tag mismatch
array.p(9) : warning 213: tag mismatch
array.p(9) : warning 213: tag mismatch
Original issue reported on code.google.com by [email protected]
on 17 Jul 2012 at 8:22
Attachments:
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.