Skip to content

Fix segfault in cb_react_ruleset_nd when Rule arg is not a membrane - #373

Draft
okamura10 with Copilot wants to merge 3 commits into
developfrom
copilot/fix-segmentation-fault-issue
Draft

Fix segfault in cb_react_ruleset_nd when Rule arg is not a membrane#373
okamura10 with Copilot wants to merge 3 commits into
developfrom
copilot/fix-segmentation-fault-issue

Conversation

Copilot AI commented Feb 21, 2026

Copy link
Copy Markdown

state_space.react_nd_set crashes with SIGSEGV when called with a non-membrane atom (e.g. []) as the Rule argument, because cb_react_ruleset_nd unconditionally dereferences rule_mem_proxy as an outer membrane proxy without checking its functor type.

Changes

  • src/ext/react_rule.cpp: Wrap the rule_mem extraction and apply_rules_in_rulesets calls in a LMN_IS_PROXY_FUNCTOR() guard. When rule_mem_proxy is not an outer proxy (functor ≥ 3), rule application is skipped and an empty list is returned — semantically equivalent to "no rules to apply". All remaining cleanup (graph membrane removal, RetRule relinking) is unaffected.
// Before — unconditional dereference, crashes when rule_mem_proxy is e.g. []
LmnMembraneRef rule_mem = LMN_PROXY_GET_MEM(
    (LmnSymbolAtomRef)((LmnSymbolAtomRef)rule_mem_proxy)->get_link(0));
auto rulesets = &rule_mem->get_rulesets();
apply_rules_in_rulesets(mem, graph_mem, rulesets, &head, &pos);

// After — guarded
if (LMN_IS_PROXY_FUNCTOR(((LmnSymbolAtomRef)rule_mem_proxy)->get_functor())) {
    LmnMembraneRef rule_mem = LMN_PROXY_GET_MEM(
        (LmnSymbolAtomRef)((LmnSymbolAtomRef)rule_mem_proxy)->get_link(0));
    auto rulesets = &rule_mem->get_rulesets();
    apply_rules_in_rulesets(mem, graph_mem, rulesets, &head, &pos);
    ...
}
  • test/library_check/testsuite/statespace/statespace.lmn: Add regression test case that calls state_space.react_nd_set([], {a}, rules) and asserts the result is [] (empty successor list, no crash).
Original prompt

This section details on the original issue you should resolve

<issue_title>segmentation fault が発生するプログラム</issue_title>
<issue_description>以下のプログラムで Segmentation Fault が発生した.

実行コマンド

> slim --hl --use-builtin-rule priority.lmn
Segmentation fault (core dumped)

プログラム

ret = run(
  {prs=[
    {a :- b.},
    {b :- c.}
  ]},
  {a, a, a.}
).

set.use.
state_space.use.
n(0), // 状態数
t(0). // 遷移数


// 初期化
// PRs: Priority Rules
run@@Ret = run(PRs, {$ini[]}), n($n) :- $nn = $n+1 |
    Ret = exp0(PRs, s(ID, {$ini[]}),
	       state_space.state_map_find(state_space.state_map_init, {$ini[]}, ID), 
	       set.init, set.init), 
	      n($nn).


// 初期化
// exp0(PriorityRulesMem, Initial State, StateMap, States, Transitions)
// [s($id, {$ini[]})] は初期状態のみがスタックにあることを示す.
exp0@@Ret = exp0(PRs, S0, Map, Ss, Ts), S0=s($id, {$ini[]}) :- int($id) |
    Ret = exp(PRs, [s($id, {$ini[]})], Map, set.insert(Ss, $id), Ts), ini($id).


//  アルゴリズム概要(改造後のexp以降の処理の概要)
//  1.   スタックに状態があるとき,スタックから状態を取り出す.
//       スタックに状態がないとき,終了.
//  2.1. 優先度付きルールのリストが空でないとき,先頭のルール集合を取り出す
//  2.2. 優先度付きルールのリストが空のとき,1. に戻る
//  3.   そのルール集合で反応を試みる
//  4.1. 遷移先があるときは状態集合,遷移集合の更新を行い,
//       優先度付きルールのリストを元に戻して 1. に戻る
//  4.2. 遷移先がないときは 2. に戻る


// 優先度付きルールのコピー
exp_1@@Ret = exp({prs=$l[]}, S0, Map, Ss, Ts) :-
    Ret = exp_1({prs=$l[]}, rsl=$l[], S0, Map, Ss, Ts).

// 対象のルール集合を取り出す
exp_2@@Ret = exp_1(PRs, rsl=[X|Rest], S0, Map, Ss, Ts) :-
    Ret = exp_2(PRs, rsl=[Rest], S0, Map, Ss, Ts, rs(X)).

// ルール集合が空のとき
% exp_2_@@Ret = exp_1(PRs, rsl=[], S0, Map, Ss, Ts) :-


// 書き換え実行
exp_3@@Ret = exp_2(PRs, RestRules, S0, Map, Ss, Ts, rs(Rs)), S0=[s($id, {$src[]})|Stk] :-  
    int($id) |
    Ret = suc_1(PRs, RestRules, r, Stk, Exp, p($id, {$src[]}), Map, Ss, Ts),
    Exp = state_space.react_nd_set(Rs, {$src[]}, r).

