Skip to content

flex segfaults in yy_top_state #748

Description

@nxg

Consider the program below.

Building and running this segfaults:

% flex -o flex-stack.c flex-stack.lex
% cc -o flex-stack flex-stack.c
% ./flex-stack "one two"
word:<one>
zsh: segmentation fault  ./flex-stack "one two"

Looking in the debugger:

%  lldb ./flex-stack                                                      
(lldb) target create "./flex-stack"
Current executable set to '/checkouts/me/codeberg/beastie/scratch/flex-stack' (arm64).
(lldb) proc lau "one two"
Process 27897 launched: '/checkouts/me/codeberg/beastie/scratch/flex-stack' (arm64)
word:<one>
Process 27897 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0xfffffffffffffffc)
    frame #0: 0x0000000100000f18 flex-stack`yy_top_state at flex-stack.c:1588:13
   1585	}
   1586	
   1587	    static int yy_top_state  (void)
-> 1588	{
   1589	    	return (yy_start_stack)[(yy_start_stack_ptr) - 1];
   1590	}
   1591	
Target 0: (flex-stack) stopped.
(lldb) p yy_start_stack_ptr
(int) 0
(lldb) ^D

Ie, there is a stack underflow when yy_top_state is called when no start-state has been pushed. I would expect yy_top_state to handle this OK, and return 0/INITIAL in this case (if (yy_start_stack_ptr == 0) return 0; perhaps?). In the real case, I was calling yy_top_state in an error handler, hoping to give the caller some suitable feedback.

The same thing happens with %option reentrant, though with yyguts_t involved.

Versions, etc:

% flex -V
flex 2.6.4
% uname -a
Darwin PHAS-MACDESKE207E9 25.6.0 Darwin Kernel Version 25.6.0: Sat Jul 11 15:24:35 PDT 2026; root:xnu-12377.161.13~4/RELEASE_ARM64_T8103 arm64
%  cc --version
Apple clang version 21.0.0 (clang-2100.1.1.101)
Target: arm64-apple-darwin25.6.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin

This is specifically the 2.6.4 built from the sources here, rather than the v2.6.4 that comes with macOS (though it displays the same behaviour).

ALPHABETIC  [a-zA-Z]
WS      [^a-zA-Z!]

%option noyywrap stack

%%

{ALPHABETIC}+   {
    printf("word:<%s>\n", yytext);
    printf("stack %d\n", yy_top_state());  // <----- note
    return 1;
}
{WS}+   {
    return 2;
}

%%
int main(int argc, char** argv)
{
    if (argc != 2) {
        fprintf(stderr, "Usage: %s string\n", argv[0]);
        exit(1);
    }

    yy_scan_string(argv[1]);

    int token;
    while ((token = yylex()) != 0) {
        printf("-> %d\n", token);
    }
}

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions