mirror of
git://repo.or.cz/tinycc.git
synced 2026-06-17 15:44:18 +08:00
arm64: reject invalid asm and clean run argv
This commit is contained in:
parent
42d85ec622
commit
8b5ab1bb01
51
arm64-asm.c
51
arm64-asm.c
@ -825,6 +825,15 @@ static int is_valid_movw_imm(int64_t val)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int is_valid_movw_shift(int shift, int is_64bit)
|
||||
{
|
||||
if (shift < 0 || (shift & 15))
|
||||
return 0;
|
||||
if (shift > (is_64bit ? 48 : 16))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int arm64_memory_is_base_only(const SValue *sv)
|
||||
{
|
||||
int r;
|
||||
@ -1278,8 +1287,7 @@ static void asm_data_proc(TCCState *s1, int token)
|
||||
opcode = ARM64_EOR_REG;
|
||||
break;
|
||||
case TOK_ASM_mul:
|
||||
case TOK_ASM_muls:
|
||||
opcode = token == TOK_ASM_mul ? ARM64_MUL_REG : ARM64_MULS_REG;
|
||||
opcode = ARM64_MUL_REG;
|
||||
break;
|
||||
default:
|
||||
tcc_error("unsupported data processing instruction");
|
||||
@ -1333,15 +1341,16 @@ static void asm_data_proc(TCCState *s1, int token)
|
||||
return;
|
||||
}
|
||||
rm = op3.reg;
|
||||
if (is_64bit != !!(op2.reg_type & REG_X) || is_64bit != !!(op3.reg_type & REG_X))
|
||||
if (is_64bit != !!(op2.reg_type & REG_X) || is_64bit != !!(op3.reg_type & REG_X)) {
|
||||
tcc_error("mismatched register widths");
|
||||
return;
|
||||
}
|
||||
gen_dp_reg(opcode, rd, rn, rm, is_64bit);
|
||||
}
|
||||
} else if (op2.type & OP_IM) {
|
||||
tcc_error("missing source register for immediate form");
|
||||
} else {
|
||||
is_64bit = (op1.reg_type & REG_X);
|
||||
gen_mov_reg(rd, rn, is_64bit);
|
||||
tcc_error("missing third operand");
|
||||
}
|
||||
}
|
||||
|
||||
@ -1664,18 +1673,37 @@ static void asm_move_wide(TCCState *s1, int token)
|
||||
if (tok == ',') next();
|
||||
parse_operand(s1, &op2);
|
||||
|
||||
if (!(op1.type & OP_REG)) {
|
||||
tcc_error("expected register in first operand");
|
||||
return;
|
||||
}
|
||||
if (!(op2.type & OP_IM) || op2.e.sym) {
|
||||
tcc_error("expected immediate in second operand");
|
||||
return;
|
||||
}
|
||||
|
||||
rd = op1.reg;
|
||||
is_64bit = (op1.reg_type & REG_X);
|
||||
imm = op2.e.v & 0xFFFF;
|
||||
if ((uint64_t)op2.e.v > 0xFFFF) {
|
||||
tcc_error("move wide immediate out of range");
|
||||
return;
|
||||
}
|
||||
imm = op2.e.v;
|
||||
|
||||
if (tok == ',') {
|
||||
next();
|
||||
if (tok == TOK_ASM_lsl) {
|
||||
next();
|
||||
if (tok == '#') next();
|
||||
asm_expr(s1, &op2.e);
|
||||
shift = (int)op2.e.v / 16;
|
||||
if (tok != TOK_ASM_lsl) {
|
||||
tcc_error("move wide shift must use lsl");
|
||||
return;
|
||||
}
|
||||
next();
|
||||
if (tok == '#') next();
|
||||
asm_expr(s1, &op2.e);
|
||||
if (op2.e.sym || !is_valid_movw_shift((int)op2.e.v, is_64bit)) {
|
||||
tcc_error("move wide shift out of range");
|
||||
return;
|
||||
}
|
||||
shift = (int)op2.e.v / 16;
|
||||
}
|
||||
|
||||
switch (token) {
|
||||
@ -1706,7 +1734,6 @@ ST_FUNC void asm_opcode(TCCState *s1, int opcode)
|
||||
case TOK_ASM_orr:
|
||||
case TOK_ASM_eor:
|
||||
case TOK_ASM_mul:
|
||||
case TOK_ASM_muls:
|
||||
asm_data_proc(s1, opcode);
|
||||
break;
|
||||
|
||||
|
||||
@ -297,7 +297,6 @@
|
||||
|
||||
/* Multiply/divide */
|
||||
DEF_ASM(mul)
|
||||
DEF_ASM(muls)
|
||||
DEF_ASM(madd)
|
||||
DEF_ASM(msub)
|
||||
DEF_ASM(smaddl)
|
||||
@ -577,7 +576,6 @@
|
||||
#define ARM64_ORR_REG 0x2A000000U
|
||||
#define ARM64_EOR_REG 0x4A000000U
|
||||
#define ARM64_MUL_REG 0x1B000000U /* Base opcode, Rm/Rn/Rd must be filled in */
|
||||
#define ARM64_MULS_REG 0x3B000000U /* Base opcode, Rm/Rn/Rd must be filled in */
|
||||
|
||||
/* Move wide immediate */
|
||||
#define ARM64_MOVZ 0x52800000U
|
||||
|
||||
15
tccrun.c
15
tccrun.c
@ -266,6 +266,17 @@ static void rt_flush_target_io(void)
|
||||
if (fn)
|
||||
fn(NULL);
|
||||
}
|
||||
|
||||
static void rt_cleanup_run_targv(TCCState *s)
|
||||
{
|
||||
void (*cleanup)(void);
|
||||
|
||||
if (!s)
|
||||
return;
|
||||
cleanup = (void (*)(void))tcc_get_symbol(s, "__tcc_cleanup_run_targv");
|
||||
if (cleanup)
|
||||
cleanup();
|
||||
}
|
||||
#endif
|
||||
|
||||
/* launch the compiled program with the given arguments */
|
||||
@ -699,6 +710,9 @@ static void rt_exit(rt_frame *f, int code)
|
||||
((void (*)(void))p)();
|
||||
}
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
rt_cleanup_run_targv(s);
|
||||
#endif
|
||||
#if defined(_WIN64) && defined(__aarch64__) && !defined(CONFIG_TCC_BACKTRACE_ONLY)
|
||||
rt_restore_context_from_jmpbuf(s->run_jb, code);
|
||||
return;
|
||||
@ -1577,6 +1591,7 @@ static long __stdcall cpu_exception_handler(EXCEPTION_POINTERS *ex_info)
|
||||
((void (*)(void))p)();
|
||||
}
|
||||
#endif
|
||||
rt_cleanup_run_targv(s);
|
||||
rt_restore_context_from_jmpbuf(s->run_jb, 255);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -43,6 +43,34 @@ int main(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#elif defined test_missing_third_operand
|
||||
int main(void)
|
||||
{
|
||||
__asm__("add x0, x1");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#elif defined test_movz_imm_range
|
||||
int main(void)
|
||||
{
|
||||
__asm__("movz x0, #0x10000");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#elif defined test_movz_shift_range
|
||||
int main(void)
|
||||
{
|
||||
__asm__("movz x0, #1, lsl #8");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#elif defined test_invalid_muls
|
||||
int main(void)
|
||||
{
|
||||
__asm__("muls x0, x1, x2");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#elif defined test_extended_inline_asm
|
||||
int main(void)
|
||||
{
|
||||
|
||||
@ -13,8 +13,20 @@
|
||||
[test_invalid_barrier_option]
|
||||
139_arm64_errors.c:42: error: invalid operand 'xyz'
|
||||
|
||||
[test_missing_third_operand]
|
||||
139_arm64_errors.c:48: error: missing third operand
|
||||
|
||||
[test_movz_imm_range]
|
||||
139_arm64_errors.c:55: error: move wide immediate out of range
|
||||
|
||||
[test_movz_shift_range]
|
||||
139_arm64_errors.c:62: error: move wide shift out of range
|
||||
|
||||
[test_invalid_muls]
|
||||
139_arm64_errors.c:70: error: ARM64 instruction 'muls' not implemented
|
||||
|
||||
[test_extended_inline_asm]
|
||||
139_arm64_errors.c:51: error: invalid reference in constraint 1 ('2')
|
||||
139_arm64_errors.c:79: error: invalid reference in constraint 1 ('2')
|
||||
|
||||
[test_extended_inline_clobber]
|
||||
139_arm64_errors.c:59: error: invalid clobber register 'bogus'
|
||||
139_arm64_errors.c:87: error: invalid clobber register 'bogus'
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
#include <tchar.h>
|
||||
|
||||
#include <windows.h>
|
||||
#include <excpt.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@ -38,6 +39,7 @@ int __cdecl __tgetmainargs(int *pargc, _TCHAR ***pargv, _TCHAR ***penv, int glob
|
||||
int __cdecl __getmainargs(int *pargc, char ***pargv, char ***penv, int globb, _startupinfo*);
|
||||
int __cdecl __wgetmainargs(int *pargc, wchar_t ***pargv, wchar_t ***penv, int globb, _startupinfo*);
|
||||
int __cdecl get_tenviron(_TCHAR ***penv);
|
||||
int __cdecl _XcptFilter(unsigned long, struct _EXCEPTION_POINTERS *);
|
||||
void __cdecl __set_app_type(int apptype);
|
||||
unsigned int __cdecl _controlfp(unsigned int new_value, unsigned int mask);
|
||||
extern int _tmain(int argc, _TCHAR * argv[], _TCHAR * env[]);
|
||||
@ -120,6 +122,7 @@ typedef struct run_targv_state {
|
||||
_TCHAR **saved_argv;
|
||||
_TCHAR **run_argv;
|
||||
int active;
|
||||
struct run_targv_state *prev;
|
||||
} run_targv_state;
|
||||
|
||||
static __declspec(thread) run_targv_state *run_targv_tls;
|
||||
@ -457,11 +460,8 @@ fail:
|
||||
}
|
||||
#endif
|
||||
|
||||
static void restore_run_targv(int ret, void *opaque)
|
||||
static void restore_run_targv(run_targv_state *state)
|
||||
{
|
||||
run_targv_state *state = (run_targv_state *)opaque;
|
||||
|
||||
(void)ret;
|
||||
if (!state || !state->active)
|
||||
return;
|
||||
__argc = state->saved_argc;
|
||||
@ -470,12 +470,12 @@ static void restore_run_targv(int ret, void *opaque)
|
||||
state->run_argv = NULL;
|
||||
state->active = 0;
|
||||
if (run_targv_tls == state)
|
||||
run_targv_tls = NULL;
|
||||
run_targv_tls = state->prev;
|
||||
}
|
||||
|
||||
static void restore_run_targv_atexit(void)
|
||||
void __tcc_cleanup_run_targv(void)
|
||||
{
|
||||
restore_run_targv(0, run_targv_tls);
|
||||
restore_run_targv(run_targv_tls);
|
||||
}
|
||||
|
||||
int _runtmain(int argc, /* as tcc passed in */ char **argv)
|
||||
@ -483,7 +483,7 @@ int _runtmain(int argc, /* as tcc passed in */ char **argv)
|
||||
int ret;
|
||||
int run_argc = argc;
|
||||
_TCHAR **env = run_get_tenviron();
|
||||
run_targv_state argv_state = { __argc, __targv, NULL, 0 };
|
||||
run_targv_state argv_state = { __argc, __targv, NULL, 0, NULL };
|
||||
wchar_t **run_wargv = NULL;
|
||||
|
||||
run_wargv = build_run_wargv(&run_argc);
|
||||
@ -501,9 +501,8 @@ int _runtmain(int argc, /* as tcc passed in */ char **argv)
|
||||
}
|
||||
if (!argv_state.run_argv)
|
||||
return 1;
|
||||
argv_state.prev = run_targv_tls;
|
||||
run_targv_tls = &argv_state;
|
||||
if (atexit(restore_run_targv_atexit))
|
||||
goto fail;
|
||||
__argc = run_argc;
|
||||
__targv = argv_state.run_argv;
|
||||
argv_state.active = 1;
|
||||
@ -516,11 +515,8 @@ int _runtmain(int argc, /* as tcc passed in */ char **argv)
|
||||
run_dtors();
|
||||
if (__run_on_exit)
|
||||
__run_on_exit(ret);
|
||||
__tcc_cleanup_run_targv();
|
||||
return ret;
|
||||
fail:
|
||||
run_targv_tls = NULL;
|
||||
free_run_targv(argv_state.run_argv);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// =============================================
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
#include <tchar.h>
|
||||
|
||||
#include <windows.h>
|
||||
#include <excpt.h>
|
||||
#include <stdlib.h>
|
||||
#define __UNKNOWN_APP 0
|
||||
#define __CONSOLE_APP 1
|
||||
@ -29,10 +30,36 @@ int __cdecl __tgetmainargs(int *pargc, _TCHAR ***pargv, _TCHAR ***penv, int glob
|
||||
int __cdecl __getmainargs(int *pargc, char ***pargv, char ***penv, int globb, _startupinfo*);
|
||||
int __cdecl __wgetmainargs(int *pargc, wchar_t ***pargv, wchar_t ***penv, int globb, _startupinfo*);
|
||||
int __cdecl get_tenviron(_TCHAR ***penv);
|
||||
int __cdecl _XcptFilter(unsigned long, struct _EXCEPTION_POINTERS *);
|
||||
__attribute__((weak)) int __cdecl __rt_get_run_argstart(void);
|
||||
|
||||
#include "crtinit.c"
|
||||
|
||||
typedef struct run_targv_state {
|
||||
int saved_argc;
|
||||
_TCHAR **saved_argv;
|
||||
int active;
|
||||
struct run_targv_state *prev;
|
||||
} run_targv_state;
|
||||
|
||||
static __declspec(thread) run_targv_state *run_targv_tls;
|
||||
|
||||
static void restore_run_targv(run_targv_state *state)
|
||||
{
|
||||
if (!state || !state->active)
|
||||
return;
|
||||
__argc = state->saved_argc;
|
||||
__targv = state->saved_argv;
|
||||
state->active = 0;
|
||||
if (run_targv_tls == state)
|
||||
run_targv_tls = state->prev;
|
||||
}
|
||||
|
||||
void __tcc_cleanup_run_targv(void)
|
||||
{
|
||||
restore_run_targv(run_targv_tls);
|
||||
}
|
||||
|
||||
static int select_run_arg_start_t(int base, const _TCHAR *arg0, int full_argc, _TCHAR **full_argv)
|
||||
{
|
||||
int i;
|
||||
@ -121,8 +148,7 @@ int _twinstart(void)
|
||||
|
||||
int _runtwinmain(int argc, /* as tcc passed in */ char **argv)
|
||||
{
|
||||
int saved_argc = __argc;
|
||||
_TCHAR **saved_argv = __targv;
|
||||
run_targv_state argv_state = { __argc, __targv, 0, NULL };
|
||||
int ret;
|
||||
int run_arg_start = -1;
|
||||
#ifdef UNICODE
|
||||
@ -155,8 +181,10 @@ int _runtwinmain(int argc, /* as tcc passed in */ char **argv)
|
||||
__argc = argc, __targv = argv;
|
||||
}
|
||||
#endif
|
||||
argv_state.prev = run_targv_tls;
|
||||
run_targv_tls = &argv_state;
|
||||
argv_state.active = 1;
|
||||
ret = go_winmain(__argc > 1 ? __targv[1] : NULL);
|
||||
__argc = saved_argc;
|
||||
__targv = saved_argv;
|
||||
__tcc_cleanup_run_targv();
|
||||
return ret;
|
||||
}
|
||||
|
||||
131
win32/test_run_arg_cleanup.c
Normal file
131
win32/test_run_arg_cleanup.c
Normal file
@ -0,0 +1,131 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <windows.h>
|
||||
|
||||
#include "..\tcc.h"
|
||||
|
||||
typedef struct libtcc_api {
|
||||
TCCState *(*tcc_new)(void);
|
||||
void (*tcc_delete)(TCCState *s);
|
||||
int (*tcc_set_options)(TCCState *s, const char *str);
|
||||
void (*tcc_set_lib_path)(TCCState *s, const char *path);
|
||||
void (*tcc_set_error_func)(TCCState *s, void *opaque, TCCErrorFunc *error_func);
|
||||
int (*tcc_set_output_type)(TCCState *s, int output_type);
|
||||
int (*tcc_add_include_path)(TCCState *s, const char *pathname);
|
||||
int (*tcc_add_library_path)(TCCState *s, const char *pathname);
|
||||
int (*tcc_compile_string)(TCCState *s, const char *buf);
|
||||
int (*tcc_run)(TCCState *s, int argc, char **argv);
|
||||
} libtcc_api;
|
||||
|
||||
static const char crash_program[] =
|
||||
"int main(void)\n"
|
||||
"{\n"
|
||||
" *(volatile int *)0 = 1;\n"
|
||||
" return 0;\n"
|
||||
"}\n";
|
||||
|
||||
static const char argv_program[] =
|
||||
"#include <string.h>\n"
|
||||
"int main(int argc, char **argv)\n"
|
||||
"{\n"
|
||||
" if (argc != 2)\n"
|
||||
" return 10 + argc;\n"
|
||||
" if (strcmp(argv[0], \"beta\") || strcmp(argv[1], \"gamma\"))\n"
|
||||
" return 20;\n"
|
||||
" return 0;\n"
|
||||
"}\n";
|
||||
|
||||
static void handle_error(void *opaque, const char *msg)
|
||||
{
|
||||
fprintf((FILE *)opaque, "%s\n", msg);
|
||||
}
|
||||
|
||||
static FARPROC load_symbol(HMODULE dll, const char *name)
|
||||
{
|
||||
FARPROC proc = GetProcAddress(dll, name);
|
||||
|
||||
if (!proc) {
|
||||
fprintf(stderr, "missing libtcc symbol: %s\n", name);
|
||||
exit(1);
|
||||
}
|
||||
return proc;
|
||||
}
|
||||
|
||||
static int run_program(const libtcc_api *api, const char *source, int run_arg_start)
|
||||
{
|
||||
TCCState *s;
|
||||
char *argv[] = { "unused0", "unused1", "unused2", NULL };
|
||||
int ret;
|
||||
|
||||
s = api->tcc_new();
|
||||
if (!s) {
|
||||
fprintf(stderr, "tcc_new failed\n");
|
||||
return 100;
|
||||
}
|
||||
|
||||
api->tcc_set_error_func(s, stderr, handle_error);
|
||||
api->tcc_set_options(s, "-bt");
|
||||
api->tcc_set_lib_path(s, ".");
|
||||
api->tcc_add_include_path(s, ".\\include");
|
||||
api->tcc_add_include_path(s, ".\\win32\\include");
|
||||
api->tcc_add_library_path(s, ".\\win32\\lib");
|
||||
s->run_arg_start = run_arg_start;
|
||||
|
||||
ret = api->tcc_set_output_type(s, TCC_OUTPUT_MEMORY);
|
||||
if (!ret)
|
||||
ret = api->tcc_compile_string(s, source);
|
||||
if (!ret)
|
||||
ret = api->tcc_run(s, 3, argv);
|
||||
|
||||
api->tcc_delete(s);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
HMODULE dll;
|
||||
libtcc_api api;
|
||||
int ret;
|
||||
|
||||
if (argc < 4) {
|
||||
fprintf(stderr, "usage: %s alpha beta gamma\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
dll = LoadLibraryA("libtcc.dll");
|
||||
if (!dll) {
|
||||
fprintf(stderr, "failed to load libtcc.dll\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
memset(&api, 0, sizeof(api));
|
||||
api.tcc_new = (void *)load_symbol(dll, "tcc_new");
|
||||
api.tcc_delete = (void *)load_symbol(dll, "tcc_delete");
|
||||
api.tcc_set_options = (void *)load_symbol(dll, "tcc_set_options");
|
||||
api.tcc_set_lib_path = (void *)load_symbol(dll, "tcc_set_lib_path");
|
||||
api.tcc_set_error_func = (void *)load_symbol(dll, "tcc_set_error_func");
|
||||
api.tcc_set_output_type = (void *)load_symbol(dll, "tcc_set_output_type");
|
||||
api.tcc_add_include_path = (void *)load_symbol(dll, "tcc_add_include_path");
|
||||
api.tcc_add_library_path = (void *)load_symbol(dll, "tcc_add_library_path");
|
||||
api.tcc_compile_string = (void *)load_symbol(dll, "tcc_compile_string");
|
||||
api.tcc_run = (void *)load_symbol(dll, "tcc_run");
|
||||
|
||||
ret = run_program(&api, crash_program, 1);
|
||||
if (ret != 255) {
|
||||
fprintf(stderr, "crash program returned %d instead of 255\n", ret);
|
||||
FreeLibrary(dll);
|
||||
return 2;
|
||||
}
|
||||
|
||||
ret = run_program(&api, argv_program, 2);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "argv cleanup test returned %d\n", ret);
|
||||
FreeLibrary(dll);
|
||||
return 3;
|
||||
}
|
||||
|
||||
puts("run argv cleanup ok");
|
||||
FreeLibrary(dll);
|
||||
return 0;
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user