// 遷移先がないとき
// 次の優先度のルール集合を試す
suc_@@Ret = suc_1(PRs, RestRules, R, Stk, [], p($id, {$src[]}), Map, Ss, Ts) :- 
    ground(R), int($id) |
    Ret = exp_1(PRs, RestRules, [s($id, {$src[]})|Stk], Map, Ss, Ts).

// 遷移先があるとき
suc_@@Ret = suc_1(PRs, RestRules, R, Stk, [{$dest[]}|Suc], Src, Map, Ss, Ts) :- 
    ground(R) |
    M = state_space.state_map_find(Map, {$dest[]}, ID),
    Ret = ns0(PRs, RestRules, Stk, Suc, Src, p(ID, {$dest[]}), M, Ss, Ts).

// 状態集合の更新
ns0@@Ret = ns0(PRs, RestRules, Stk, Suc, Src, p($d, D), Map, Ss, Ts) :- int($d) |
    Ret = ns(PRs, RestRules, Stk, Suc, Res, Src, p($d, D), Map, S, Ts),
    S = set.find(Ss, $d, Res).

ns@@Ret = ns(PRs, RestRules, Stk, Suc, some, p($s, Src), p($d, Dst), Map, Ss, Ts) :-
    int($s), int($d) |
    Ret = nt(PRs, RestRules, Stk, Suc, Res, p($s, Src), p($d, Dst), Map, Ss, T),
    T = set.find(Ts, '.'($s, $d), Res).


// TODO: このルール以降で次のエラーが発生する
// 'slim --hl --use-builtin-rule pr…' terminated by signal SIGSEGV (Address boundary error)
// suc_1 を test とかに置き換えれば,状態が確認できる.
ns_@@Ret = ns(PRs, RestRules, Stk, Suc, none, p($s, Src), p($d, Dst), Map, Ss, Ts), n($n), t($t) :-
    int($s), int($d), $nn=$n+1, $tt=$t+1|
    Ret = suc_1(PRs, RestRules, r, [s($d, Dst)|Stk], Suc, p($s, Src), Map, S, T),
    S = set.insert(Ss, $d), T = set.insert(Ts, '.'($s, $d)),
    n($nn), t($tt).


// 遷移集合の更新

nt@@Ret = nt(PRs, RestRules, Stk, Suc, some, Src, p($d, {$dest[]}), Map, Ss, Ts) :-
    int($d) |
    Ret = suc_1(PRs, RestRules, r, Stk, Suc, Src, Map, Ss, Ts).

nt_@@Ret = nt(PRs, RestRules, Stk, Suc, none, p($s, Src), p(D, {$dest[]}), Map, Ss, Ts), t($t) :-
    int($s), $tt=$t+1 |
    Ret = suc_1(PRs, RestRules, r, Stk, Suc, p($s, Src), Map, Ss, set.insert(Ts, '.'($s, D))), t($tt).


// 状態遷移系の出力
% Ret = state_space(I, M, S, T) :-
% Ret = ss(I, M, set.to_list(S), set.to_list(T)).
% Ret = ss(I, M, [$x|S], T) :- int($x) |
% Ret = ss(I, state_space.state_map_find(M, $x, Res), S, T), state($x, Res).

```</issue_description>

## Comments on the Issue (you are @copilot in this section)

<comments>
<comment_new><author>@Snaif-Yamachan</author><body>
実行コマンド `> slim -t --hl --use-builtin-rule first.il`

set.use.
state_space.use.
ret(suc_1({prs([{a :- b. },{b :- c.}]). },
'='(rsl,[[]]),r,[s(7,{a. a. b. })],
state_space.react_nd_set([],{a. a. a. },r),
p(9,{a. a. a. }))).
r([{b :- c.}]). r({a :- b.}). //delete->unknown

上記プログラムでバグを再現
最後の行を消した場合、segvの代わりにinterpret: Unknown operationが表示されエラー終了する
次に実行されるルールはstate_space.lmn内の

Ret = state_space.react_nd_set(Rule, Graph, RetRule) :- '$callback'('cb_react_ruleset_nd', Rule, Graph, RetRule, Ret).

で、このルールが`cb_react_ruleset_nd`を呼び出しており、その関数を追跡した結果react_rule.cpp内`apply_rules_in_rulesets`が呼び出す`Task::react_rule(&rc, src_graph, r);`内でsegvが発生することまで判明した</body></comment_new>
</comments>


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Copilot AI and others added 2 commits February 21, 2026 01:59
…roxy

When state_space.react_nd_set is called with a non-membrane argument (e.g.
[] nil atom) as the Rule parameter, cb_react_ruleset_nd crashed with SIGSEGV
because it unconditionally dereferenced rule_mem_proxy as an outer membrane
proxy.

The fix adds a LMN_IS_PROXY_FUNCTOR() guard before accessing the membrane.
When rule_mem_proxy is not a proxy (e.g. []), rule application is skipped
and an empty result list is returned, consistent with 'no rules to apply'
semantics.

Also adds a regression test to the statespace library test suite.

Co-authored-by: okamura10 <130753425+okamura10@users.noreply.github.com>
Co-authored-by: okamura10 <130753425+okamura10@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix segmentation fault in priority rule execution Fix segfault in cb_react_ruleset_nd when Rule arg is not a membrane Feb 21, 2026
Copilot AI requested a review from okamura10 February 21, 2026 02:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

segmentation fault が発生するプログラム

3 participants