오토마톤 학습을 활용한 Ruby 파서 호환성 문제 해결

[JA] Make Parsers Compatible Using Automata Learning / Hiroya Fujinami @makenowjust

작성자
RubyKaigi
발행일
2025년 05월 27일

핵심 요약

  • 1 Ruby의 두 파서(parse.y, Prism) 간 호환성 문제를 오토마톤 이론 및 오토마톤 학습을 통해 체계적으로 발견하는 방법을 제시합니다.
  • 2 Angluin의 L* 알고리즘과 Visible Pushdown Automata(VPA)를 활용하여 블랙박스 시스템인 파서의 동작을 오토마톤으로 추론하고, 그 차이를 분석하여 버그를 식별했습니다.
  • 3 발표자가 개발한 Ruby 라이브러리 'Lernnen'을 사용하여 실제 Prism 파서에서 특정 구문(`(:A)`) 파싱 오류를 발견하고 수정하는 과정을 시연했습니다.

도입

Ruby 언어는 현재 `parse.y`와 `Prism`이라는 두 가지 주요 파서 구현체를 사용하고 있습니다. `parse.y`는 오랜 기간 사용되어 온 Bison 기반의 파서이며, `Prism`은 C 언어로 작성된 새로운 파서로, 성능과 라이브러리 활용성 측면에서 이점을 가집니다. 그러나 이처럼 여러 파서가 존재함에 따라 특정 코드에 대해 파서마다 다른 해석을 내놓는 '파서 호환성' 문제가 발생할 수 있습니다. 본 발표는 이러한 호환성 문제를 해결하기 위해 오토마톤 이론과 오토마톤 학습(Automata Learning)을 적용하는 혁신적인 접근 방식을 제안하고, 실제 Ruby 파서에서 버그를 발견한 사례를 소개합니다.

파서 호환성 문제와 기존 해결책의 한계

Ruby 파서 구현체 간의 호환성 문제는 특정 파서에서는 올바르게 동작하는 코드가 다른 파서에서는 오류를 발생시키거나 다르게 파싱되는 상황을 야기합니다. 기존에는 유닛 테스트, 공개 Gem 파싱, 퍼징(fuzzing)과 같은 물량 공세 방식이 사용되었으나, Ruby 문법의 복잡성과 마이너하거나 새로운 구문의 미활용성으로 인해 모든 경우를 포괄적으로 검증하기 어렵다는 한계가 있었습니다.

오토마톤 이론의 적용

발표자는 이 문제를 해결하기 위해 오토마톤 이론을 도입합니다. * 오토마톤과 정규 표현식: 오토마톤은 상태, 알파벳, 전이 함수 등을 통해 문자열의 수락 여부를 결정하며, 정규 표현식과 상호 변환이 가능합니다. 이는 오토마톤이 문자열 집합을 다루는 효과적인 도구임을 의미합니다. * 집합 연산과 대칭 차집합: 오토마톤은 문자열 집합에 대한 교집합, 합집합, 차집합 등 다양한 집합 연산을 효율적으로 수행할 수 있습니다. 특히, 두 파서의 차이를 발견하는 데 핵심적인 ‘대칭 차집합(Symmetric Difference, XOR)’ 연산은 한 오토마톤에는 포함되지만 다른 오토마톤에는 포함되지 않는 문자열 집합을 찾아냅니다. * 파서와 오토마톤 연결: 파서가 특정 문자열을 성공적으로 파싱할 때만 수락하는 ‘파서에 대응하는 오토마톤’ 개념을 정의하여 파서의 동작을 오토마톤으로 모델링합니다.

오토마톤 학습(Automata Learning)을 통한 오토마톤 획득

블랙박스 시스템인 파서로부터 해당 오토마톤을 직접 구축하는 것은 어렵습니다. 이를 위해 ‘오토마톤 학습’ 알고리즘, 특히 Angluin의 L* 알고리즘이 활용됩니다. * L* 알고리즘: L는 ‘멤버십 쿼리(Membership Query)’ (주어진 문자열이 시스템에 의해 수락되는가?)와 ‘동등성 쿼리(Equivalence Query)’ (학습된 오토마톤이 실제 시스템과 일치하는가? 불일치 시 반례 제공)를 통해 시스템의 동작을 학습합니다. * Ruby 문법의 복잡성 극복: L는 정규 언어에 특화되어 있어 Ruby와 같은 복잡한 문맥 자유 언어(Context-Free Language)를 직접 학습하기 어렵습니다. 이를 해결하기 위해 괄호의 중첩과 같은 문맥 자유 언어의 일부 특성을 처리할 수 있는 ‘Visible Pushdown Automata(VPA)’를 사용합니다. VPA는 Ruby 문법 전체는 아니지만, 특정 부분 문법의 호환성 검증에 유용합니다.

‘Lernnen’ 라이브러리와 실제 버그 발견

발표자는 자신이 개발한 Ruby 기반 오토마톤 학습 라이브러리 ‘Lernnen’을 소개합니다. ‘Lernnen’은 다양한 오토마톤 학습 알고리즘을 지원하며, 사용자 친화적인 API를 제공하여 쉽게 오토마톤을 학습하고 분석할 수 있도록 합니다. * 실험 설정: Lernnen을 사용하여 문자열 리터럴, 콜론, 괄호 등 제한된 알파벳에 대한 parse.yPrism의 오토마톤을 학습했습니다. * 버그 발견: 학습된 두 오토마톤의 대칭 차집합을 계산한 결과, (:A)와 같은 구문이 parse.y에서는 올바르게 파싱되지만 Prism에서는 심볼 리터럴로 잘못 파싱되는 버그를 발견했습니다. 이 버그는 Prism에 보고되어 이미 수정되었습니다.

결론

본 발표는 오토마톤 이론과 오토마톤 학습이라는 학술적 방법론을 실제 Ruby 파서의 호환성 문제 해결에 성공적으로 적용한 사례를 보여주었습니다. 이는 기존의 물량 공세 방식으로는 발견하기 어려웠던 미묘한 버그를 체계적이고 포괄적으로 식별할 수 있는 가능성을 제시합니다. 특히, 발표자가 개발한 'Lernnen' 라이브러리는 이러한 오토마톤 학습 기법을 Ruby 개발자들이 쉽게 활용할 수 있도록 지원합니다. 비록 Ruby 문법 전체를 학습하는 것은 현재 기술로는 어렵고, 파싱 성공 여부뿐 아니라 추상 구문 트리(AST)의 동일성 검증과 같은 추가적인 과제가 남아있지만, 이번 연구는 소프트웨어 시스템의 복잡한 동작을 형식적으로 검증하는 새로운 방향을 제시하며, 향후 연구를 위한 중요한 기반을 마련했습니다. 오토마톤 학습은 코드 리팩토링 후 동작 일치 여부 확인 등 다양한 소프트웨어 검증 시나리오에 유용하게 활용될 수 있을 것입니다.

댓글 0

댓글 작성

0/1000
정중하고 건설적인 댓글을 작성해 주세요.

아직 댓글이 없습니다

첫 번째 댓글을 작성해보세요!