Skip to content

Commit

Permalink
CStrings leakless
Browse files Browse the repository at this point in the history
avoid memory leaks with lost CStrings on stack after errors.

tccpp.c:
- use/abuse static Cstring tokcstr where possible
tccgen.c:
- use/abuse static Cstring initstr where possible
tcc.h/libtcc.a:
- add 'stk_data' array to track memory pointer on stack
- add macros stk_push/pop() and cstr_new/free_s()
tccasm.c:
- use that
- use char[16] instead of char* for op.constraint
  • Loading branch information
grischka committed Apr 25, 2023
1 parent 40131b7 commit a045400
Show file tree
Hide file tree
Showing 5 changed files with 118 additions and 123 deletions.
8 changes: 7 additions & 1 deletion libtcc.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@
/* XXX: get rid of this ASAP (or maybe not) */
ST_DATA struct TCCState *tcc_state;
TCC_SEM(static tcc_compile_sem);
/* an array of pointers to memory to be free'd after errors */
ST_DATA void** stk_data;
ST_DATA int nb_stk_data;

/********************************************************/
#ifdef _WIN32
Expand Down Expand Up @@ -609,8 +612,11 @@ static void error1(int mode, const char *fmt, va_list ap)
cstr_free(&cs);
if (mode != ERROR_WARN)
s1->nb_errors++;
if (mode == ERROR_ERROR && s1->error_set_jmp_enabled)
if (mode == ERROR_ERROR && s1->error_set_jmp_enabled) {
while (nb_stk_data)
tcc_free(*(void**)stk_data[--nb_stk_data]);
longjmp(s1->error_jmp_buf, 1);
}
}

LIBTCCAPI void tcc_set_error_func(TCCState *s, void *error_opaque, TCCErrorFunc error_func)
Expand Down
17 changes: 13 additions & 4 deletions tcc.h
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,7 @@ typedef struct CString {
int size; /* size in bytes */
int size_allocated;
void *data; /* either 'char *' or 'nwchar_t *' */
struct CString *prev;
} CString;

