Eliminating Stack Overflow by Abstract Interpretation

An important correctness criterion for software running on embedded microcontrollers is stack safety: a guarantee that the call stack does not overflow. We address two aspects of the problem of creating stack-safe embedded software that also makes efficient use of memory: statically bounding worst-case stack depth, and automatically reducing stack memory requirements. Our first contribution is a method for statically guaranteeing stack safety by performing whole-program analysis, using an approach based on context-sensitive abstract interpretation of machine code. Abstract interpretation permits our analysis to accurately model when interrupts are enabled and disabled, which is essential for accurately bounding the stack depth of typical embedded systems. We have implemented a stack analysis tool that targets Atmel AVR microcontrollers, and tested it on embedded applications compiled from up to 30,000 lines of C . We experimentally validate the accuracy of the tool, which runs in a few seconds on the largest programs that we tested. The second contribution of this paper is a novel framework for automatically reducing stack memory requirements. We show that goal-directed global function inlining can be used to reduce the stack memory requirements of component-based embedded software, on average, to 40% of the requirement of a system compiled without inlining, and to 68% of the requirement of a system compiled with aggressive whole-program inlining that is not directed towards reducing stack usage.

[1]  Rainer Leupers,et al.  Function inlining under code size constraints for embedded processors , 1999, 1999 IEEE/ACM International Conference on Computer-Aided Design. Digest of Technical Papers (Cat. No.99CH37051).

[2]  Theodore P. Baker,et al.  A stack-based resource allocation policy for realtime processes , 1990, [1990] Proceedings 11th Real-Time Systems Symposium.

[3]  Andrew Ayers,et al.  Aggressive inlining , 1997, PLDI '97.

[4]  Robert Szewczyk,et al.  System architecture directions for networked sensors , 2000, ASPLOS IX.

[5]  Saumya K. Debray,et al.  Alias analysis of executable code , 1998, POPL '98.

[6]  Giuseppe Lipari,et al.  Minimizing memory utilization of real-time task sets in single and multi-processor systems-on-a-chip , 2001, Proceedings 22nd IEEE Real-Time Systems Symposium (RTSS 2001) (Cat. No.01PR1420).

[7]  Jakob Engblom Static properties of commercial embedded real-time programs, and their implication for worst-case execution time analysis , 1999, Proceedings of the Fifth IEEE Real-Time Technology and Applications Symposium.

[8]  Eric Eide,et al.  Knit: component composition for systems software , 2000, OSDI.

[9]  Frank Yellin,et al.  The Java Virtual Machine Specification , 1996 .

[10]  John Regehr,et al.  HOIST: a system for automatically deriving static analyzers for embedded systems , 2004, ASPLOS XI.

[11]  Patrick Cousot,et al.  Abstract interpretation: a unified lattice model for static analysis of programs by construction or approximation of fixpoints , 1977, POPL.

[12]  Thomas W. Reps,et al.  Analyzing Memory Accesses in x86 Executables , 2004, CC.

[13]  Jens Palsberg,et al.  Static checking of interrupt-driven software , 2001, Proceedings of the 23rd International Conference on Software Engineering. ICSE 2001.

[14]  Mark Stephenson,et al.  Bidwidth analysis with application to silicon compilation , 2000, PLDI '00.

[15]  Jens Palsberg,et al.  Stack Size Analysis for Interrupt-Driven Programs , 2003, SAS.

[16]  Manas Saksena,et al.  Scalable real-time system design using preemption thresholds , 2000, Proceedings 21st IEEE Real-Time Systems Symposium.

[17]  Jens Palsberg,et al.  A Typed Interrupt Calculus , 2002, FTRTFT.