Search code examples
cbisoncpu-architecturelex

Bison/Lex segfaults on x86 but runs on arm


I have a problem described in the title. I have an Edify language parser that runs without errors when I building it on arm but fails when I try to use it with x86. I traced segfault to yy_scan_bytes function, more precisely to this code:

YY_BUFFER_STATE yy_scan_bytes  (yyconst char * yybytes, int  _yybytes_len ) {
YY_BUFFER_STATE b;
char * buf;
yy_size_t n;
int i;
/* Get memory for full buffer, including space for trailing EOB's. */
n = _yybytes_len + 2;
buf = (char *) yyalloc(n  );

if ( ! buf ) {
  YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
}

for ( i = 0; i < _yybytes_len; ++i ) {
  buf[i] = yybytes[i]; // <==========
}

The full code is here: https://github.com/twaik/edify_x86_failing_code I've got it from AROMA Installer source. That's everything I discovered after debug. Thanks.


Solution

  • Trying to build your code gives me these errors:

    main.c: In function ‘parse_string’:
    main.c:27:5: warning: implicit declaration of function ‘yy_switch_to_buffer’ [-W
    implicit-function-declaration]
         yy_switch_to_buffer(yy_scan_string(str));
         ^~~~~~~~~~~~~~~~~~~
    main.c:27:25: warning: implicit declaration of function ‘yy_scan_string’ [-Wimplicit-function-declaration]
         yy_switch_to_buffer(yy_scan_string(str));
    

    That means that the compiler assumes that yy_switch_to_buffer() and yy_scan_string() return an int, as it does for all functions that are not declared before use (as per the c89 standard). But that is not the case (the first returns void, and the second a pointer (YY_BUFFER_STATE)). Notice that on x86_64, the size of a pointer is not the same as the size of an int.

    Adding some band-aid prototypes like

    void yy_switch_to_buffer(void*);
    void *yy_scan_string(const char*);
    

    to main.c, before their use in parse_string() may stop the segfaulting.

    A better fix would be to arrange in the Makefile that the lexer be run with the --header-file=lex-header.h option, and then include lex-header.h from main.c. Or even better, wrap all lex-specific code in some simple functions, and put the prototypes of those functions in a header included from both main.c and the *.l file.