TCCStates should (obviously) be completely independent.
But this corner case shows that a syntax error in the first
one prevents subsequent TCCStates from failing on *correct code*.
My guess would be that a longjmp while processing the syntax
error in the global declaration skips the reset of something associated
with symbol tables.
This is as far as I got: In the non-error case, the first name that
relocate_syms() finds is "memset". In the error case, the first name
that it finds is "L.2". That's probably a good clue for people smarter
than me. The memset is probably required to initialize the stack-allocated
struct, but for some reason things work when that struct is explicitly
declared (vs. initialized inline).
The code below shows the error when run with an argument.
It works as expected with no arguments. [I apologize for any
formatting errors, I suck at getting gmail to do what I intend.]
$ tcc -v
tcc version 0.9.28rc 2025-10-03 mob@bcfb872f* (AArch64 Linux)
$ uname -a
Linux penguin 6.6.67-06628-g571b599e617d #1 SMP PREEMPT Mon, 27 Jan 2025
12:44:48 -0800 aarch64 GNU/Linux
$ tcc -ggdb3 tcc-state-bug.c -ltcc && ./a.out x
----
compiling:
int x=
<string>:1: error: expression expected before '<eof>'
errors found, 1 expected
----
compiling:
void inline_struct_initalization()
{
struct S { char *data; };
// Replacing "" w/0 avoids the bug!
// As does an explicit stack allocation!
void *p = &(struct S){""};
}
tcc: error: undefined symbol 'L.2'
errors found, 0 expected
#include <stdio.h>#include "libtcc.h"
// This one (correctly) doesn't compile, and *allows* c2 to be
compiledconst char *c1_ok = " int x=1";
// This one (correctly) doesn't compile, but *prevents* c2 from being
compiled!const char *c1_bad = " int x=";
// This one should compile without errors, but previously compiling//
'c1_bad' in a *separate TCCState* incorrectly causes it to fail.const
char *c2 = " \n\ void
inline_struct_initalization() \n\ {
\n\ struct S { char *data; };
\n\ // Replacing \"\" w/0 avoids the bug! \n\ // As
does an explicit stack allocation! \n\ void *p = &(struct
S){\"\"}; \n\ }
\n\";
void compile(const char *str, int expected){
fprintf(stderr, "----\ncompiling:\n%s\n", str);
TCCState *t = tcc_new();
if ( tcc_set_output_type(t, TCC_OUTPUT_MEMORY)
|| tcc_compile_string(t, str)
|| tcc_relocate(t))
fprintf(stderr, "errors found, %d expected\n", expected);
tcc_delete(t);}
// Run with no args to see things working correctly.// Run with any
arg and c2 will produce "tcc: error: undefined symbol 'L.2'"int
main(int argc, char *argv[]){
compile(argc == 1 ? c1_ok : c1_bad, 1);
compile(c2, 0);}
This is of course only relevant in interactive situations where someone
might enter incorrect code. But correct cleanup after errors is important!
Perhaps someone smarter than me can get further.
Thanks - Eric
_______________________________________________
Tinycc-devel mailing list
[email protected]
https://lists.nongnu.org/mailman/listinfo/tinycc-devel