/* type definition */
Expand Down Expand Up @@ -733,7 +734,7 @@ typedef struct ExprValue {
#define MAX_ASM_OPERANDS 30
typedef struct ASMOperand {
int id; /* GCC 3 optional identifier (0 if number only supported) */
char *constraint;
char constraint[16];
char asm_str[16]; /* computed asm string for operand */
SValue *vt; /* C value of the expression */
int ref_index; /* if >= 0, gives reference to a output constraint */
Expand Down Expand Up @@ -1208,6 +1209,8 @@ enum tcc_token {
/* ------------ libtcc.c ------------ */

ST_DATA struct TCCState *tcc_state;
ST_DATA void** stk_data;
ST_DATA int nb_stk_data;

/* public functions currently used by the tcc main function */
ST_FUNC char *pstrcpy(char *buf, size_t buf_size, const char *s);
Expand Down Expand Up @@ -1257,11 +1260,17 @@ ST_FUNC void cstr_free(CString *cstr);
ST_FUNC int cstr_printf(CString *cs, const char *fmt, ...) PRINTF_LIKE(2,3);
ST_FUNC int cstr_vprintf(CString *cstr, const char *fmt, va_list ap);
ST_FUNC void cstr_reset(CString *cstr);

ST_FUNC void tcc_open_bf(TCCState *s1, const char *filename, int initlen);
ST_FUNC int tcc_open(TCCState *s1, const char *filename);
ST_FUNC void tcc_close(void);

/* mark a memory pointer on stack for cleanup after errors */
#define stk_push(p) dynarray_add(&stk_data, &nb_stk_data, p)
#define stk_pop() (--nb_stk_data)
/* mark CString on stack for cleanup errors */
#define cstr_new_s(cstr) (cstr_new(cstr), stk_push(&(cstr)->data))
#define cstr_free_s(cstr) (cstr_free(cstr), stk_pop())

ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags);
/* flags: */
#define AFF_PRINT_ERROR 0x10 /* print error if file not found */
Expand Down Expand Up @@ -1483,8 +1492,8 @@ ST_FUNC int type_size(CType *type, int *a);
ST_FUNC void mk_pointer(CType *type);
ST_FUNC void vstore(void);
ST_FUNC void inc(int post, int c);
ST_FUNC void parse_mult_str (CString *astr, const char *msg);
ST_FUNC void parse_asm_str(CString *astr);
ST_FUNC CString* parse_mult_str(const char *msg);
ST_FUNC CString* parse_asm_str(void);
ST_FUNC void indir(void);
ST_FUNC void unary(void);
ST_FUNC void gexpr(void);
Expand Down
48 changes: 23 additions & 25 deletions tccasm.c
Original file line number Diff line number Diff line change
Expand Up @@ -1064,15 +1064,12 @@ ST_FUNC int find_constraint(ASMOperand *operands, int nb_operands,
}

static void subst_asm_operands(ASMOperand *operands, int nb_operands,
CString *out_str, CString *in_str)
CString *out_str, const char *str)
{
int c, index, modifier;
const char *str;
ASMOperand *op;
SValue sv;

cstr_new(out_str);
str = in_str->data;
for(;;) {
c = *str++;
if (c == '%') {
Expand Down Expand Up @@ -1118,11 +1115,11 @@ static void parse_asm_operands(ASMOperand *operands, int *nb_operands_ptr,
{
ASMOperand *op;
int nb_operands;
char* astr;

if (tok != ':') {
nb_operands = *nb_operands_ptr;
for(;;) {
CString astr;
if (nb_operands >= MAX_ASM_OPERANDS)
tcc_error("too many asm operands");
op = &operands[nb_operands++];
Expand All @@ -1135,10 +1132,8 @@ static void parse_asm_operands(ASMOperand *operands, int *nb_operands_ptr,
next();
skip(']');
}
parse_mult_str(&astr, "string constant");
op->constraint = tcc_malloc(astr.size);
strcpy(op->constraint, astr.data);
cstr_free(&astr);
astr = parse_mult_str("string constant")->data;
pstrcpy(op->constraint, sizeof op->constraint, astr);
skip('(');
gexpr();
if (is_output) {
Expand Down Expand Up @@ -1171,7 +1166,8 @@ static void parse_asm_operands(ASMOperand *operands, int *nb_operands_ptr,
/* parse the GCC asm() instruction */
ST_FUNC void asm_instr(void)
{
CString astr, astr1;
CString astr, *astr1;

ASMOperand operands[MAX_ASM_OPERANDS];
int nb_outputs, nb_operands, i, must_subst, out_reg, nb_labels;
uint8_t clobber_regs[NB_ASM_REGS];
Expand All @@ -1183,7 +1179,11 @@ ST_FUNC void asm_instr(void)
|| tok == TOK_GOTO) {
next();
}
parse_asm_str(&astr);

astr1 = parse_asm_str();
cstr_new_s(&astr);
cstr_cat(&astr, astr1->data, astr1->size);

nb_operands = 0;
nb_outputs = 0;
nb_labels = 0;
Expand Down Expand Up @@ -1273,13 +1273,14 @@ ST_FUNC void asm_instr(void)
printf("asm: \"%s\"\n", (char *)astr.data);
#endif
if (must_subst) {
subst_asm_operands(operands, nb_operands + nb_labels, &astr1, &astr);
cstr_free(&astr);
} else {
astr1 = astr;
cstr_reset(astr1);
cstr_cat(astr1, astr.data, astr.size);
cstr_reset(&astr);
subst_asm_operands(operands, nb_operands + nb_labels, &astr, astr1->data);
}

#ifdef ASM_DEBUG
printf("subst_asm: \"%s\"\n", (char *)astr1.data);
printf("subst_asm: \"%s\"\n", (char *)astr.data);
#endif

/* generate loads */
Expand All @@ -1290,7 +1291,8 @@ ST_FUNC void asm_instr(void)
bleed out to surrounding code. */
sec = cur_text_section;
/* assemble the string with tcc internal assembler */
tcc_assemble_inline(tcc_state, astr1.data, astr1.size - 1, 0);
tcc_assemble_inline(tcc_state, astr.data, astr.size - 1, 0);
cstr_free_s(&astr);
if (sec != cur_text_section) {
tcc_warning("inline asm tries to change current section");
use_section1(tcc_state, sec);
Expand All @@ -1305,23 +1307,20 @@ ST_FUNC void asm_instr(void)

/* free everything */
for(i=0;i<nb_operands;i++) {
ASMOperand *op;
op = &operands[i];
tcc_free(op->constraint);
vpop();
}
cstr_free(&astr1);

}

ST_FUNC void asm_global_instr(void)
{
CString astr;
CString *astr;
int saved_nocode_wanted = nocode_wanted;

/* Global asm blocks are always emitted. */
nocode_wanted = 0;
next();
parse_asm_str(&astr);
astr = parse_asm_str();
skip(')');
/* NOTE: we do not eat the ';' so that we can restore the current
token after the assembler parsing */
Expand All @@ -1335,14 +1334,13 @@ ST_FUNC void asm_global_instr(void)
ind = cur_text_section->data_offset;

/* assemble the string with tcc internal assembler */
tcc_assemble_inline(tcc_state, astr.data, astr.size - 1, 1);
tcc_assemble_inline(tcc_state, astr->data, astr->size - 1, 1);

cur_text_section->data_offset = ind;

/* restore the current C token */
next();

cstr_free(&astr);
nocode_wanted = saved_nocode_wanted;
}

Expand Down
Loading

0 comments on commit a045400

Please sign in to comment.