all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
* bug#74547: 31.0.50; igc: assertion failed in buffer.c
@ 2024-11-26 18:35 Óscar Fuentes
  2024-11-27  6:54 ` Gerd Möllmann
  0 siblings, 1 reply; 25+ messages in thread
From: Óscar Fuentes @ 2024-11-26 18:35 UTC (permalink / raw)
  To: 74547


While editing a .dart file with lsp-mode.

gdb) bt full
#0  terminate_due_to_signal (sig=6, backtrace_limit=2147483647) at ../../emacs/src/emacs.c:433
#1  0x00005555559038cf in set_state (state=IGC_STATE_DEAD) at ../../emacs/src/igc.c:858
        old_state = IGC_STATE_USABLE
#2  0x0000555555902f3e in igc_assert_fail
    (file=0x555555a47782 "buffer.c", line=579, msg=0x555555a4a157 "size > 0")
    at ../../emacs/src/igc.c:209
#3  0x00005555559c1384 in mps_lib_assert_fail
    (condition=0x555555a4a157 "size > 0", line=579, file=0x555555a47782 "buffer.c")
    at /home/oscar/dev/other/mps/code/mpsliban.c:87
#4  BufferFill
    (pReturn=pReturn@entry=0x7fffffff9988, buffer=buffer@entry=0x7fffe8000578, size=size@entry=0)
    at /home/oscar/dev/other/mps/code/buffer.c:579
        res = <optimized out>
        pool = <optimized out>
        base = 0x7fff93f2f7d0
        limit = 0x1
        next = <optimized out>
#5  0x00005555559f2da0 in amcSegFix (seg=0x7fffb820d070, ss=0x7fffffff9fc0, refIO=0x7fffffff99d0)
    at /home/oscar/dev/other/mps/code/poolamc.c:1633
        clientQ = <optimized out>
        arena = 0x7ffff7fbf000
        pool = <optimized out>
        amc = <optimized out>
        res = <optimized out>
        format = 0x7fffe8000388
        headerSize = 0
--Type <RET> for more, q to quit, c to continue without paging--
        ref = <optimized out>
        base = <optimized out>
        newRef = <optimized out>
        newBase = 0x7fff8a259f28
        length = 0
        buffer = 0x7fffe8000578
        gen = <optimized out>
        grey = <optimized out>
        toSeg = <optimized out>
        ti = <optimized out>
        trace = <optimized out>
#6  0x0000555555990b8c in _mps_fix2 (mps_ss=0x7fffffff9fc8, mps_ref_io=0x7fffffff9a10)
    at /home/oscar/dev/other/mps/code/trace.c:1433
        ss = 0x7fffffff9fc0
        ref = 0x7fff93f2f7d0
        chunk = 0x7fff84000000
        i = <optimized out>
        tract = <optimized out>
        seg = <optimized out>
        res = <optimized out>
#7  0x0000555555903cac in fix_lisp_obj (ss=0x7fffffff9fc8, pobj=0x7fff89f0e000)
    at ../../emacs/src/igc.c:998
        res = 32767
        client = 0x7fff93f2f7d0
        base = 0x7fff93f2f7d0
        p = 0x7fff89f0e000
--Type <RET> for more, q to quit, c to continue without paging--
        word = 140735675561940
        tag = 4
        _ss = 0x7fffffff9fc8
        _mps_zs = 22
        _mps_ufs = 549755846664
        _mps_wt = 32768
        _mps_w = 133143986160
#8  0x0000555555904160 in fix_array (ss=0x7fffffff9fc8, array=0x7fff89f0e000, n=6)
    at ../../emacs/src/igc.c:1233
        res = 30
        i = 0
        _ss = 0x7fffffff9fc8
        _mps_zs = 22
        _mps_ufs = 549755813896
        _mps_wt = <optimized out>
        _mps_w = 133143986160
#9  0x000055555590674b in fix_vectorlike (ss=0x7fffffff9fc8, v=0x7fff89f0dff0)
    at ../../emacs/src/igc.c:1974
        res = 32767
        size = 6
        _ss = 0x7fffffff9fc8
        _mps_zs = 22
        _mps_ufs = 549755813896
        _mps_wt = <optimized out>
        _mps_w = 133143986160
#10 0x0000555555908d53 in fix_vector (ss=0x7fffffff9fc8, v=0x7fff89f0dff0)
--Type <RET> for more, q to quit, c to continue without paging--
    at ../../emacs/src/igc.c:2646
        obj_ = 0x7fff89f0dff0
        res = 0
        _ss = 0x7fffffff9fc8
        _mps_zs = 22
        _mps_ufs = 549755813896
        _mps_wt = <optimized out>
        _mps_w = 133143986160
#11 0x00005555559061d4 in dflt_scan_obj
    (ss=0x7fffffff9fc8, base_start=0x7fff89f0dff0, base_limit=0x7fff89f0f000, closure=0x0)
    at ../../emacs/src/igc.c:1888
        obj_ = 0x7fff89f0dff0
        res = 0
        base = 0x7fff89f0dff0
        client = 0x7fff89f0dff0
        header = 0x7fff89f0dff0
        _ss = 0x7fffffff9fc8
        _mps_zs = 22
        _mps_ufs = 549755813896
        _mps_wt = <optimized out>
        _mps_w = 133143986160
#12 0x0000555555906619 in dflt_scanx
    (ss=0x7fffffff9fc8, base_start=0x7fff89f0d000, base_limit=0x7fff89f0f000, closure=0x0)
    at ../../emacs/src/igc.c:1951
        res = 0
        base = 0x7fff89f0dff0
--Type <RET> for more, q to quit, c to continue without paging--
        _ss = 0x7fffffff9fc8
        _mps_zs = 22
        _mps_ufs = 549755813896
        _mps_wt = <optimized out>
        _mps_w = 133143986160
#13 0x00005555559066b8 in dflt_scan
    (ss=0x7fffffff9fc8, base_start=0x7fff89f0d000, base_limit=0x7fff89f0f000)
    at ../../emacs/src/igc.c:1962
        res = 0
        _ss = 0x7fffffff9fc8
        _mps_zs = 22
        _mps_ufs = 0
        _mps_wt = <optimized out>
        _mps_w = 133143986160
#14 0x00005555559c25bf in TraceScanFormat
    (limit=0x7fff89f0f000, base=0x7fff89f0d000, ss=0x7fffffff9fc0)
    at /home/oscar/dev/other/mps/code/trace.c:1539
#15 amcSegScan (totalReturn=0x7fffffff9fbc, seg=0x7fffb82b3340, ss=0x7fffffff9fc0)
    at /home/oscar/dev/other/mps/code/poolamc.c:1440
        base = 0x7fff89f0d000
        limit = 0x7fff89f0f000
        format = 0x7fffe8000388
        pool = <optimized out>
        amc = <optimized out>
        res = <optimized out>
        buffer = 0x5555559bf6d8 <SegScan+56>
--Type <RET> for more, q to quit, c to continue without paging--
#16 0x00005555559ee4f9 in traceScanSegRes
    (ts=ts@entry=1, rank=rank@entry=1, arena=arena@entry=0x7ffff7fbf000, seg=seg@entry=0x7fffb82b3340)
    at /home/oscar/dev/other/mps/code/trace.c:1205
        ssStruct = {
          sig = 1368771141,
          ss_s = {
            _zs = 22,
            _w = 133143986160,
            _ufs = 549755813896
          },
          arena = 0x7ffff7fbf000,
          formatScan = 0x555555906660 <dflt_scan>,
          areaScan = 0x555555980ca0 <traceNoAreaScan>,
          areaScanClosure = 0x7ffff7fbf000,
          fix = 0x555555982120 <SegFix>,
          fixClosure = 0x0,
          traces = 1,
          rank = 1,
          wasMarked = 0,
          fixedSummary = 0,
          scannedSize = 8192
        }
        ss = 0x7fffffff9fc0
        wasTotal = 1
        white = 133143986160
        res = <optimized out>
--Type <RET> for more, q to quit, c to continue without paging--
#17 0x00005555559ee6ea in traceScanSeg (ts=1, rank=1, arena=0x7ffff7fbf000, seg=0x7fffb82b3340)
    at /home/oscar/dev/other/mps/code/trace.c:1267
        res = <optimized out>
#18 0x00005555559ef0c4 in TraceAdvance (trace=trace@entry=0x7ffff7fbfaa8)
    at /home/oscar/dev/other/mps/code/trace.c:1728
        res = <optimized out>
        seg = 0x7fffb82b3340
        rank = 1
        arena = <optimized out>
        oldWork = <optimized out>
        newWork = <optimized out>
#19 0x00005555559ef754 in TracePoll
    (workReturn=workReturn@entry=0x7fffffffa198, collectWorldReturn=collectWorldReturn@entry=0x7fffffffa194, globals=globals@entry=0x7ffff7fbf008, collectWorldAllowed=<optimized out>)
    at /home/oscar/dev/other/mps/code/trace.c:1849
        trace = 0x7ffff7fbfaa8
        arena = 0x7ffff7fbf000
        oldWork = 21021000
        newWork = <optimized out>
        work = <optimized out>
        endWork = 21201780
#20 0x00005555559ef94b in ArenaPoll (globals=globals@entry=0x7ffff7fbf008)
    at /home/oscar/dev/other/mps/code/global.c:745
        arena = 0x7ffff7fbf000
        start = 127960946
        worldCollected = 0
--Type <RET> for more, q to quit, c to continue without paging--
        moreWork = <optimized out>
        workWasDone = 1
        tracedWork = 188224
#21 0x00005555559efce7 in mps_ap_fill (p_o=0x7fffffffa320, mps_ap=0x7fffe8001980, size=24)
    at /home/oscar/dev/other/mps/code/mpsi.c:1097
        _sc = {
          jumpBuffer = {{
              __jmpbuf = {140737085708576, 7934441737627226205, 140737488341000, 140737488346136, 93825011090592, 93824998081432, 7934441737587380317, 4272113373193949277},
              __mask_was_saved = 0,
              __saved_mask = {
                __val = {8589988184, 140735675617355, 53592, 93824998129552, 46912143837648, 8, 1216, 140735675620139, 53592, 93825011044696, 53592, 93824998129552, 8, 24, 140737488331504, 93824996095173}
              }
            }}
        }
        buf = 0x7fffe8001920
        arena = 0x7ffff7fbf000
        p = 0xd158
        res = <optimized out>
#22 0x000055555590b0c2 in alloc_impl (size=24, type=IGC_OBJ_CONS, ap=0x7fffe8001980)
    at ../../emacs/src/igc.c:3802
        res = 21845
        p = 0x0
#23 0x000055555590b1b4 in alloc (size=24, type=IGC_OBJ_CONS) at ../../emacs/src/igc.c:3830
#24 0x000055555590b267 in igc_make_cons (car=XIL(0x2aaa95ab49d0), cdr=XIL(0x7fffeccdc75c))
--Type <RET> for more, q to quit, c to continue without paging--
    at ../../emacs/src/igc.c:3859
        cons = 0x0
#25 0x00005555558022c0 in Fcons (car=XIL(0x2aaa95ab49d0), cdr=XIL(0x7fffeccdc75c))
    at ../../emacs/src/alloc.c:2955
#26 0x0000555555842ced in funcall_lambda (fun=XIL(0x7fff93f3e2a5), nargs=1, arg_vector=0x7fffffffa5d8)
    at ../../emacs/src/eval.c:3324
        arg = XIL(0x7fffeccdc75c)
        next = XIL(0x2aaa95ab49d0)
        syms_left = XIL(0x7fffec95ce6b)
        lexenv = XIL(0x7fffc0fb14cb)
        count = {
          bytes = 1152
        }
        i = 1
        optional = false
        rest = false
        previous_rest = false
        val = XIL(0)
#27 0x0000555555841da2 in funcall_general (fun=XIL(0x7fff93f3e2a5), numargs=1, args=0x7fffffffa5d8)
    at ../../emacs/src/eval.c:3050
        original_fun = XIL(0x7fff93f3e2a5)
#28 0x0000555555842064 in Ffuncall (nargs=2, args=0x7fffffffa5d0) at ../../emacs/src/eval.c:3099
        count = {
          bytes = 1120
        }
        val = XIL(0)
--Type <RET> for more, q to quit, c to continue without paging--
#29 0x0000555555854850 in mapcar1
    (leni=15, vals=0x7fffffffa660, fn=XIL(0x7fff93f3e2a5), seq=XIL(0x7fff93f3e44b))
    at ../../emacs/src/fns.c:3373
        dummy = XIL(0)
        i = 12
        tail = XIL(0x7fff93f3e56b)
#30 0x0000555555854fde in Fmapcar (function=XIL(0x7fff93f3e2a5), sequence=XIL(0x7fff93f3e44b))
    at ../../emacs/src/fns.c:3493
        sa_avail = 16264
        sa_count = {
          bytes = 1120
        }
        leni = 15
        args = 0x7fffffffa660
        nmapped = 140737488332592
        ret = XIL(0x555555839828)
#31 0x0000555555840b20 in eval_sub (form=XIL(0x7fffeded0a33)) at ../../emacs/src/eval.c:2607
        i = 2
        maxargs = 2
        args_left = XIL(0)
        numargs = 2
        original_fun = XIL(0x2aaa6a8789a0)
        original_args = XIL(0x7fffeded0cab)
        count = {
          bytes = 1088
        }
--Type <RET> for more, q to quit, c to continue without paging--
        fun = XIL(0x5555566b7265)
        val = XIL(0x7fffffffa800)
        funcar = XIL(0)
        argvals = {XIL(0x7fff93f3e2a5), XIL(0x7fff93f3e44b), XIL(0x2420000026600), XIL(0x2440000027000), XIL(0x555556ae8628), XIL(0x7ffff76dc739), XIL(0x555556738000), XIL(0)}
#32 0x000055555583ceb5 in Flet (args=XIL(0x7fffedecf953)) at ../../emacs/src/eval.c:1084
        temps = 0x7fffffffa870
        tem = XIL(0x5555566b47a5)
        lexenv = XIL(0x135584a4ab)
        elt = XIL(0x7fffeded0283)
        count = {
          bytes = 1088
        }
        argnum = 0
        sa_avail = 16368
        sa_count = {
          bytes = 1088
        }
        varlist = XIL(0x7fffeded029b)
        varlist_len = 2
        nvars = 2
#33 0x0000555555840798 in eval_sub (form=XIL(0x7fffedecf2cb)) at ../../emacs/src/eval.c:2555
        args_left = XIL(0x7fffedecf953)
        numargs = 2
        original_fun = XIL(0xe1c0)
        original_args = XIL(0x7fffedecf953)
--Type <RET> for more, q to quit, c to continue without paging--
        count = {
          bytes = 1056
        }
        fun = XIL(0x5555566b47a5)
        val = XIL(0x7fffb61b20b0)
        funcar = XIL(0x555555af3f90)
        argvals = {XIL(0x1ffffa9d0), XIL(0), XIL(0x7fff93f3d04b), XIL(0xd158), XIL(0x5555558179e4), XIL(0x555555af3f90), XIL(0x7fffffffa9e0), XIL(0x555555817afb)}
#34 0x000055555583b494 in Fprogn (body=XIL(0x7fffedecf2e3)) at ../../emacs/src/eval.c:443
        form = XIL(0x7fffedecf2cb)
        val = XIL(0)
#35 0x000055555583d0a8 in Flet (args=XIL(0x7fffedecddfb)) at ../../emacs/src/eval.c:1113
        temps = 0x7fffffffaa90
        tem = XIL(0)
        lexenv = XIL(0x7fff93f3d04b)
        elt = XIL(0x2aaa97797290)
        count = {
          bytes = 1024
        }
        argnum = 1
        sa_avail = 16376
        sa_count = {
          bytes = 1024
        }
        varlist = XIL(0)
        varlist_len = 1
--Type <RET> for more, q to quit, c to continue without paging--
        nvars = 1
#36 0x0000555555840798 in eval_sub (form=XIL(0x7fffedecd043)) at ../../emacs/src/eval.c:2555
        args_left = XIL(0x7fffedecddfb)
        numargs = 3
        original_fun = XIL(0xe1c0)
        original_args = XIL(0x7fffedecddfb)
        count = {
          bytes = 992
        }
        fun = XIL(0x5555566b47a5)
        val = XIL(0x555555848d14)
        funcar = XIL(0x7fffffffac10)
        argvals = {XIL(0x7fffffffad80), XIL(0x555555981480), XIL(0x555556738000), XIL(0), XIL(0), XIL(0x7fffffffabe0), make_fixnum(23456248831157), XIL(0)}
#37 0x0000555555840a3e in eval_sub (form=XIL(0x7fffede44f43)) at ../../emacs/src/eval.c:2592
        i = 0
        maxargs = 1
        args_left = XIL(0x7fffede4724b)
        numargs = 1
        original_fun = XIL(0x2aaa6a87dd60)
        original_args = XIL(0x7fffede4724b)
        count = {
          bytes = 960
        }
        fun = XIL(0x5555566b6cc5)
        val = XIL(0x7fffffffad30)
--Type <RET> for more, q to quit, c to continue without paging--
        funcar = XIL(0)
        argvals = {XIL(0x7fffe8011458), XIL(0x7fffffffada8), XIL(0x5555559813c0), XIL(0x5555559813e0), XIL(0x7fffffffad98), XIL(0x7fffffffaea0), XIL(0x555556738000), XIL(0)}
#38 0x0000555555842835 in apply_lambda (fun=XIL(0x7fffbc35adc5), args=XIL(0x7fffede44c4b), count=...)
    at ../../emacs/src/eval.c:3216
        i = 0
        arg_vector = 0x7fffffffada0
        tem = XIL(0x7fffede44f43)
        sa_avail = 16368
        sa_count = {
          bytes = 960
        }
        numargs = 2
        args_left = XIL(0x7fffede44f5b)
#39 0x0000555555840d36 in eval_sub (form=XIL(0x7fffede4495b)) at ../../emacs/src/eval.c:2651
        original_fun = XIL(0x2aaa961a0fa8)
        original_args = XIL(0x7fffede44c4b)
        count = {
          bytes = 928
        }
        fun = XIL(0x7fffbc35adc5)
        val = XIL(0x7fffb61b20b0)
        funcar = XIL(0x555555af3f90)
        argvals = {XIL(0x184183dd0), XIL(0), XIL(0x7fffec29f443), XIL(0xd158), XIL(0x5555558179e4), XIL(0x555555af3f90), XIL(0x7fffffffaee0), XIL(0x555555817afb)}
#40 0x000055555583b494 in Fprogn (body=XIL(0)) at ../../emacs/src/eval.c:443
--Type <RET> for more, q to quit, c to continue without paging--
        form = XIL(0x7fffede4495b)
        val = XIL(0)
#41 0x0000555555842f49 in funcall_lambda (fun=XIL(0x7fffede44245), nargs=0, arg_vector=0x7fffffffb020)
    at ../../emacs/src/eval.c:3356
        syms_left = XIL(0)
        lexenv = XIL(0x7fffec29f443)
        count = {
          bytes = 896
        }
        i = 0
        optional = false
        rest = false
        previous_rest = false
        val = XIL(0x23)
#42 0x000055555584289b in apply_lambda (fun=XIL(0x7fffede44245), args=XIL(0), count=...)
    at ../../emacs/src/eval.c:3221
        arg_vector = 0x7fffffffb020
        tem = XIL(0x219770bee0)
        sa_avail = 16384
        sa_count = {
          bytes = 896
        }
        numargs = 0
        args_left = XIL(0)
#43 0x0000555555840d36 in eval_sub (form=XIL(0x7fffede43b9b)) at ../../emacs/src/eval.c:2651
        original_fun = XIL(0x2aaa9770bee0)
--Type <RET> for more, q to quit, c to continue without paging--
        original_args = XIL(0)
        count = {
          bytes = 864
        }
        fun = XIL(0x7fffede44245)
        val = XIL(0x7fff93f3cfc0)
        funcar = make_fixnum(23456248816738)
        argvals = {XIL(0x7fffffffb150), XIL(0x55555584f9f5), XIL(0x7fff93f3cfdb), XIL(0x2aaa961dc2d8), XIL(0x555556738000), XIL(0), XIL(0), XIL(0x7fff93f3cfc3)}
#44 0x000055555583cac0 in FletX (args=XIL(0x7fffec978b93)) at ../../emacs/src/eval.c:1021
        li = {
          tortoise = XIL(0x7fffec978c13),
          max = 2,
          n = 0,
          q = 2
        }
        var = XIL(0x2aaa9a427760)
        val = XIL(0x7fffffffb250)
        elt = XIL(0x7fffede43543)
        lexenv = XIL(0x7fff93f3d01b)
        count = {
          bytes = 864
        }
        varlist = XIL(0x7fffec978c13)
#45 0x0000555555840798 in eval_sub (form=XIL(0x7fffec978b33)) at ../../emacs/src/eval.c:2555
        args_left = XIL(0x7fffec978b93)
--Type <RET> for more, q to quit, c to continue without paging--
        numargs = 2
        original_fun = XIL(0xe1f8)
        original_args = XIL(0x7fffec978b93)
        count = {
          bytes = 832
        }
        fun = XIL(0x5555566b4745)
        val = XIL(0x5555567504a0)
        funcar = XIL(0x7fffffffdc18)
        argvals = {XIL(0x7ffff7fbf000), XIL(0x5555559e601c), XIL(0x18), XIL(0x7fffe80003f8), XIL(0x7fffffffb398), XIL(0x7ffff7fbf000), XIL(0x7fffe8000110), XIL(0x7fffffffc808)}
#46 0x000055555583b34d in Fif (args=XIL(0x7fffec978a53)) at ../../emacs/src/eval.c:398
        cond = XIL(0x38)
#47 0x0000555555840798 in eval_sub (form=XIL(0x7fffec9789cb)) at ../../emacs/src/eval.c:2555
        args_left = XIL(0x7fffec978a53)
        numargs = 3
        original_fun = XIL(0xc6a0)
        original_args = XIL(0x7fffec978a53)
        count = {
          bytes = 800
        }
        fun = XIL(0x5555566b40e5)
        val = make_fixnum(23456249031744)
        funcar = XIL(0x7fffffffb4b0)
        argvals = {XIL(0x7fffffffb470), make_fixnum(23456249023624), XIL(0x5b4ad3), XIL(0x18), XIL(0x300000018), XIL(0x7fff93f3d018), XIL(0x18), XIL(0x1)}
--Type <RET> for more, q to quit, c to continue without paging--
#48 0x000055555583b494 in Fprogn (body=XIL(0)) at ../../emacs/src/eval.c:443
        form = XIL(0x7fffec9789cb)
        val = XIL(0)
#49 0x000055555583ccb0 in FletX (args=XIL(0x7fffec97874b)) at ../../emacs/src/eval.c:1046
        var = XIL(0x2aaa96240a98)
        val = XIL(0x38)
        elt = XIL(0x7fffec978a3b)
        lexenv = XIL(0x7fffec29f443)
        count = {
          bytes = 768
        }
        varlist = XIL(0)
#50 0x0000555555840798 in eval_sub (form=XIL(0x7fffec978693)) at ../../emacs/src/eval.c:2555
        args_left = XIL(0x7fffec97874b)
        numargs = 2
        original_fun = XIL(0xe1f8)
        original_args = XIL(0x7fffec97874b)
        count = {
          bytes = 736
        }
        fun = XIL(0x5555566b4745)
        val = XIL(0x55555669b880)
        funcar = XIL(0x7fffffffb670)
        argvals = {XIL(0x7fffffffb650), XIL(0x7fffe8001980), XIL(0x300000000), XIL(0x18), XIL(0x555556738000), XIL(0), XIL(0), XIL(0x2e0)}
#51 0x000055555583de53 in internal_lisp_condition_case
--Type <RET> for more, q to quit, c to continue without paging--
    (var=XIL(0), bodyform=XIL(0x7fffec978693), handlers=XIL(0x7fffec9786ab))
    at ../../emacs/src/eval.c:1544
        clause = XIL(0x7fffec978763)
        condition = XIL(0x7fff93f3cf7b)
        c = 0x7fffefb28298
        clauses_volatile = 0x7fffffffb6f0
        pcl = 0x7fffffffb6f8
        oldhandlerlist = 0x7fffec0289e8
        clausenb = 2
        success_handler = XIL(0)
        clauses = 0x7fffffffb6f0
        var_volatile = XIL(0)
        val = XIL(0x7fffffffb7a0)
        handler_body = XIL(0x555556deab60)
        count = {
          bytes = 736
        }
#52 0x000055555583d951 in Fcondition_case (args=XIL(0x7fffec9783d3)) at ../../emacs/src/eval.c:1443
        var = XIL(0)
        bodyform = XIL(0x7fffec978693)
        handlers = XIL(0x7fffec9786ab)
#53 0x0000555555840798 in eval_sub (form=XIL(0x7fffec9781b3)) at ../../emacs/src/eval.c:2555
        args_left = XIL(0x7fffec9783d3)
        numargs = 3
        original_fun = XIL(0x6f20)
        original_args = XIL(0x7fffec9783d3)
--Type <RET> for more, q to quit, c to continue without paging--
        count = {
          bytes = 704
        }
        fun = XIL(0x5555566b4a45)
        val = XIL(0x7fffb61b20b0)
        funcar = XIL(0x555555af3f90)
        argvals = {XIL(0x193f3cea3), XIL(0), XIL(0x7fffec29f443), XIL(0xd158), XIL(0x5555558179e4), XIL(0x555555af3f90), XIL(0x7fffffffb8f0), XIL(0x555555817afb)}
#54 0x000055555583b494 in Fprogn (body=XIL(0)) at ../../emacs/src/eval.c:443
        form = XIL(0x7fffec9781b3)
        val = XIL(0)
#55 0x0000555555842f49 in funcall_lambda (fun=XIL(0x7fffec977e75), nargs=0, arg_vector=0x7fffffffba30)
    at ../../emacs/src/eval.c:3356
        syms_left = XIL(0)
        lexenv = XIL(0x7fffec29f443)
        count = {
          bytes = 672
        }
        i = 0
        optional = false
        rest = false
        previous_rest = false
        val = make_fixnum(34910567923712)
#56 0x000055555584289b in apply_lambda (fun=XIL(0x7fffec977e75), args=XIL(0), count=...)
    at ../../emacs/src/eval.c:3221
        arg_vector = 0x7fffffffba30
--Type <RET> for more, q to quit, c to continue without paging--
        tem = XIL(0x219623fc48)
        sa_avail = 16384
        sa_count = {
          bytes = 672
        }
        numargs = 0
        args_left = XIL(0)
#57 0x0000555555840d36 in eval_sub (form=XIL(0x7fffec977a23)) at ../../emacs/src/eval.c:2651
        original_fun = XIL(0x2aaa9623fc48)
        original_args = XIL(0)
        count = {
          bytes = 640
        }
        fun = XIL(0x7fffec977e75)
        val = XIL(0x4590)
        funcar = XIL(0x7fffffffbb80)
        argvals = {XIL(0x280), XIL(0x280), XIL(0x555556738000), XIL(0), XIL(0), XIL(0x7fffffffbb50), make_fixnum(23456248831157), XIL(0xffffbb60)}
#58 0x0000555555840a3e in eval_sub (form=XIL(0x7fffec976bfb)) at ../../emacs/src/eval.c:2592
        i = 2
        maxargs = 3
        args_left = XIL(0x7fffec97776b)
        numargs = 3
        original_fun = XIL(0x2aaa958f80b0)
        original_args = XIL(0x7fffec977003)
        count = {
--Type <RET> for more, q to quit, c to continue without paging--
          bytes = 608
        }
        fun = XIL(0x5555566ab025)
        val = XIL(0)
        funcar = XIL(0x555555af3f90)
        argvals = {XIL(0x7fffed4cb0ad), XIL(0x4590), XIL(0x7fff93f3cf63), XIL(0xd158), XIL(0x5555558179e4), XIL(0x555555af3f90), XIL(0x7fffffffbc90), XIL(0x555555817afb)}
#59 0x000055555583b494 in Fprogn (body=XIL(0)) at ../../emacs/src/eval.c:443
        form = XIL(0x7fffec976bfb)
        val = XIL(0)
#60 0x000055555583d0a8 in Flet (args=XIL(0x7fffec97615b)) at ../../emacs/src/eval.c:1113
        temps = 0x7fffffffbd40
        tem = make_fixnum(0)
        lexenv = XIL(0x7fff93f3cf63)
        elt = XIL(0x7fffec976be3)
        count = {
          bytes = 576
        }
        argnum = 2
        sa_avail = 16368
        sa_count = {
          bytes = 576
        }
        varlist = XIL(0)
        varlist_len = 2
        nvars = 2
--Type <RET> for more, q to quit, c to continue without paging--
#61 0x0000555555840798 in eval_sub (form=XIL(0x7fffec975e3b)) at ../../emacs/src/eval.c:2555
        args_left = XIL(0x7fffec97615b)
        numargs = 3
        original_fun = XIL(0xe1c0)
        original_args = XIL(0x7fffec97615b)
        count = {
          bytes = 544
        }
        fun = XIL(0x5555566b47a5)
        val = XIL(0x7ffff7fbf000)
        funcar = XIL(0x7fffec975e23)
        argvals = {XIL(0x7ffff7fbf000), XIL(0x7fffbe437045), XIL(0x7fffe0a702c0), XIL(0x7ffff7fbf658), XIL(0x7ffff7fbf000), XIL(0x5555559e601c), XIL(0x7fffb817a3a8), XIL(0x5555559ed408)}
#62 0x000055555583b494 in Fprogn (body=XIL(0x7fffec975e53)) at ../../emacs/src/eval.c:443
        form = XIL(0x7fffec975e3b)
        val = XIL(0)
#63 0x000055555583b4c4 in prog_ignore (body=XIL(0x7fffec975b23)) at ../../emacs/src/eval.c:454
#64 0x000055555583d111 in Fwhile (args=XIL(0x7fffec975683)) at ../../emacs/src/eval.c:1134
        test = XIL(0x7fffec975b0b)
        body = XIL(0x7fffec975b23)
#65 0x0000555555840798 in eval_sub (form=XIL(0x7fffec9751f3)) at ../../emacs/src/eval.c:2555
        args_left = XIL(0x7fffec975683)

        numargs = 3
        original_fun = XIL(0x2aaa95906448)
        original_args = XIL(0x7fffec975683)
        count = {
--Type <RET> for more, q to quit, c to continue without paging--
          bytes = 512
        }
        fun = XIL(0x5555566b4805)
        val = XIL(0x7fffb61b20b0)
        funcar = XIL(0x555555af3f90)
        argvals = {XIL(0x1ffffc060), XIL(0), XIL(0x7fff93f3cea3), XIL(0xd158), XIL(0x5555558179e4), XIL(0x555555af3f90), XIL(0x7fffffffc070), XIL(0x555555817afb)}
#66 0x000055555583b494 in Fprogn (body=XIL(0)) at ../../emacs/src/eval.c:443
        form = XIL(0x7fffec9751f3)
        val = XIL(0)
#67 0x000055555583d0a8 in Flet (args=XIL(0x7fffec974853)) at ../../emacs/src/eval.c:1113
        temps = 0x7fffffffc120
        tem = XIL(0)
        lexenv = XIL(0x7fff93f3cea3)
        elt = XIL(0x2aaa9623dad0)
        count = {
          bytes = 480
        }
        argnum = 3
        sa_avail = 16360
        sa_count = {
          bytes = 480
        }
        varlist = XIL(0)
        varlist_len = 3
        nvars = 3
--Type <RET> for more, q to quit, c to continue without paging--
#68 0x0000555555840798 in eval_sub (form=XIL(0x7fffec974333)) at ../../emacs/src/eval.c:2555
        args_left = XIL(0x7fffec974853)
        numargs = 2
        original_fun = XIL(0xe1c0)
        original_args = XIL(0x7fffec974853)
        count = {
          bytes = 448
        }
        fun = XIL(0x5555566b47a5)
        val = XIL(0x7fffffffc2a0)
        funcar = XIL(0)
        argvals = {XIL(0x7fff93f3cdd3), XIL(0x7fff93f3cd73), XIL(0x7fff93f3cdd3), XIL(0x7fff93f3cd73), XIL(0), make_fixnum(1000000000000), XIL(0x555556738000), XIL(0)}
#69 0x000055555583b494 in Fprogn (body=XIL(0)) at ../../emacs/src/eval.c:443
        form = XIL(0x7fffec974333)
        val = XIL(0)
#70 0x000055555583b36f in Fif (args=XIL(0x7fffec973573)) at ../../emacs/src/eval.c:399
        cond = XIL(0)
#71 0x0000555555840798 in eval_sub (form=XIL(0x7fffec973133)) at ../../emacs/src/eval.c:2555
        args_left = XIL(0x7fffec973573)
        numargs = 3
        original_fun = XIL(0xc6a0)
        original_args = XIL(0x7fffec973573)
        count = {
          bytes = 416
        }
--Type <RET> for more, q to quit, c to continue without paging--
        fun = XIL(0x5555566b40e5)
        val = XIL(0x7fffb61b20b0)
        funcar = XIL(0x555555af3f90)
        argvals = {XIL(0x1ffffc400), XIL(0), XIL(0x7fffec29f443), XIL(0xd158), XIL(0x5555558179e4), XIL(0x555555af3f90), XIL(0x7fffffffc430), XIL(0x555555817afb)}
#72 0x000055555583b494 in Fprogn (body=XIL(0)) at ../../emacs/src/eval.c:443
        form = XIL(0x7fffec973133)
        val = XIL(0)
#73 0x0000555555842f49 in funcall_lambda (fun=XIL(0x7fffec9726bd), nargs=0, arg_vector=0x7fffffffc818)
    at ../../emacs/src/eval.c:3356
        syms_left = XIL(0)
        lexenv = XIL(0x7fffec29f443)
        count = {
          bytes = 384
        }
        i = 0
        optional = false
        rest = false
        previous_rest = false
        val = XIL(0x555555ae8398)
#74 0x0000555555841da2 in funcall_general (fun=XIL(0x7fffec9726bd), numargs=0, args=0x7fffffffc818)
    at ../../emacs/src/eval.c:3050
        original_fun = XIL(0x2aaa9623a0a0)
#75 0x0000555555842064 in Ffuncall (nargs=1, args=0x7fffffffc810) at ../../emacs/src/eval.c:3099
        count = {
          bytes = 352
--Type <RET> for more, q to quit, c to continue without paging--
        }
        val = make_fixnum(0)
#76 0x000055555584112d in Fapply (nargs=2, args=0x7fffffffc810) at ../../emacs/src/eval.c:2724
        i = 140736340922707
        funcall_nargs = 56
        funcall_args = 0x0
        spread_arg = XIL(0)
        fun = XIL(0x2aaa9623a0a0)
        sa_avail = 16384
        sa_count = {
          bytes = 352
        }
        numargs = 0
        retval = XIL(0x567d38e0)
#77 0x00005555558425ee in funcall_subr (subr=0x5555566b4ce0 <Sapply>, numargs=2, args=0x7fffffffc810)
    at ../../emacs/src/eval.c:3190
        maxargs = -2
        fun = XIL(0x555555839828)
#78 0x0000555555841d56 in funcall_general (fun=XIL(0x5555566b4ce5), numargs=2, args=0x7fffffffc810)
    at ../../emacs/src/eval.c:3046
        original_fun = XIL(0x48a0)
#79 0x0000555555842064 in Ffuncall (nargs=3, args=0x7fffffffc808) at ../../emacs/src/eval.c:3099
        count = {
          bytes = 320
        }
        val = make_fixnum(23456248827543)
--Type <RET> for more, q to quit, c to continue without paging--
#80 0x00007fffe0a652c9 in F74696d65722d6576656e742d68616e646c6572_timer_event_handler_0 ()
    at /home/oscar/dev/emacs/igc-debug/src/../native-lisp/31.0.50-25e6c268/preloaded/timer-3ee7cfd9-faf18a90.eln
#81 0x0000555555842394 in funcall_subr (subr=0x7fffec024b60, numargs=1, args=0x7fffffffc9c8)
    at ../../emacs/src/eval.c:3167
        argbuf = {XIL(0x7fffec024b65), XIL(0x7fffffffc8b0), XIL(0x555556738000), XIL(0), XIL(0), XIL(0x13ffffc8d0), XIL(0x7fffec024b65), XIL(0x7fffffffc8e0)}
        a = 0x7fffffffc9c8
        maxargs = 1
        fun = XIL(0x555555839828)
#82 0x0000555555841d56 in funcall_general (fun=XIL(0x7fffec024b65), numargs=1, args=0x7fffffffc9c8)
    at ../../emacs/src/eval.c:3046
        original_fun = XIL(0x150e0)
#83 0x0000555555842064 in Ffuncall (nargs=2, args=0x7fffffffc9c0) at ../../emacs/src/eval.c:3099
        count = {
          bytes = 224
        }
        val = XIL(0x150e0)
#84 0x000055555576e3e2 in timer_check_2 (timers=XIL(0x7fff93f3c8cb), idle_timers=XIL(0x7fff93f3c95b))
    at ../../emacs/src/keyboard.c:4820
        count = {
          bytes = 192
        }
        old_deactivate_mark = XIL(0)
        chosen_timer = XIL(0x7fffbe437045)
        timer = XIL(0x7fffbe437045)
--Type <RET> for more, q to quit, c to continue without paging--
        idle_timer = XIL(0x7fffedd1d0c5)
        ripe = true
        timer_ripe = true
        idle_timer_ripe = true
        difference = {
          tv_sec = 0,
          tv_nsec = 527695107
        }
        timer_difference = {
          tv_sec = 0,
          tv_nsec = 527695107
        }
        idle_timer_difference = {
          tv_sec = 0,
          tv_nsec = 511956257
        }
        now = {
          tv_sec = 1732645572,
          tv_nsec = 273958132
        }
        idleness_now = {
          tv_sec = 0,
          tv_nsec = 636956257
        }
#85 0x000055555576e527 in timer_check () at ../../emacs/src/keyboard.c:4885
        nexttime = {
--Type <RET> for more, q to quit, c to continue without paging--
          tv_sec = 93824995782329,
          tv_nsec = 363641187
        }
        timers = XIL(0x7fff93f3c8b3)
        idle_timers = XIL(0x7fff93f3c943)
        tem = XIL(0)
#86 0x00005555558c556b in wait_reading_process_output
    (time_limit=30, nsecs=0, read_kbd=-1, do_display=true, wait_for_cell=XIL(0), wait_proc=0x0, just_wait_proc=0) at ../../emacs/src/process.c:5433
        old_timers_run = 5142
        process_skipped = false
        wrapped = true
        channel_start = 21
        child_fd = 13
        last_read_channel = 20
        channel = 21
        nfds = 1
        Available = {
          fds_bits = {0 <repeats 16 times>}
        }
        Writeok = {
          fds_bits = {0 <repeats 16 times>}
        }
        check_write = true
        check_delay = 2
        no_avail = false
--Type <RET> for more, q to quit, c to continue without paging--
        xerrno = 11
        proc = XIL(0x7fffec0a9005)
        timeout = {
          tv_sec = 29,
          tv_nsec = 363641187
        }
        end_time = {
          tv_sec = 1732645601,
          tv_nsec = 637403875
        }
        timer_delay = {
          tv_sec = 0,
          tv_nsec = 75496097
        }
        got_output_end_time = {
          tv_sec = 0,
          tv_nsec = -1
        }
        wait = TIMEOUT
        got_some_output = 111340
        prev_wait_proc_nbytes_read = 0
        retry_for_async = false
        count = {
          bytes = 160
        }
        now = {
--Type <RET> for more, q to quit, c to continue without paging--
          tv_sec = 1732645572,
          tv_nsec = 273762688
        }
#87 0x00005555555b3552 in sit_for (timeout=make_fixnum(30), reading=true, display_option=1)
    at ../../emacs/src/dispnew.c:6362
        sec = 30
        nsec = 0
        do_display = true
        curbuf_eq_winbuf = true
        nbytes = 21845
#88 0x0000555555769966 in read_char
    (commandflag=1, map=XIL(0x7fff93a23273), prev_event=XIL(0), used_mouse_menu=0x7fffffffd41f, end_time=0x0) at ../../emacs/src/keyboard.c:2937
        tem0 = XIL(0xca90)
        timeout = 30
        count1 = {
          bytes = 128
        }
        delay_level = 4
        buffer_size = 54
        c = XIL(0)
        local_getcjmp = {{
            __jmpbuf = {0, 7934441734953357405, 0, 140737488346136, 140737354125312, 93824998081432, 7934441734561189981, 4272114679796584541},
            __mask_was_saved = 0,
            __saved_mask = {
--Type <RET> for more, q to quit, c to continue without paging--
              __val = {93824996094498, 5850328, 24, 12884901912, 140735670268528, 24, 1, 140737488343728, 93824996126978, 0, 140737085708672, 17179857584, 24, 140735670268528, 1451047136, 17179857616}
            }
          }}
        save_jump = {{
            __jmpbuf = {0, 0, 0, 0, 0, 0, 0, 0},
            __mask_was_saved = 0,
            __saved_mask = {
              __val = {0 <repeats 16 times>}
            }
          }}
        tem = XIL(0x7fffffffd130)
        save = XIL(0x7fffb61b20b5)
        previous_echo_area_message = XIL(0)
        also_record = XIL(0)
        reread = false
        recorded = false
        polling_stopped_here = false
        orig_kboard = 0x555556924ec0
        jmpcount = {
          bytes = 128
        }
        c_volatile = XIL(0)
#89 0x000055555577c969 in read_key_sequence
    (keybuf=0x7fffffffd5d0, prompt=XIL(0), dont_downcase_last=false, can_return_switch_frame=true, fix_current_buffer=true, prevent_redisplay=false, disable_text_conversion_p=false)
--Type <RET> for more, q to quit, c to continue without paging--
    at ../../emacs/src/keyboard.c:10763
        interrupted_kboard = 0x555556924ec0
        interrupted_frame = 0x7fffe341bca0
        key = XIL(0xd430)
        used_mouse_menu = false
        echo_local_start = 0
        last_real_key_start = 0
        keys_local_start = 0
        new_binding = XIL(0x7fffffffd538)
        count = {
          bytes = 96
        }
        t = 0
        echo_start = 0
        keys_start = 0
        current_binding = XIL(0x7fff93a23273)
        first_unbound = 31
        mock_input = 0
        used_mouse_menu_history = {false <repeats 30 times>}
        fkey = {
          parent = XIL(0x7fffe3147cc3),
          map = XIL(0x7fffe3147cc3),
          start = 0,
          end = 0
        }
        keytran = {
--Type <RET> for more, q to quit, c to continue without paging--
          parent = XIL(0x7fffec00127b),
          map = XIL(0x7fffec00127b),
          start = 0,
          end = 0
        }
        indec = {
          parent = XIL(0x7fffe3147cab),
          map = XIL(0x7fffe3147cab),
          start = 0,
          end = 0
        }
        shift_translated = false
        delayed_switch_frame = XIL(0)
        original_uppercase = XIL(0)
        original_uppercase_position = -1
        disabled_conversion = false
        starting_buffer = 0x7fffb61b20b0
        fake_prefixed_keys = XIL(0)
        first_event = XIL(0)
        second_event = XIL(0)
#90 0x000055555576522c in command_loop_1 () at ../../emacs/src/keyboard.c:1435
        cmd = XIL(0x2aaa95abfe00)
        keybuf = {XIL(0x12a98), make_fixnum(107), XIL(0x7fffffffd660), XIL(0x55555581ba01), XIL(0x200000038), XIL(0), XIL(0), XIL(0xd158), XIL(0x7fffe3a959e4), XIL(0x7fffe3a959cb), XIL(0x7fffe3a959cb), XIL(0xd158), XIL(0x555555af3f90), XIL(0x7fffe1886988), XIL(0), XIL(0x555556745158), make_fixnum(23456248779936), XIL(0), XIL(0x7fffffffd6f0), XIL(0x55555581c579), XIL(0x7fffe188698d), XIL(0x256dea900), XIL(0), --Type <RET> for more, q to quit, c to continue without paging--
XIL(0xd158), XIL(0x555555af3f90), XIL(0x7fffe15c1c23), XIL(0x7fffe1de517b), XIL(0), XIL(0x7fffffffd730), XIL(0xd158)}
        i = 1
        last_pt = 12041
        prev_modiff = 19844
        prev_buffer = 0x7fffb61b20b0
#91 0x000055555583e13b in internal_condition_case
    (bfun=0x555555764dfd <command_loop_1>, handlers=XIL(0xa8), hfun=0x55555576427b <cmd_error>)
    at ../../emacs/src/eval.c:1618
        val = XIL(0x15460)
        c = 0x7fffe2a52120
#92 0x00005555557649c3 in command_loop_2 (handlers=XIL(0xa8)) at ../../emacs/src/keyboard.c:1174
        val = XIL(0x15460)
#93 0x000055555583d581 in internal_catch
    (tag=XIL(0x15460), func=0x555555764999 <command_loop_2>, arg=XIL(0xa8))
    at ../../emacs/src/eval.c:1297
        val = XIL(0x5555557610c0)
        c = 0x7fffe2a51fe8
#94 0x0000555555764955 in command_loop () at ../../emacs/src/keyboard.c:1152
#95 0x0000555555763d1d in recursive_edit_1 () at ../../emacs/src/keyboard.c:760
        count = {
          bytes = 32
        }
        val = XIL(0x7fffffffd950)
#96 0x0000555555763f49 in Frecursive_edit () at ../../emacs/src/keyboard.c:843
        count = {
--Type <RET> for more, q to quit, c to continue without paging--
          bytes = 0
        }
        buffer = XIL(0)
#97 0x000055555575f83e in main (argc=1, argv=0x7fffffffdc08) at ../../emacs/src/emacs.c:2646
        stack_bottom_variable = 0x7fffffffda40
        old_argc = 1
        dump_file = 0x0
        no_loadup = false
        junk = 0x0
        dname_arg = 0x0
        ch_to_dir = 0x0
        original_pwd = 0x0
        dump_mode = 0x0
        skip_args = 0
        temacs = 0x0
        attempt_load_pdump = true
        only_version = false
        rlim = {
          rlim_cur = 10022912,
          rlim_max = 18446744073709551615
        }
        lc_all = 0x0
        sockfd = -1
        module_assertions = false

Lisp Backtrace:

--Type <RET> for more, q to quit, c to continue without paging--
0x93f3e2a0 PVEC_CLOSURE
"mapcar" (0xffffa7a0)
"let" (0xffffa9f0)
"let" (0xffffac00)
"reverse" (0xffffad30)
"string-join" (0xffffaef0)
"mini-echo-concat-segments" (0xffffb020)
"let*" (0xffffb320)
"if" (0xffffb490)
"let*" (0xffffb680)
"condition-case" (0xffffb900)
"mini-echo-build-info" (0xffffba30)
"overlay-put" (0xffffbca0)
"let" (0xffffbec0)
"while" (0xffffc080)
"let" (0xffffc2a0)
"if" (0xffffc440)
"mini-echo-update" (0xffffc818)
"apply" (0xffffc810)
"timer-event-handler" (0xffffc9c8)


In GNU Emacs 31.0.50 (build 2, x86_64-pc-linux-gnu, X toolkit, cairo
 version 1.18.2) of 2024-11-25 built on sky
Repository revision: fad5e872ca05e45afa42ad5fc77b6890c051e4a6
Repository branch: scratch/igc
Windowing system distributor 'The X.Org Foundation', version 11.0.12101014
System Description: Debian GNU/Linux trixie/sid

Configured using:
 'configure CPPFLAGS=-I/home/oscar/lib/mps/include
 LDFLAGS=-L/home/oscar/lib/mps/lib --with-native-compilation
 --with-tree-sitter --without-toolkit-scroll-bars --with-x-toolkit=lucid
 --with-modules --without-imagemagick --with-mps=yes
 --enable-checking=yes,glyphs --enable-check-lisp-object-type
 'CFLAGS=-O0 -g3''

Configured features:
CAIRO DBUS FREETYPE GIF GLIB GMP GNUTLS GSETTINGS HARFBUZZ JPEG LIBOTF
LIBSELINUX LIBXML2 MODULES MPS NATIVE_COMP NOTIFY INOTIFY PDUMPER PNG
SECCOMP SOUND SQLITE3 THREADS TIFF TREE_SITTER WEBP X11 XAW3D XDBE XIM
XINPUT2 XPM LUCID ZLIB

Important settings:
  value of $LANG: es_ES.UTF-8
  locale-coding-system: utf-8-unix

Major mode: Lisp Interaction

Minor modes in effect:
  fancy-compilation-mode: t
  global-git-commit-mode: t
  pulsar-global-mode: t
  pulsar-mode: t
  evil-owl-mode: t
  evil-paredit-mode: t
  evil-local-mode: t
  mini-echo-mode: t
  global-hide-mode-line-mode: t
  hide-mode-line-mode: t
  pdf-occur-global-minor-mode: t
  TeX-PDF-mode: t
  key-chord-mode: t
  paredit-mode: t
  display-fill-column-indicator-mode: t
  vertico-multiform-mode: t
  marginalia-mode: t
  vertico-mode: t
  window-highlight-mode: t
  which-key-mode: t
  global-anzu-mode: t
  anzu-mode: t
  tooltip-mode: t
  global-eldoc-mode: t
  eldoc-mode: t
  show-paren-mode: t
  electric-indent-mode: t
  mouse-wheel-mode: t
  tool-bar-mode: t
  file-name-shadow-mode: t
  global-font-lock-mode: t
  font-lock-mode: t
  window-divider-mode: t
  minibuffer-regexp-mode: t
  column-number-mode: t
  line-number-mode: t
  indent-tabs-mode: t
  auto-composition-mode: t
  auto-encryption-mode: t
  auto-compression-mode: t

Load-path shadows:
/home/oscar/elisp/singles/flx hides /home/oscar/.emacs.d/elpa/flx-20240205.356/flx
/home/oscar/elisp/magit/lisp/magit-section hides /home/oscar/.emacs.d/elpa/magit-section-20241122.1431/magit-section
/home/oscar/elisp/singles/avy hides /home/oscar/.emacs.d/elpa/avy-20241101.1357/avy
/home/oscar/elisp/singles/which-key hides /home/oscar/dev/emacs/emacs/lisp/which-key
/home/oscar/elisp/singles/transient hides /home/oscar/dev/emacs/emacs/lisp/transient
/home/oscar/.emacs.d/elpa/ef-themes-1.9.0/theme-loaddefs hides /home/oscar/dev/emacs/emacs/lisp/theme-loaddefs

Features:
(solarized-selenized-dark-theme solarized-palettes solarized
solarized-faces company-posframe posframe ispell shadow sort mail-extr
emacsbug vertico-directory mule-util fussy meteo-radar flycheck
lp0-ts-mode lp0-mode symbol-overlay company-ctags find-file
company-fuzzy ht company aggressive-indent deft org-noter org-element
org-persist xdg org-id org-element-ast inline avl-tree org-protocol
org-capture org-refile org-crypt hl-todo etags-select etags fileloop
generator xref fancy-compilation ffap orgit org ob ob-tangle ob-ref
ob-lob ob-table ob-exp org-macro org-src sh-script smie executable
ob-comint org-pcomplete org-list org-footnote org-faces org-entities
noutline outline ob-emacs-lisp ob-core ob-eval org-cycle org-table ol
org-fold org-fold-core org-keys oc org-loaddefs org-version org-compat
org-macs magit-bookmark git-rebase magit-extras magit-sparse-checkout
magit-gitignore magit-ediff ediff magit-subtree magit-patch
magit-submodule magit-blame magit-stash magit-reflog magit-bisect
magit-push magit-pull magit-fetch magit-clone magit-remote magit-commit
magit-sequence magit-notes magit-worktree magit-tag magit-merge
magit-branch magit-reset magit-files magit-refs magit-status magit
magit-repos magit-apply magit-wip magit-log magit-diff smerge-mode diff
git-commit magit-core magit-autorevert autorevert filenotify
magit-margin magit-transient magit-process with-editor shell pcomplete
magit-mode transient magit-git magit-base which-func vc-git files-x
vc-dispatcher magit-section benchmark cursor-sensor pulsar pulse
evil-textobj-tree-sitter-core treesit evil-owl buffer-flip evil-paredit
evil-anzu evil evil-keybindings evil-integration evil-maps evil-commands
evil-digraphs reveal evil-jumps evil-command-window evil-types
evil-search evil-ex evil-macros evil-repeat evil-states evil-core
evil-common rect evil-vars mini-echo mini-echo-segments hide-mode-line
wgrep grep ag vc-svn find-dired s dash pdf-occur ibuf-ext ibuffer
ibuffer-loaddefs tablist tablist-filter semantic/wisent/comp
semantic/wisent semantic/wisent/wisent semantic/util-modes semantic/util
semantic semantic/tag semantic/lex semantic/fw mode-local find-func
cedet pdf-isearch let-alist pdf-misc imenu pdf-tools cus-edit cus-load
pdf-view bookmark jka-compr pdf-cache pdf-info tq pdf-util format-spec
pdf-macs image-mode exif preview reporter desktop frameset latex
latex-flymake flymake project compile comint ansi-osc ansi-color
tex-ispell tex-style tex dbus xml crm texmathp auctex key-chord comp
comp-cstr warnings comp-run comp-common cmake-mode paredit-menu paredit
edmacro kmacro server yasnippet lisp-mnt cl-extra help-mode psvn
wid-edit log-edit message sendmail yank-media puny rfc822 mml mml-sec
epa derived epg rfc6068 epg-config gnus-util text-property-search
time-date mm-decode mm-bodies mm-encode mail-parse rfc2231 rfc2047
rfc2045 mm-util ietf-drums mail-prsvr mailabbrev mail-utils gmm-utils
mailheader pcvs-util add-log diff-mode track-changes pp elp ediff-merg
ediff-mult ediff-wind ediff-diff ediff-help ediff-init ediff-util dired
dired-loaddefs display-fill-column-indicator vertico-multiform
marginalia vertico flx-rs-core flx-rs flx window-highlight color
face-remap nord-theme goto-chg avy rx ring highlight-parentheses
ws-butler which-key diminish cl anzu easy-mmode thingatpt tmr pcase
compat solar cal-dst cal-menu calendar cal-loaddefs finder-inf advice
auctex-autoloads tex-site casual-calc-autoloads casual-lib-autoloads
color-theme-sanityinc-tomorrow-autoloads company-posframe-autoloads
company-autoloads consult-ag-autoloads consult-flycheck-autoloads
consult-lsp-autoloads consult-org-roam-autoloads
consult-project-extra-autoloads consult-todo-autoloads
deadgrep-autoloads ef-themes-autoloads embark-consult-autoloads
consult-autoloads embark-autoloads evil-textobj-tree-sitter-autoloads
flutter-autoloads flycheck-autoloads fussy-autoloads flx-autoloads
hl-todo-autoloads hotfuzz-autoloads hyperstitional-themes-autoloads
lsp-dart-autoloads dart-mode-autoloads dap-mode-autoloads bui-autoloads
lsp-docker-autoloads lsp-treemacs-autoloads lsp-ui-autoloads
lsp-mode-autoloads f-autoloads marginalia-autoloads
markdown-mode-autoloads org-roam-autoloads magit-section-autoloads
emacsql-autoloads pdf-tools-autoloads pomm-autoloads alert-autoloads
log4e-autoloads gntp-autoloads shackle-autoloads spinner-autoloads
symbol-overlay-autoloads tablist-autoloads treemacs-autoloads
cfrs-autoloads posframe-autoloads ht-autoloads hydra-autoloads
lv-autoloads pfuture-autoloads ace-window-autoloads avy-autoloads
s-autoloads info dash-autoloads vertico-autoloads vundo-autoloads
wgrep-ag-autoloads wgrep-deadgrep-autoloads wgrep-autoloads
yaml-autoloads yeetube-autoloads package browse-url url url-proxy
url-privacy url-expand url-methods url-history url-cookie
generate-lisp-file url-domsuf url-util mailcap url-handlers url-parse
auth-source cl-seq eieio eieio-core cl-macs icons password-cache json
subr-x map byte-opt gv bytecomp byte-compile url-vars cl-loaddefs cl-lib
rmc iso-transl tooltip cconv eldoc paren electric uniquify ediff-hook
vc-hooks lisp-float-type elisp-mode mwheel term/x-win x-win
term/common-win x-dnd touch-screen tool-bar dnd fontset image regexp-opt
fringe tabulated-list replace newcomment text-mode lisp-mode prog-mode
register page tab-bar menu-bar rfn-eshadow isearch easymenu timer select
scroll-bar mouse jit-lock font-lock syntax font-core term/tty-colors
frame minibuffer nadvice seq simple cl-generic indonesian philippine
cham georgian utf-8-lang misc-lang vietnamese tibetan thai tai-viet lao
korean japanese eucjp-ms cp51932 hebrew greek romanian slovak czech
european ethiopic indian cyrillic chinese composite emoji-zwj charscript
charprop case-table epa-hook jka-cmpr-hook help abbrev obarray oclosure
cl-preloaded button loaddefs theme-loaddefs faces cus-face macroexp
files window text-properties overlay sha1 md5 base64 format env
code-pages mule custom widget keymap hashtable-print-readable backquote
threads dbusbind inotify dynamic-setting system-font-setting
font-render-setting cairo x-toolkit xinput2 x multi-tty move-toolbar
make-network-process native-compile mps emacs)

Memory information:
((conses 24 0 0) (symbols 56 0 0) (strings 40 0 0) (string-bytes 1 0)
 (vectors 24 0) (vector-slots 8 0 0) (floats 24 0 0)
 (intervals 64 0 0) (buffers 1000 0))





^ permalink raw reply	[flat|nested] 25+ messages in thread

* bug#74547: 31.0.50; igc: assertion failed in buffer.c
  2024-11-26 18:35 bug#74547: 31.0.50; igc: assertion failed in buffer.c Óscar Fuentes
@ 2024-11-27  6:54 ` Gerd Möllmann
  2024-12-01 10:49   ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 25+ messages in thread
From: Gerd Möllmann @ 2024-11-27  6:54 UTC (permalink / raw)
  To: Óscar Fuentes; +Cc: 74547, Pip Cet

Óscar Fuentes <oscarfv@telefonica.net> writes:

> While editing a .dart file with lsp-mode.

Thanks Oscar. That's a difficult one.

> #3  0x00005555559c1384 in mps_lib_assert_fail
>     (condition=0x555555a4a157 "size > 0", line=579, file=0x555555a47782 "buffer.c")
>     at /home/oscar/dev/other/mps/code/mpsliban.c:87
> #4  BufferFill
> #5  0x00005555559f2da0 in amcSegFix (seg=0x7fffb820d070, ss=0x7fffffff9fc0, refIO=0x7fffffff99d0)
>         trace = <optimized out>
> #6  0x0000555555990b8c in _mps_fix2 (mps_ss=0x7fffffff9fc8, mps_ref_io=0x7fffffff9a10)
>         res = <optimized out>
> #7  0x0000555555903cac in fix_lisp_obj (ss=0x7fffffff9fc8, pobj=0x7fff89f0e000)
>     at ../../emacs/src/igc.c:998
>         res = 32767
>         client = 0x7fff93f2f7d0
>         base = 0x7fff93f2f7d0
>         p = 0x7fff89f0e000
> --Type <RET> for more, q to quit, c to continue without paging--
>         word = 140735675561940
>         tag = 4
>         _ss = 0x7fffffff9fc8
>         _mps_zs = 22
>         _mps_ufs = 549755846664
>         _mps_wt = 32768
>         _mps_w = 133143986160
> #8  0x0000555555904160 in fix_array (ss=0x7fffffff9fc8, array=0x7fff89f0e000, n=6)
>     at ../../emacs/src/igc.c:1233
>         res = 30
>         i = 0
>         _ss = 0x7fffffff9fc8
>         _mps_zs = 22
>         _mps_ufs = 549755813896
>         _mps_wt = <optimized out>
>         _mps_w = 133143986160
> #9  0x000055555590674b in fix_vectorlike (ss=0x7fffffff9fc8, v=0x7fff89f0dff0)
>     at ../../emacs/src/igc.c:1974
>         res = 32767
>         size = 6
>         _ss = 0x7fffffff9fc8
>         _mps_zs = 22
>         _mps_ufs = 549755813896
>         _mps_wt = <optimized out>
>         _mps_w = 133143986160
> #10 0x0000555555908d53 in fix_vector (ss=0x7fffffff9fc8, v=0x7fff89f0dff0)
> --Type <RET> for more, q to quit, c to continue without paging--
>     at ../../emacs/src/igc.c:2646
>         obj_ = 0x7fff89f0dff0
>         res = 0
>         _ss = 0x7fffffff9fc8
>         _mps_zs = 22
>         _mps_ufs = 549755813896
>         _mps_wt = <optimized out>
>         _mps_w = 133143986160
> #11 0x00005555559061d4 in dflt_scan_obj
>     (ss=0x7fffffff9fc8, base_start=0x7fff89f0dff0,
>     base_limit=0x7fff89f0f000, closure=0x0)

I've stripped the rest of the backtrace because it's probably not
too relevant.

What Emacs is doing here is allocate a cons, which triggers a GC step
because the allocation point needs more memory. In this GC step, we
scans a memory area containing a vector (or vectorlike) containing 6
elements. The first element is a string for which MPS_FIX1 says it needs
to be passed to MPS_FIX2, but MPS_FIX2 aborts.

I have no idea why that is. I've added Pip in CC, maybe he has ideas.

> In GNU Emacs 31.0.50 (build 2, x86_64-pc-linux-gnu, X toolkit, cairo
>  version 1.18.2) of 2024-11-25 built on sky
> Repository revision: fad5e872ca05e45afa42ad5fc77b6890c051e4a6
> Repository branch: scratch/igc
> Windowing system distributor 'The X.Org Foundation', version 11.0.12101014
> System Description: Debian GNU/Linux trixie/sid
>
> Configured using:
>  'configure CPPFLAGS=-I/home/oscar/lib/mps/include
>  LDFLAGS=-L/home/oscar/lib/mps/lib --with-native-compilation
>  --with-tree-sitter --without-toolkit-scroll-bars --with-x-toolkit=lucid
>  --with-modules --without-imagemagick --with-mps=yes
>  --enable-checking=yes,glyphs --enable-check-lisp-object-type
>  'CFLAGS=-O0 -g3''

Could you please configure --with-mps=debug? That uses the debug version
of MPS which is more picky, but slower. Also,
--enable-checking=igc_debug is probably better. IIRC, that's not on by
default, and we probably don't need the other checks.

Maybe we some further hints that way.
  





^ permalink raw reply	[flat|nested] 25+ messages in thread

* bug#74547: 31.0.50; igc: assertion failed in buffer.c
  2024-11-27  6:54 ` Gerd Möllmann
@ 2024-12-01 10:49   ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2024-12-01 12:05     ` Gerd Möllmann
  0 siblings, 1 reply; 25+ messages in thread
From: Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-12-01 10:49 UTC (permalink / raw)
  To: Gerd Möllmann; +Cc: 74547, Óscar Fuentes

Gerd Möllmann <gerd.moellmann@gmail.com> writes:

> Óscar Fuentes <oscarfv@telefonica.net> writes:
>
>> While editing a .dart file with lsp-mode.
>
> Thanks Oscar. That's a difficult one.

I agree.

>> #3  0x00005555559c1384 in mps_lib_assert_fail
>>     (condition=0x555555a4a157 "size > 0", line=579, file=0x555555a47782 "buffer.c")
>>     at /home/oscar/dev/other/mps/code/mpsliban.c:87
>> #4  BufferFill
>> #5  0x00005555559f2da0 in amcSegFix (seg=0x7fffb820d070, ss=0x7fffffff9fc0, refIO=0x7fffffff99d0)
>>         trace = <optimized out>
>> #6  0x0000555555990b8c in _mps_fix2 (mps_ss=0x7fffffff9fc8, mps_ref_io=0x7fffffff9a10)
>>         res = <optimized out>
>> #7  0x0000555555903cac in fix_lisp_obj (ss=0x7fffffff9fc8, pobj=0x7fff89f0e000)
>>     at ../../emacs/src/igc.c:998
>>         res = 32767
>>         client = 0x7fff93f2f7d0
>>         base = 0x7fff93f2f7d0
>>         p = 0x7fff89f0e000
>> --Type <RET> for more, q to quit, c to continue without paging--
>>         word = 140735675561940
>>         tag = 4
>>         _ss = 0x7fffffff9fc8
>>         _mps_zs = 22
>>         _mps_ufs = 549755846664
>>         _mps_wt = 32768
>>         _mps_w = 133143986160
>> #8  0x0000555555904160 in fix_array (ss=0x7fffffff9fc8, array=0x7fff89f0e000, n=6)
>>     at ../../emacs/src/igc.c:1233
>>         res = 30
>>         i = 0
>>         _ss = 0x7fffffff9fc8
>>         _mps_zs = 22
>>         _mps_ufs = 549755813896
>>         _mps_wt = <optimized out>
>>         _mps_w = 133143986160
>> #9  0x000055555590674b in fix_vectorlike (ss=0x7fffffff9fc8, v=0x7fff89f0dff0)
>>     at ../../emacs/src/igc.c:1974
>>         res = 32767
>>         size = 6
>>         _ss = 0x7fffffff9fc8
>>         _mps_zs = 22
>>         _mps_ufs = 549755813896
>>         _mps_wt = <optimized out>
>>         _mps_w = 133143986160
>> #10 0x0000555555908d53 in fix_vector (ss=0x7fffffff9fc8, v=0x7fff89f0dff0)
>> --Type <RET> for more, q to quit, c to continue without paging--
>>     at ../../emacs/src/igc.c:2646
>>         obj_ = 0x7fff89f0dff0
>>         res = 0
>>         _ss = 0x7fffffff9fc8
>>         _mps_zs = 22
>>         _mps_ufs = 549755813896
>>         _mps_wt = <optimized out>
>>         _mps_w = 133143986160
>> #11 0x00005555559061d4 in dflt_scan_obj
>>     (ss=0x7fffffff9fc8, base_start=0x7fff89f0dff0,
>>     base_limit=0x7fff89f0f000, closure=0x0)
>
> I've stripped the rest of the backtrace because it's probably not
> too relevant.
>
> What Emacs is doing here is allocate a cons, which triggers a GC step
> because the allocation point needs more memory. In this GC step, we
> scans a memory area containing a vector (or vectorlike) containing 6
> elements. The first element is a string for which MPS_FIX1 says it needs
> to be passed to MPS_FIX2, but MPS_FIX2 aborts.
>
> I have no idea why that is. I've added Pip in CC, maybe he has ideas.

I think the relevant part is that the IGC header of the object passed to
_mps_fix2 is incorrect: it claims to have size 0.  This is often the
case when no traceable reference to an object was found in a previous GC
pass and the memory has been reused for other purposes.

So it seems there is a vector or pseudovector of size 6 that somehow
attempts to resurrect a freed object (in the first slot). Unfortunately,
6 is the usual size for Lisp closures, so it's a very common allocation
and we can't just breakpoint based on that size alone.

Do you have a core dump, Óscar? I think we need to look at the vector
and see whether we can figure out how it was allocated or modified.

I think it's unlikely this particular vector is a closure, FWIW, because
the first slot of a closure vector is always a fixnum.

Pip






^ permalink raw reply	[flat|nested] 25+ messages in thread

* bug#74547: 31.0.50; igc: assertion failed in buffer.c
  2024-12-01 10:49   ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2024-12-01 12:05     ` Gerd Möllmann
  2024-12-01 12:17       ` Gerd Möllmann
  0 siblings, 1 reply; 25+ messages in thread
From: Gerd Möllmann @ 2024-12-01 12:05 UTC (permalink / raw)
  To: Pip Cet; +Cc: 74547, Óscar Fuentes

Pip Cet <pipcet@protonmail.com> writes:

> I think it's unlikely this particular vector is a closure, FWIW, because
> the first slot of a closure vector is always a fixnum.

I agree.

I've now checked all the possible PVEC types, and the only ones that fit
size 6 are normal vectors, closures, or records. I also don't believe
that it's a closure because of the fixnum. And records (SQLite) seem a
bit unlikely.





^ permalink raw reply	[flat|nested] 25+ messages in thread

* bug#74547: 31.0.50; igc: assertion failed in buffer.c
  2024-12-01 12:05     ` Gerd Möllmann
@ 2024-12-01 12:17       ` Gerd Möllmann
  2024-12-01 12:30         ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2024-12-01 13:18         ` Óscar Fuentes
  0 siblings, 2 replies; 25+ messages in thread
From: Gerd Möllmann @ 2024-12-01 12:17 UTC (permalink / raw)
  To: Pip Cet; +Cc: 74547, Óscar Fuentes

Gerd Möllmann <gerd.moellmann@gmail.com> writes:

> Pip Cet <pipcet@protonmail.com> writes:
>
>> I think it's unlikely this particular vector is a closure, FWIW, because
>> the first slot of a closure vector is always a fixnum.
>
> I agree.
>
> I've now checked all the possible PVEC types, and the only ones that fit
> size 6 are normal vectors, closures, or records. I also don't believe
> that it's a closure because of the fixnum. And records (SQLite) seem a
> bit unlikely.

Hm, reading Oscar's report again - he was using LSP. Maybe it's
something in the parser.





^ permalink raw reply	[flat|nested] 25+ messages in thread

* bug#74547: 31.0.50; igc: assertion failed in buffer.c
  2024-12-01 12:17       ` Gerd Möllmann
@ 2024-12-01 12:30         ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2024-12-01 12:39           ` Gerd Möllmann
  2024-12-01 13:18         ` Óscar Fuentes
  1 sibling, 1 reply; 25+ messages in thread
From: Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-12-01 12:30 UTC (permalink / raw)
  To: Gerd Möllmann; +Cc: 74547, Óscar Fuentes

Gerd Möllmann <gerd.moellmann@gmail.com> writes:

> Gerd Möllmann <gerd.moellmann@gmail.com> writes:
>> Pip Cet <pipcet@protonmail.com> writes:
>>
>>> I think it's unlikely this particular vector is a closure, FWIW, because
>>> the first slot of a closure vector is always a fixnum.
>>
>> I agree.
>>
>> I've now checked all the possible PVEC types, and the only ones that fit
>> size 6 are normal vectors, closures, or records. I also don't believe
>> that it's a closure because of the fixnum. And records (SQLite) seem a
>> bit unlikely.
>
> Hm, reading Oscar's report again - he was using LSP. Maybe it's
> something in the parser.

You mean the JSON code? Because I'm just looking at that and it doesn't
appear to be protecting its Lisp_Objects at all; but I'm not a hundred
percent sure LSP uses the JSON code.

In either case, we need to fix json.c, I'll try to do that next.

Pip






^ permalink raw reply	[flat|nested] 25+ messages in thread

* bug#74547: 31.0.50; igc: assertion failed in buffer.c
  2024-12-01 12:30         ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2024-12-01 12:39           ` Gerd Möllmann
  2024-12-01 12:57             ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 25+ messages in thread
From: Gerd Möllmann @ 2024-12-01 12:39 UTC (permalink / raw)
  To: Pip Cet; +Cc: 74547, Óscar Fuentes

Pip Cet <pipcet@protonmail.com> writes:

> Gerd Möllmann <gerd.moellmann@gmail.com> writes:
>
>> Gerd Möllmann <gerd.moellmann@gmail.com> writes:
>>> Pip Cet <pipcet@protonmail.com> writes:
>>>
>>>> I think it's unlikely this particular vector is a closure, FWIW, because
>>>> the first slot of a closure vector is always a fixnum.
>>>
>>> I agree.
>>>
>>> I've now checked all the possible PVEC types, and the only ones that fit
>>> size 6 are normal vectors, closures, or records. I also don't believe
>>> that it's a closure because of the fixnum. And records (SQLite) seem a
>>> bit unlikely.
>>
>> Hm, reading Oscar's report again - he was using LSP. Maybe it's
>> something in the parser.
>
> You mean the JSON code? Because I'm just looking at that and it doesn't
> appear to be protecting its Lisp_Objects at all; but I'm not a hundred
> percent sure LSP uses the JSON code.

Yes, exactly, json.c. First thing I saw when searching for xfree

static void
json_parser_done (void *parser)
{
  struct json_parser *p = (struct json_parser *) parser;
  if (p->object_workspace != p->internal_object_workspace)
    xfree (p->object_workspace);

That at least needs an explanation. I would have expected it to be
allocated as root.

>
> In either case, we need to fix json.c, I'll try to do that next.
>
> Pip

Thanks!





^ permalink raw reply	[flat|nested] 25+ messages in thread

* bug#74547: 31.0.50; igc: assertion failed in buffer.c
  2024-12-01 12:39           ` Gerd Möllmann
@ 2024-12-01 12:57             ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2024-12-01 13:30               ` Gerd Möllmann
  0 siblings, 1 reply; 25+ messages in thread
From: Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-12-01 12:57 UTC (permalink / raw)
  To: Gerd Möllmann; +Cc: 74547, Óscar Fuentes, geza.herman

Gerd Möllmann <gerd.moellmann@gmail.com> writes:
> Pip Cet <pipcet@protonmail.com> writes:
> Yes, exactly, json.c. First thing I saw when searching for xfree
>
> static void
> json_parser_done (void *parser)
> {
>   struct json_parser *p = (struct json_parser *) parser;
>   if (p->object_workspace != p->internal_object_workspace)
>     xfree (p->object_workspace);
>
> That at least needs an explanation. I would have expected it to be
> allocated as root.

Well, the explanation is this comment:

  /* Lisp_Objects are collected in this area during object/array
     parsing.  To avoid allocations, initially
     internal_object_workspace is used.  If it runs out of space then
     we switch to allocated space.  Important note: with this design,
     GC must not run during JSON parsing, otherwise Lisp_Objects in
     the workspace may get incorrectly collected. */

Obviously, we cannot make any such guarantees when MPS is in use. (I
don't think we can make the guarantee when MPS is not in use, but I'm
not totally certain; we certainly allocate strings while parsing JSON,
which is sufficient to trigger GC in the MPS case).

Note that the json_parser object itself is fine (it's allocated on the
stack, thus marked ambiguously), it's only in the case that we create
more than 64 Lisp_Object values when parsing a single JSON document that
we end up with untraced references on the heap.

I don't know whether it's likely that that was what happened to Oscar.
My gut feeling is 64 objects would be easily reached by LSP messages,
but I'd need more time to test.

Anyway, here's a patch which might help:

commit c175744f2172ba3405ae98eb3575b2bf4adadfa4
Author: Pip Cet <pipcet@protonmail.com>
Date:   Sun Dec 1 12:46:08 2024 +0000

    Ensure JSON parser allocations are traced (bug#74547)
    
    * src/json.c (json_parser_done):
    (json_make_object_workspace_for_slow_path): Use IGC-aware allocations.

diff --git a/src/json.c b/src/json.c
index eb446f5c221..900fbcbb41a 100644
--- a/src/json.c
+++ b/src/json.c
@@ -807,7 +807,11 @@ json_parser_done (void *parser)
 {
   struct json_parser *p = (struct json_parser *) parser;
   if (p->object_workspace != p->internal_object_workspace)
+#ifdef HAVE_MPS
+    igc_xfree (p->object_workspace);
+#else
     xfree (p->object_workspace);
+#endif
   if (p->byte_workspace != p->internal_byte_workspace)
     xfree (p->byte_workspace);
 }
@@ -833,17 +837,31 @@ json_make_object_workspace_for_slow_path (struct json_parser *parser,
   if (parser->object_workspace_size
       == JSON_PARSER_INTERNAL_OBJECT_WORKSPACE_SIZE)
     {
+#ifndef HAVE_MPS
       new_workspace_ptr
 	= xnmalloc (new_workspace_size, sizeof (Lisp_Object));
+#else
+      new_workspace_ptr
+	= igc_xalloc_lisp_objs_exact (new_workspace_size);
+#endif
       memcpy (new_workspace_ptr, parser->object_workspace,
 	      (sizeof (Lisp_Object)
 	       * parser->object_workspace_current));
     }
   else
     {
+#ifndef HAVE_MPS
       new_workspace_ptr
 	= xnrealloc (parser->object_workspace, new_workspace_size,
 		     sizeof (Lisp_Object));
+#else
+      new_workspace_ptr
+	= igc_xalloc_lisp_objs_exact (new_workspace_size);
+      memcpy (new_workspace_ptr, parser->object_workspace,
+	      (sizeof (Lisp_Object)
+	       * parser->object_workspace_current));
+      igc_xfree (parser->object_workspace);
+#endif
     }
 
   parser->object_workspace = new_workspace_ptr;






^ permalink raw reply related	[flat|nested] 25+ messages in thread

* bug#74547: 31.0.50; igc: assertion failed in buffer.c
  2024-12-01 12:17       ` Gerd Möllmann
  2024-12-01 12:30         ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2024-12-01 13:18         ` Óscar Fuentes
  2024-12-01 13:44           ` Gerd Möllmann
  1 sibling, 1 reply; 25+ messages in thread
From: Óscar Fuentes @ 2024-12-01 13:18 UTC (permalink / raw)
  To: Gerd Möllmann; +Cc: Pip Cet, 74547

Gerd Möllmann <gerd.moellmann@gmail.com> writes:

> Hm, reading Oscar's report again - he was using LSP. Maybe it's
> something in the parser.

The three times that I caugth the crash with the debugger mini-echo [1]
was in the Elisp backtrace. Maybe lsp-mode does something that upsets
the garbage collector and it surfaces when mini-echo executes. Just now
tried for some minutes with mini-echo active and without lsp-mode and no
crash, but maybe I was unlucky. lsp-mode is heavy on GC and it is
difficult to replicate that.

As for the core dump, I have two, but I'm not sure if they contain
sensitive info. Usually the crash takes a few minutes of work to happen.
I can execute Emacs under gdb on a controlled environment and then
answer your requests, no problem with having it open for several days.
Or send you the core dump, if it is more useful.


1. https://github.com/liuyinz/mini-echo.el





^ permalink raw reply	[flat|nested] 25+ messages in thread

* bug#74547: 31.0.50; igc: assertion failed in buffer.c
  2024-12-01 12:57             ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2024-12-01 13:30               ` Gerd Möllmann
  2024-12-01 14:58                 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 25+ messages in thread
From: Gerd Möllmann @ 2024-12-01 13:30 UTC (permalink / raw)
  To: Pip Cet; +Cc: 74547, Óscar Fuentes, geza.herman

Pip Cet <pipcet@protonmail.com> writes:

> Gerd Möllmann <gerd.moellmann@gmail.com> writes:
>> Pip Cet <pipcet@protonmail.com> writes:
>> Yes, exactly, json.c. First thing I saw when searching for xfree
>>
>> static void
>> json_parser_done (void *parser)
>> {
>>   struct json_parser *p = (struct json_parser *) parser;
>>   if (p->object_workspace != p->internal_object_workspace)
>>     xfree (p->object_workspace);
>>
>> That at least needs an explanation. I would have expected it to be
>> allocated as root.
>
> Well, the explanation is this comment:
>
>   /* Lisp_Objects are collected in this area during object/array
>      parsing.  To avoid allocations, initially
>      internal_object_workspace is used.  If it runs out of space then
>      we switch to allocated space.  Important note: with this design,
>      GC must not run during JSON parsing, otherwise Lisp_Objects in
>      the workspace may get incorrectly collected. */

That explains it, indeed :-(.

>
> Obviously, we cannot make any such guarantees when MPS is in use. (I
> don't think we can make the guarantee when MPS is not in use, but I'm
> not totally certain; we certainly allocate strings while parsing JSON,
> which is sufficient to trigger GC in the MPS case).

If json.c calls something like maybe_quit, which I's expect it must,
then GC can indeed happen. See bug#56108 for an example in the regexp
code found with ASAN. It's not as risky in the old code as with
concurrent GC, but anyway.

>
> Note that the json_parser object itself is fine (it's allocated on the
> stack, thus marked ambiguously), it's only in the case that we create
> more than 64 Lisp_Object values when parsing a single JSON document that
> we end up with untraced references on the heap.
>
> I don't know whether it's likely that that was what happened to Oscar.
> My gut feeling is 64 objects would be easily reached by LSP messages,
> but I'd need more time to test.
>
> Anyway, here's a patch which might help:
>
> commit c175744f2172ba3405ae98eb3575b2bf4adadfa4
> Author: Pip Cet <pipcet@protonmail.com>
> Date:   Sun Dec 1 12:46:08 2024 +0000

Very nide, thank you!






^ permalink raw reply	[flat|nested] 25+ messages in thread

* bug#74547: 31.0.50; igc: assertion failed in buffer.c
  2024-12-01 13:18         ` Óscar Fuentes
@ 2024-12-01 13:44           ` Gerd Möllmann
  0 siblings, 0 replies; 25+ messages in thread
From: Gerd Möllmann @ 2024-12-01 13:44 UTC (permalink / raw)
  To: Óscar Fuentes; +Cc: Pip Cet, 74547

Óscar Fuentes <oscarfv@telefonica.net> writes:

> Gerd Möllmann <gerd.moellmann@gmail.com> writes:
>
>> Hm, reading Oscar's report again - he was using LSP. Maybe it's
>> something in the parser.
>
> The three times that I caugth the crash with the debugger mini-echo [1]
> was in the Elisp backtrace. Maybe lsp-mode does something that upsets
> the garbage collector and it surfaces when mini-echo executes. Just now
> tried for some minutes with mini-echo active and without lsp-mode and no
> crash, but maybe I was unlucky. lsp-mode is heavy on GC and it is
> difficult to replicate that.

Yeah, It's pretty difficult to find the exact time when something goes
wrong because the allocation points have some memory reserved, so that
it's not exactly predictable when a GC step happens.

But I find Pip's change very promising. It's fixing something that
cleqrly cannot work with MPS. Could you please try it (it doesn't seem
to be pushed yet.)





^ permalink raw reply	[flat|nested] 25+ messages in thread

* bug#74547: 31.0.50; igc: assertion failed in buffer.c
  2024-12-01 13:30               ` Gerd Möllmann
@ 2024-12-01 14:58                 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2024-12-01 15:18                   ` Gerd Möllmann
                                     ` (2 more replies)
  0 siblings, 3 replies; 25+ messages in thread
From: Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-12-01 14:58 UTC (permalink / raw)
  To: Gerd Möllmann; +Cc: 74547, Óscar Fuentes, geza.herman

Gerd Möllmann <gerd.moellmann@gmail.com> writes:

> Pip Cet <pipcet@protonmail.com> writes:

>> Gerd Möllmann <gerd.moellmann@gmail.com> writes:
>>> Pip Cet <pipcet@protonmail.com> writes:
>>> Yes, exactly, json.c. First thing I saw when searching for xfree
>>>
>>> static void
>>> json_parser_done (void *parser)
>>> {
>>>   struct json_parser *p = (struct json_parser *) parser;
>>>   if (p->object_workspace != p->internal_object_workspace)
>>>     xfree (p->object_workspace);
>>>
>>> That at least needs an explanation. I would have expected it to be
>>> allocated as root.
>>
>> Well, the explanation is this comment:
>>
>>   /* Lisp_Objects are collected in this area during object/array
>>      parsing.  To avoid allocations, initially
>>      internal_object_workspace is used.  If it runs out of space then
>>      we switch to allocated space.  Important note: with this design,
>>      GC must not run during JSON parsing, otherwise Lisp_Objects in
>>      the workspace may get incorrectly collected. */
>
> That explains it, indeed :-(.

Just to be clear, I think the mixed heap/stack allocation is the right
thing to do here, but we need to let both garbage collectors know about
the Lisp_Objects we allocated.

I think the best way to do that is to use a Lisp_Vector when we run out
of stack space. That way, we don't have to worry about forgetting to GC
it, and we can use standard functions rather than rolling our own.

>> Obviously, we cannot make any such guarantees when MPS is in use. (I
>> don't think we can make the guarantee when MPS is not in use, but I'm
>> not totally certain; we certainly allocate strings while parsing JSON,
>> which is sufficient to trigger GC in the MPS case).
>
> If json.c calls something like maybe_quit, which I's expect it must,
> then GC can indeed happen. See bug#56108 for an example in the regexp
> code found with ASAN. It's not as risky in the old code as with
> concurrent GC, but anyway.

There's a rarely_quit in json_parse_array, which, AFAICS, always
triggers in the first loop iteration (when i == 0), but probably never
reaches 65536 for the second trigger.

My proposal is to modify json.c so it uses a lisp vector if more than 64
objects are needed, and to remove the home-grown symset hash set,
replacing it by a standard hash table.

Note that the symset is only used to detect duplicate JSON keys. When
such duplication is detected, we simply ignore the second plist entry.
(I think it would be better to throw an error, but the documentation
disagrees.)

So here's the patch with the old behavior, where

  (json-serialize '(a "test" a "ignored"))

doesn't throw an error and simply returns

"{\"a\":\"test\"}"

commit 85fbd342d3b4a8afabe8078e19be9b45fe3e20d2
Author: Pip Cet <pipcet@protonmail.com>
Date:   Sun Dec 1 12:46:08 2024 +0000

    Use standard Lisp objects in json.c (bug#74547)
    
    * src/json.c (json_out_t): Make the symset table a Lisp_Object.
    (symset_t):
    (pop_symset):
    (cleanup_symset_tables):
    (symset_hash):
    (symset_expand):
    (symset_size): Remove.
    (make_symset_table): Use an ordinary hash table for the symset.
    (push_symset): Don't return a value.
    (symset_add): Use ordinary hash table accessors.
    (cleanup_json_out): Remove.
    (json_out_object_cons): Use ordinary hash table for symsets.
    (json_serialize):
    (json_parser_init):
    (json_parser_done): Adjust to use ordinary hash table code.
    (json_make_object_workspace_for_slow_path): Use an ordinary vector for
    the workspace.
    (json_parse_array): Avoid calling rarely_quit(0)
    (json_parser_done): Remove manual memory management.

diff --git a/src/json.c b/src/json.c
index eb446f5c221..0e17b893087 100644
--- a/src/json.c
+++ b/src/json.c
@@ -28,7 +28,6 @@ Copyright (C) 2017-2024 Free Software Foundation, Inc.
 #include "lisp.h"
 #include "buffer.h"
 #include "coding.h"
-#include "igc.h"
 
 enum json_object_type
   {
@@ -111,161 +110,9 @@ json_parse_args (ptrdiff_t nargs, Lisp_Object *args,
   ptrdiff_t chars_delta;      /* size - {number of characters in buf} */
 
   int maxdepth;
-  struct symset_tbl *ss_table;	/* table used by containing object */
   struct json_configuration conf;
 } json_out_t;
 
-/* Set of symbols.  */
-typedef struct
-{
-  ptrdiff_t count;		/* symbols in table */
-  int bits;			/* log2(table size) */
-  struct symset_tbl *table;	/* heap-allocated table */
-} symset_t;
-
-struct symset_tbl
-{
-  /* Table used by the containing object if any, so that we can free all
-     tables if an error occurs.  */
-  struct symset_tbl *up;
-  /* Table of symbols (2**bits elements), Qunbound where unused.  */
-  Lisp_Object entries[];
-};
-
-static inline ptrdiff_t
-symset_size (int bits)
-{
-  return (ptrdiff_t) 1 << bits;
-}
-
-static struct symset_tbl *
-make_symset_table (int bits, struct symset_tbl *up)
-{
-  int maxbits = min (SIZE_WIDTH - 2 - (word_size < 8 ? 2 : 3), 32);
-  if (bits > maxbits)
-    memory_full (PTRDIFF_MAX);	/* Will never happen in practice.  */
-#ifdef HAVE_MPS
-  struct symset_tbl *st = igc_xzalloc_ambig (sizeof *st + (sizeof *st->entries << bits));
-#else
-  struct symset_tbl *st = xmalloc (sizeof *st + (sizeof *st->entries << bits));
-#endif
-  st->up = up;
-  ptrdiff_t size = symset_size (bits);
-  for (ptrdiff_t i = 0; i < size; i++)
-    st->entries[i] = Qunbound;
-  return st;
-}
-
-/* Create a new symset to use for a new object.  */
-static symset_t
-push_symset (json_out_t *jo)
-{
-  int bits = 4;
-  struct symset_tbl *tbl = make_symset_table (bits, jo->ss_table);
-  jo->ss_table = tbl;
-  return (symset_t){ .count = 0, .bits = bits, .table = tbl };
-}
-
-/* Destroy the current symset.  */
-static void
-pop_symset (json_out_t *jo, symset_t *ss)
-{
-  jo->ss_table = ss->table->up;
-#ifdef HAVE_MPS
-  igc_xfree (ss->table);
-#else
-  xfree (ss->table);
-#endif
-}
-
-/* Remove all heap-allocated symset tables, in case an error occurred.  */
-static void
-cleanup_symset_tables (struct symset_tbl *st)
-{
-  while (st)
-    {
-      struct symset_tbl *up = st->up;
-#ifdef HAVE_MPS
-      igc_xfree (st);
-#else
-      xfree (st);
-#endif
-      st = up;
-    }
-}
-
-static inline uint32_t
-symset_hash (Lisp_Object sym, int bits)
-{
-  EMACS_UINT hash;
-#ifdef HAVE_MPS
-  hash = igc_hash (sym);
-#else
-  hash = XHASH (sym);
-#endif
-  return knuth_hash (reduce_emacs_uint_to_hash_hash (hash), bits);
-}
-
-/* Enlarge the table used by a symset.  */
-static NO_INLINE void
-symset_expand (symset_t *ss)
-{
-  struct symset_tbl *old_table = ss->table;
-  int oldbits = ss->bits;
-  ptrdiff_t oldsize = symset_size (oldbits);
-  int bits = oldbits + 1;
-  ss->bits = bits;
-  ss->table = make_symset_table (bits, old_table->up);
-  /* Move all entries from the old table to the new one.  */
-  ptrdiff_t mask = symset_size (bits) - 1;
-  struct symset_tbl *tbl = ss->table;
-  for (ptrdiff_t i = 0; i < oldsize; i++)
-    {
-      Lisp_Object sym = old_table->entries[i];
-      if (!BASE_EQ (sym, Qunbound))
-	{
-	  ptrdiff_t j = symset_hash (sym, bits);
-	  while (!BASE_EQ (tbl->entries[j], Qunbound))
-	    j = (j + 1) & mask;
-	  tbl->entries[j] = sym;
-	}
-    }
-#ifdef HAVE_MPS
-  igc_xfree (old_table);
-#else
-  xfree (old_table);
-#endif
-}
-
-/* If sym is in ss, return false; otherwise add it and return true.
-   Comparison is done by strict identity.  */
-static inline bool
-symset_add (json_out_t *jo, symset_t *ss, Lisp_Object sym)
-{
-  /* Make sure we don't fill more than half of the table.  */
-  if (ss->count >= (symset_size (ss->bits) >> 1))
-    {
-      symset_expand (ss);
-      jo->ss_table = ss->table;
-    }
-
-  struct symset_tbl *tbl = ss->table;
-  ptrdiff_t mask = symset_size (ss->bits) - 1;
-  for (ptrdiff_t i = symset_hash (sym, ss->bits); ; i = (i + 1) & mask)
-    {
-      Lisp_Object s = tbl->entries[i];
-      if (BASE_EQ (s, sym))
-	return false;		/* Previous occurrence found.  */
-      if (BASE_EQ (s, Qunbound))
-	{
-	  /* Not in set, add it.  */
-	  tbl->entries[i] = sym;
-	  ss->count++;
-	  return true;
-	}
-    }
-}
-
 static NO_INLINE void
 json_out_grow_buf (json_out_t *jo, ptrdiff_t bytes)
 {
@@ -283,7 +130,6 @@ cleanup_json_out (void *arg)
   json_out_t *jo = arg;
   xfree (jo->buf);
   jo->buf = NULL;
-  cleanup_symset_tables (jo->ss_table);
 }
 
 /* Make room for `bytes` more bytes in buffer.  */
@@ -442,8 +288,8 @@ json_out_unnest (json_out_t *jo)
 static void
 json_out_object_cons (json_out_t *jo, Lisp_Object obj)
 {
+  Lisp_Object symset = CALLN (Fmake_hash_table, QCtest, Qeq);
   json_out_nest (jo);
-  symset_t ss = push_symset (jo);
   json_out_byte (jo, '{');
   bool is_alist = CONSP (XCAR (obj));
   bool first = true;
@@ -469,8 +315,9 @@ json_out_object_cons (json_out_t *jo, Lisp_Object obj)
       key = maybe_remove_pos_from_symbol (key);
       CHECK_TYPE (BARE_SYMBOL_P (key), Qsymbolp, key);
 
-      if (symset_add (jo, &ss, key))
+      if (NILP (Fgethash (key, symset, Qnil)))
 	{
+	  Fputhash (key, Qt, symset);
 	  if (!first)
 	    json_out_byte (jo, ',');
 	  first = false;
@@ -486,7 +333,6 @@ json_out_object_cons (json_out_t *jo, Lisp_Object obj)
     }
   CHECK_LIST_END (tail, obj);
   json_out_byte (jo, '}');
-  pop_symset (jo, &ss);
   json_out_unnest (jo);
 }
 
@@ -591,7 +437,6 @@ json_serialize (json_out_t *jo, Lisp_Object object,
   jo->capacity = 0;
   jo->chars_delta = 0;
   jo->buf = NULL;
-  jo->ss_table = NULL;
   jo->conf.object_type = json_object_hashtable;
   jo->conf.array_type = json_array_array;
   jo->conf.null_object = QCnull;
@@ -729,6 +574,7 @@ #define JSON_PARSER_INTERNAL_BYTE_WORKSPACE_SIZE 512
   Lisp_Object internal_object_workspace
   [JSON_PARSER_INTERNAL_OBJECT_WORKSPACE_SIZE];
   Lisp_Object *object_workspace;
+  Lisp_Object object_workspace_vector;
   size_t object_workspace_size;
   size_t object_workspace_current;
 
@@ -796,6 +642,7 @@ json_parser_init (struct json_parser *parser,
   parser->object_workspace_size
     = JSON_PARSER_INTERNAL_OBJECT_WORKSPACE_SIZE;
   parser->object_workspace_current = 0;
+  parser->object_workspace_vector = Qnil;
 
   parser->byte_workspace = parser->internal_byte_workspace;
   parser->byte_workspace_end = (parser->byte_workspace
@@ -806,8 +653,6 @@ json_parser_init (struct json_parser *parser,
 json_parser_done (void *parser)
 {
   struct json_parser *p = (struct json_parser *) parser;
-  if (p->object_workspace != p->internal_object_workspace)
-    xfree (p->object_workspace);
   if (p->byte_workspace != p->internal_byte_workspace)
     xfree (p->byte_workspace);
 }
@@ -818,6 +663,11 @@ json_parser_done (void *parser)
 json_make_object_workspace_for_slow_path (struct json_parser *parser,
 					  size_t size)
 {
+  if (NILP (parser->object_workspace_vector))
+    {
+      parser->object_workspace_vector =
+	Fvector(parser->object_workspace_current, parser->object_workspace);
+    }
   size_t needed_workspace_size
     = (parser->object_workspace_current + size);
   size_t new_workspace_size = parser->object_workspace_size;
@@ -829,23 +679,13 @@ json_make_object_workspace_for_slow_path (struct json_parser *parser,
 	}
     }
 
-  Lisp_Object *new_workspace_ptr;
-  if (parser->object_workspace_size
-      == JSON_PARSER_INTERNAL_OBJECT_WORKSPACE_SIZE)
-    {
-      new_workspace_ptr
-	= xnmalloc (new_workspace_size, sizeof (Lisp_Object));
-      memcpy (new_workspace_ptr, parser->object_workspace,
-	      (sizeof (Lisp_Object)
-	       * parser->object_workspace_current));
-    }
-  else
-    {
-      new_workspace_ptr
-	= xnrealloc (parser->object_workspace, new_workspace_size,
-		     sizeof (Lisp_Object));
-    }
+  Lisp_Object new_workspace_vector =
+    larger_vector (parser->object_workspace_vector,
+		   new_workspace_size - parser->object_workspace_size, -1);
+
+  Lisp_Object *new_workspace_ptr = XVECTOR (new_workspace_vector)->contents;
 
+  parser->object_workspace_vector = new_workspace_vector;
   parser->object_workspace = new_workspace_ptr;
   parser->object_workspace_size = new_workspace_size;
 }
@@ -1476,7 +1316,7 @@ json_parse_array (struct json_parser *parser)
 	result = make_vector (number_of_elements, Qnil);
 	for (size_t i = 0; i < number_of_elements; i++)
 	  {
-	    rarely_quit (i);
+	    rarely_quit (~i);
 	    ASET (result, i, parser->object_workspace[first + i]);
 	  }
 	parser->object_workspace_current = first;






^ permalink raw reply related	[flat|nested] 25+ messages in thread

* bug#74547: 31.0.50; igc: assertion failed in buffer.c
  2024-12-01 14:58                 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2024-12-01 15:18                   ` Gerd Möllmann
  2024-12-01 15:48                     ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2024-12-01 15:55                     ` Eli Zaretskii
  2024-12-01 15:23                   ` Eli Zaretskii
  2024-12-01 15:30                   ` Óscar Fuentes
  2 siblings, 2 replies; 25+ messages in thread
From: Gerd Möllmann @ 2024-12-01 15:18 UTC (permalink / raw)
  To: Pip Cet; +Cc: 74547, Óscar Fuentes, geza.herman

Pip Cet <pipcet@protonmail.com> writes:

> Gerd Möllmann <gerd.moellmann@gmail.com> writes:
>
>> Pip Cet <pipcet@protonmail.com> writes:
>
>>> Gerd Möllmann <gerd.moellmann@gmail.com> writes:
>>>> Pip Cet <pipcet@protonmail.com> writes:
>>>> Yes, exactly, json.c. First thing I saw when searching for xfree
>>>>
>>>> static void
>>>> json_parser_done (void *parser)
>>>> {
>>>>   struct json_parser *p = (struct json_parser *) parser;
>>>>   if (p->object_workspace != p->internal_object_workspace)
>>>>     xfree (p->object_workspace);
>>>>
>>>> That at least needs an explanation. I would have expected it to be
>>>> allocated as root.
>>>
>>> Well, the explanation is this comment:
>>>
>>>   /* Lisp_Objects are collected in this area during object/array
>>>      parsing.  To avoid allocations, initially
>>>      internal_object_workspace is used.  If it runs out of space then
>>>      we switch to allocated space.  Important note: with this design,
>>>      GC must not run during JSON parsing, otherwise Lisp_Objects in
>>>      the workspace may get incorrectly collected. */
>>
>> That explains it, indeed :-(.
>
> Just to be clear, I think the mixed heap/stack allocation is the right
> thing to do here, but we need to let both garbage collectors know about
> the Lisp_Objects we allocated.
>
> I think the best way to do that is to use a Lisp_Vector when we run out
> of stack space. That way, we don't have to worry about forgetting to GC
> it, and we can use standard functions rather than rolling our own.

Yeah, I'd prefer using Lisp_Vectors too, and it was actually implemented
at some point, but removed again, see

  https://yhetil.org/emacs-devel/87edc1rzig.fsf@gmail.com/

I vaguely remember a longer thread about GC in json.c at the time. Could
be that that was before igc became a realistic possibility, don't
remember.

And yes, I've forgotten about it, and should actually have fixed this
long ago :-).





^ permalink raw reply	[flat|nested] 25+ messages in thread

* bug#74547: 31.0.50; igc: assertion failed in buffer.c
  2024-12-01 14:58                 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2024-12-01 15:18                   ` Gerd Möllmann
@ 2024-12-01 15:23                   ` Eli Zaretskii
  2024-12-01 15:30                   ` Óscar Fuentes
  2 siblings, 0 replies; 25+ messages in thread
From: Eli Zaretskii @ 2024-12-01 15:23 UTC (permalink / raw)
  To: Pip Cet, Mattias Engdegård, Géza Herman
  Cc: gerd.moellmann, 74547, oscarfv, geza.herman

> Cc: 74547@debbugs.gnu.org,
>  Óscar Fuentes <oscarfv@telefonica.net>, geza.herman@gmail.com
> Date: Sun, 01 Dec 2024 14:58:10 +0000
> From:  Pip Cet via "Bug reports for GNU Emacs,
>  the Swiss army knife of text editors" <bug-gnu-emacs@gnu.org>
> 
> Gerd Möllmann <gerd.moellmann@gmail.com> writes:
> 
> > Pip Cet <pipcet@protonmail.com> writes:
> 
> >> Gerd Möllmann <gerd.moellmann@gmail.com> writes:
> >>> Pip Cet <pipcet@protonmail.com> writes:
> >>> Yes, exactly, json.c. First thing I saw when searching for xfree
> >>>
> >>> static void
> >>> json_parser_done (void *parser)
> >>> {
> >>>   struct json_parser *p = (struct json_parser *) parser;
> >>>   if (p->object_workspace != p->internal_object_workspace)
> >>>     xfree (p->object_workspace);
> >>>
> >>> That at least needs an explanation. I would have expected it to be
> >>> allocated as root.
> >>
> >> Well, the explanation is this comment:
> >>
> >>   /* Lisp_Objects are collected in this area during object/array
> >>      parsing.  To avoid allocations, initially
> >>      internal_object_workspace is used.  If it runs out of space then
> >>      we switch to allocated space.  Important note: with this design,
> >>      GC must not run during JSON parsing, otherwise Lisp_Objects in
> >>      the workspace may get incorrectly collected. */
> >
> > That explains it, indeed :-(.
> 
> Just to be clear, I think the mixed heap/stack allocation is the right
> thing to do here, but we need to let both garbage collectors know about
> the Lisp_Objects we allocated.
> 
> I think the best way to do that is to use a Lisp_Vector when we run out
> of stack space. That way, we don't have to worry about forgetting to GC
> it, and we can use standard functions rather than rolling our own.
> 
> >> Obviously, we cannot make any such guarantees when MPS is in use. (I
> >> don't think we can make the guarantee when MPS is not in use, but I'm
> >> not totally certain; we certainly allocate strings while parsing JSON,
> >> which is sufficient to trigger GC in the MPS case).
> >
> > If json.c calls something like maybe_quit, which I's expect it must,
> > then GC can indeed happen. See bug#56108 for an example in the regexp
> > code found with ASAN. It's not as risky in the old code as with
> > concurrent GC, but anyway.
> 
> There's a rarely_quit in json_parse_array, which, AFAICS, always
> triggers in the first loop iteration (when i == 0), but probably never
> reaches 65536 for the second trigger.
> 
> My proposal is to modify json.c so it uses a lisp vector if more than 64
> objects are needed, and to remove the home-grown symset hash set,
> replacing it by a standard hash table.
> 
> Note that the symset is only used to detect duplicate JSON keys. When
> such duplication is detected, we simply ignore the second plist entry.
> (I think it would be better to throw an error, but the documentation
> disagrees.)
> 
> So here's the patch with the old behavior, where
> 
>   (json-serialize '(a "test" a "ignored"))
> 
> doesn't throw an error and simply returns
> 
> "{\"a\":\"test\"}"

Adding Mattias and Géza, who were involved in implementing json.c.

> commit 85fbd342d3b4a8afabe8078e19be9b45fe3e20d2
> Author: Pip Cet <pipcet@protonmail.com>
> Date:   Sun Dec 1 12:46:08 2024 +0000
> 
>     Use standard Lisp objects in json.c (bug#74547)
>     
>     * src/json.c (json_out_t): Make the symset table a Lisp_Object.
>     (symset_t):
>     (pop_symset):
>     (cleanup_symset_tables):
>     (symset_hash):
>     (symset_expand):
>     (symset_size): Remove.
>     (make_symset_table): Use an ordinary hash table for the symset.
>     (push_symset): Don't return a value.
>     (symset_add): Use ordinary hash table accessors.
>     (cleanup_json_out): Remove.
>     (json_out_object_cons): Use ordinary hash table for symsets.
>     (json_serialize):
>     (json_parser_init):
>     (json_parser_done): Adjust to use ordinary hash table code.
>     (json_make_object_workspace_for_slow_path): Use an ordinary vector for
>     the workspace.
>     (json_parse_array): Avoid calling rarely_quit(0)
>     (json_parser_done): Remove manual memory management.
> 
> diff --git a/src/json.c b/src/json.c
> index eb446f5c221..0e17b893087 100644
> --- a/src/json.c
> +++ b/src/json.c
> @@ -28,7 +28,6 @@ Copyright (C) 2017-2024 Free Software Foundation, Inc.
>  #include "lisp.h"
>  #include "buffer.h"
>  #include "coding.h"
> -#include "igc.h"
>  
>  enum json_object_type
>    {
> @@ -111,161 +110,9 @@ json_parse_args (ptrdiff_t nargs, Lisp_Object *args,
>    ptrdiff_t chars_delta;      /* size - {number of characters in buf} */
>  
>    int maxdepth;
> -  struct symset_tbl *ss_table;	/* table used by containing object */
>    struct json_configuration conf;
>  } json_out_t;
>  
> -/* Set of symbols.  */
> -typedef struct
> -{
> -  ptrdiff_t count;		/* symbols in table */
> -  int bits;			/* log2(table size) */
> -  struct symset_tbl *table;	/* heap-allocated table */
> -} symset_t;
> -
> -struct symset_tbl
> -{
> -  /* Table used by the containing object if any, so that we can free all
> -     tables if an error occurs.  */
> -  struct symset_tbl *up;
> -  /* Table of symbols (2**bits elements), Qunbound where unused.  */
> -  Lisp_Object entries[];
> -};
> -
> -static inline ptrdiff_t
> -symset_size (int bits)
> -{
> -  return (ptrdiff_t) 1 << bits;
> -}
> -
> -static struct symset_tbl *
> -make_symset_table (int bits, struct symset_tbl *up)
> -{
> -  int maxbits = min (SIZE_WIDTH - 2 - (word_size < 8 ? 2 : 3), 32);
> -  if (bits > maxbits)
> -    memory_full (PTRDIFF_MAX);	/* Will never happen in practice.  */
> -#ifdef HAVE_MPS
> -  struct symset_tbl *st = igc_xzalloc_ambig (sizeof *st + (sizeof *st->entries << bits));
> -#else
> -  struct symset_tbl *st = xmalloc (sizeof *st + (sizeof *st->entries << bits));
> -#endif
> -  st->up = up;
> -  ptrdiff_t size = symset_size (bits);
> -  for (ptrdiff_t i = 0; i < size; i++)
> -    st->entries[i] = Qunbound;
> -  return st;
> -}
> -
> -/* Create a new symset to use for a new object.  */
> -static symset_t
> -push_symset (json_out_t *jo)
> -{
> -  int bits = 4;
> -  struct symset_tbl *tbl = make_symset_table (bits, jo->ss_table);
> -  jo->ss_table = tbl;
> -  return (symset_t){ .count = 0, .bits = bits, .table = tbl };
> -}
> -
> -/* Destroy the current symset.  */
> -static void
> -pop_symset (json_out_t *jo, symset_t *ss)
> -{
> -  jo->ss_table = ss->table->up;
> -#ifdef HAVE_MPS
> -  igc_xfree (ss->table);
> -#else
> -  xfree (ss->table);
> -#endif
> -}
> -
> -/* Remove all heap-allocated symset tables, in case an error occurred.  */
> -static void
> -cleanup_symset_tables (struct symset_tbl *st)
> -{
> -  while (st)
> -    {
> -      struct symset_tbl *up = st->up;
> -#ifdef HAVE_MPS
> -      igc_xfree (st);
> -#else
> -      xfree (st);
> -#endif
> -      st = up;
> -    }
> -}
> -
> -static inline uint32_t
> -symset_hash (Lisp_Object sym, int bits)
> -{
> -  EMACS_UINT hash;
> -#ifdef HAVE_MPS
> -  hash = igc_hash (sym);
> -#else
> -  hash = XHASH (sym);
> -#endif
> -  return knuth_hash (reduce_emacs_uint_to_hash_hash (hash), bits);
> -}
> -
> -/* Enlarge the table used by a symset.  */
> -static NO_INLINE void
> -symset_expand (symset_t *ss)
> -{
> -  struct symset_tbl *old_table = ss->table;
> -  int oldbits = ss->bits;
> -  ptrdiff_t oldsize = symset_size (oldbits);
> -  int bits = oldbits + 1;
> -  ss->bits = bits;
> -  ss->table = make_symset_table (bits, old_table->up);
> -  /* Move all entries from the old table to the new one.  */
> -  ptrdiff_t mask = symset_size (bits) - 1;
> -  struct symset_tbl *tbl = ss->table;
> -  for (ptrdiff_t i = 0; i < oldsize; i++)
> -    {
> -      Lisp_Object sym = old_table->entries[i];
> -      if (!BASE_EQ (sym, Qunbound))
> -	{
> -	  ptrdiff_t j = symset_hash (sym, bits);
> -	  while (!BASE_EQ (tbl->entries[j], Qunbound))
> -	    j = (j + 1) & mask;
> -	  tbl->entries[j] = sym;
> -	}
> -    }
> -#ifdef HAVE_MPS
> -  igc_xfree (old_table);
> -#else
> -  xfree (old_table);
> -#endif
> -}
> -
> -/* If sym is in ss, return false; otherwise add it and return true.
> -   Comparison is done by strict identity.  */
> -static inline bool
> -symset_add (json_out_t *jo, symset_t *ss, Lisp_Object sym)
> -{
> -  /* Make sure we don't fill more than half of the table.  */
> -  if (ss->count >= (symset_size (ss->bits) >> 1))
> -    {
> -      symset_expand (ss);
> -      jo->ss_table = ss->table;
> -    }
> -
> -  struct symset_tbl *tbl = ss->table;
> -  ptrdiff_t mask = symset_size (ss->bits) - 1;
> -  for (ptrdiff_t i = symset_hash (sym, ss->bits); ; i = (i + 1) & mask)
> -    {
> -      Lisp_Object s = tbl->entries[i];
> -      if (BASE_EQ (s, sym))
> -	return false;		/* Previous occurrence found.  */
> -      if (BASE_EQ (s, Qunbound))
> -	{
> -	  /* Not in set, add it.  */
> -	  tbl->entries[i] = sym;
> -	  ss->count++;
> -	  return true;
> -	}
> -    }
> -}
> -
>  static NO_INLINE void
>  json_out_grow_buf (json_out_t *jo, ptrdiff_t bytes)
>  {
> @@ -283,7 +130,6 @@ cleanup_json_out (void *arg)
>    json_out_t *jo = arg;
>    xfree (jo->buf);
>    jo->buf = NULL;
> -  cleanup_symset_tables (jo->ss_table);
>  }
>  
>  /* Make room for `bytes` more bytes in buffer.  */
> @@ -442,8 +288,8 @@ json_out_unnest (json_out_t *jo)
>  static void
>  json_out_object_cons (json_out_t *jo, Lisp_Object obj)
>  {
> +  Lisp_Object symset = CALLN (Fmake_hash_table, QCtest, Qeq);
>    json_out_nest (jo);
> -  symset_t ss = push_symset (jo);
>    json_out_byte (jo, '{');
>    bool is_alist = CONSP (XCAR (obj));
>    bool first = true;
> @@ -469,8 +315,9 @@ json_out_object_cons (json_out_t *jo, Lisp_Object obj)
>        key = maybe_remove_pos_from_symbol (key);
>        CHECK_TYPE (BARE_SYMBOL_P (key), Qsymbolp, key);
>  
> -      if (symset_add (jo, &ss, key))
> +      if (NILP (Fgethash (key, symset, Qnil)))
>  	{
> +	  Fputhash (key, Qt, symset);
>  	  if (!first)
>  	    json_out_byte (jo, ',');
>  	  first = false;
> @@ -486,7 +333,6 @@ json_out_object_cons (json_out_t *jo, Lisp_Object obj)
>      }
>    CHECK_LIST_END (tail, obj);
>    json_out_byte (jo, '}');
> -  pop_symset (jo, &ss);
>    json_out_unnest (jo);
>  }
>  
> @@ -591,7 +437,6 @@ json_serialize (json_out_t *jo, Lisp_Object object,
>    jo->capacity = 0;
>    jo->chars_delta = 0;
>    jo->buf = NULL;
> -  jo->ss_table = NULL;
>    jo->conf.object_type = json_object_hashtable;
>    jo->conf.array_type = json_array_array;
>    jo->conf.null_object = QCnull;
> @@ -729,6 +574,7 @@ #define JSON_PARSER_INTERNAL_BYTE_WORKSPACE_SIZE 512
>    Lisp_Object internal_object_workspace
>    [JSON_PARSER_INTERNAL_OBJECT_WORKSPACE_SIZE];
>    Lisp_Object *object_workspace;
> +  Lisp_Object object_workspace_vector;
>    size_t object_workspace_size;
>    size_t object_workspace_current;
>  
> @@ -796,6 +642,7 @@ json_parser_init (struct json_parser *parser,
>    parser->object_workspace_size
>      = JSON_PARSER_INTERNAL_OBJECT_WORKSPACE_SIZE;
>    parser->object_workspace_current = 0;
> +  parser->object_workspace_vector = Qnil;
>  
>    parser->byte_workspace = parser->internal_byte_workspace;
>    parser->byte_workspace_end = (parser->byte_workspace
> @@ -806,8 +653,6 @@ json_parser_init (struct json_parser *parser,
>  json_parser_done (void *parser)
>  {
>    struct json_parser *p = (struct json_parser *) parser;
> -  if (p->object_workspace != p->internal_object_workspace)
> -    xfree (p->object_workspace);
>    if (p->byte_workspace != p->internal_byte_workspace)
>      xfree (p->byte_workspace);
>  }
> @@ -818,6 +663,11 @@ json_parser_done (void *parser)
>  json_make_object_workspace_for_slow_path (struct json_parser *parser,
>  					  size_t size)
>  {
> +  if (NILP (parser->object_workspace_vector))
> +    {
> +      parser->object_workspace_vector =
> +	Fvector(parser->object_workspace_current, parser->object_workspace);
> +    }
>    size_t needed_workspace_size
>      = (parser->object_workspace_current + size);
>    size_t new_workspace_size = parser->object_workspace_size;
> @@ -829,23 +679,13 @@ json_make_object_workspace_for_slow_path (struct json_parser *parser,
>  	}
>      }
>  
> -  Lisp_Object *new_workspace_ptr;
> -  if (parser->object_workspace_size
> -      == JSON_PARSER_INTERNAL_OBJECT_WORKSPACE_SIZE)
> -    {
> -      new_workspace_ptr
> -	= xnmalloc (new_workspace_size, sizeof (Lisp_Object));
> -      memcpy (new_workspace_ptr, parser->object_workspace,
> -	      (sizeof (Lisp_Object)
> -	       * parser->object_workspace_current));
> -    }
> -  else
> -    {
> -      new_workspace_ptr
> -	= xnrealloc (parser->object_workspace, new_workspace_size,
> -		     sizeof (Lisp_Object));
> -    }
> +  Lisp_Object new_workspace_vector =
> +    larger_vector (parser->object_workspace_vector,
> +		   new_workspace_size - parser->object_workspace_size, -1);
> +
> +  Lisp_Object *new_workspace_ptr = XVECTOR (new_workspace_vector)->contents;
>  
> +  parser->object_workspace_vector = new_workspace_vector;
>    parser->object_workspace = new_workspace_ptr;
>    parser->object_workspace_size = new_workspace_size;
>  }
> @@ -1476,7 +1316,7 @@ json_parse_array (struct json_parser *parser)
>  	result = make_vector (number_of_elements, Qnil);
>  	for (size_t i = 0; i < number_of_elements; i++)
>  	  {
> -	    rarely_quit (i);
> +	    rarely_quit (~i);
>  	    ASET (result, i, parser->object_workspace[first + i]);
>  	  }
>  	parser->object_workspace_current = first;
> 
> 
> 
> 
> 





^ permalink raw reply	[flat|nested] 25+ messages in thread

* bug#74547: 31.0.50; igc: assertion failed in buffer.c
  2024-12-01 14:58                 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2024-12-01 15:18                   ` Gerd Möllmann
  2024-12-01 15:23                   ` Eli Zaretskii
@ 2024-12-01 15:30                   ` Óscar Fuentes
  2024-12-01 15:48                     ` Gerd Möllmann
  2024-12-01 15:58                     ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2 siblings, 2 replies; 25+ messages in thread
From: Óscar Fuentes @ 2024-12-01 15:30 UTC (permalink / raw)
  To: Pip Cet; +Cc: Gerd Möllmann, 74547, geza.herman

Pip Cet <pipcet@protonmail.com> writes:

> commit 85fbd342d3b4a8afabe8078e19be9b45fe3e20d2
> Author: Pip Cet <pipcet@protonmail.com>
> Date:   Sun Dec 1 12:46:08 2024 +0000

Pip, is that your local repo? Do you intend to push the changes soon or
should I apply them as patches over scratch/igc? Today I plan to do
quite a lot of work with lsp-mode.

Thanks!





^ permalink raw reply	[flat|nested] 25+ messages in thread

* bug#74547: 31.0.50; igc: assertion failed in buffer.c
  2024-12-01 15:18                   ` Gerd Möllmann
@ 2024-12-01 15:48                     ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2024-12-01 16:32                       ` Geza Herman
  2024-12-01 15:55                     ` Eli Zaretskii
  1 sibling, 1 reply; 25+ messages in thread
From: Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-12-01 15:48 UTC (permalink / raw)
  To: Gerd Möllmann; +Cc: 74547, Óscar Fuentes, geza.herman

Gerd Möllmann <gerd.moellmann@gmail.com> writes:

> Yeah, I'd prefer using Lisp_Vectors too, and it was actually implemented
> at some point, but removed again, see
>
>   https://yhetil.org/emacs-devel/87edc1rzig.fsf@gmail.com/
>
> I vaguely remember a longer thread about GC in json.c at the time. Could
> be that that was before igc became a realistic possibility, don't
> remember.

Okay, sounds like it's a political issue. I'll push the first patch
which keeps changes to a minimum.

Pip






^ permalink raw reply	[flat|nested] 25+ messages in thread

* bug#74547: 31.0.50; igc: assertion failed in buffer.c
  2024-12-01 15:30                   ` Óscar Fuentes
@ 2024-12-01 15:48                     ` Gerd Möllmann
  2024-12-01 15:58                     ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
  1 sibling, 0 replies; 25+ messages in thread
From: Gerd Möllmann @ 2024-12-01 15:48 UTC (permalink / raw)
  To: Óscar Fuentes; +Cc: Pip Cet, 74547, geza.herman

Óscar Fuentes <oscarfv@telefonica.net> writes:

> Pip Cet <pipcet@protonmail.com> writes:
>
>> commit 85fbd342d3b4a8afabe8078e19be9b45fe3e20d2
>> Author: Pip Cet <pipcet@protonmail.com>
>> Date:   Sun Dec 1 12:46:08 2024 +0000
>
> Pip, is that your local repo? Do you intend to push the changes soon or
> should I apply them as patches over scratch/igc? Today I plan to do
> quite a lot of work with lsp-mode.
>
> Thanks!

I think you could apply either patch from Pip, Oscar. They should be
functionally equivalent, and it could tell us if we are on the right
track.

It might take some time until a solution is found (it's Pip's second
path :-)) that satisfies all parties.





^ permalink raw reply	[flat|nested] 25+ messages in thread

* bug#74547: 31.0.50; igc: assertion failed in buffer.c
  2024-12-01 15:18                   ` Gerd Möllmann
  2024-12-01 15:48                     ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2024-12-01 15:55                     ` Eli Zaretskii
  1 sibling, 0 replies; 25+ messages in thread
From: Eli Zaretskii @ 2024-12-01 15:55 UTC (permalink / raw)
  To: Gerd Möllmann; +Cc: pipcet, oscarfv, 74547, geza.herman

> Cc: 74547@debbugs.gnu.org,
>  Óscar Fuentes <oscarfv@telefonica.net>, geza.herman@gmail.com
> From: Gerd Möllmann <gerd.moellmann@gmail.com>
> Date: Sun, 01 Dec 2024 16:18:31 +0100
> 
> Pip Cet <pipcet@protonmail.com> writes:
> 
> > Gerd Möllmann <gerd.moellmann@gmail.com> writes:
> >
> >> Pip Cet <pipcet@protonmail.com> writes:
> >
> >>> Gerd Möllmann <gerd.moellmann@gmail.com> writes:
> >>>> Pip Cet <pipcet@protonmail.com> writes:
> >>>> Yes, exactly, json.c. First thing I saw when searching for xfree
> >>>>
> >>>> static void
> >>>> json_parser_done (void *parser)
> >>>> {
> >>>>   struct json_parser *p = (struct json_parser *) parser;
> >>>>   if (p->object_workspace != p->internal_object_workspace)
> >>>>     xfree (p->object_workspace);
> >>>>
> >>>> That at least needs an explanation. I would have expected it to be
> >>>> allocated as root.
> >>>
> >>> Well, the explanation is this comment:
> >>>
> >>>   /* Lisp_Objects are collected in this area during object/array
> >>>      parsing.  To avoid allocations, initially
> >>>      internal_object_workspace is used.  If it runs out of space then
> >>>      we switch to allocated space.  Important note: with this design,
> >>>      GC must not run during JSON parsing, otherwise Lisp_Objects in
> >>>      the workspace may get incorrectly collected. */
> >>
> >> That explains it, indeed :-(.
> >
> > Just to be clear, I think the mixed heap/stack allocation is the right
> > thing to do here, but we need to let both garbage collectors know about
> > the Lisp_Objects we allocated.
> >
> > I think the best way to do that is to use a Lisp_Vector when we run out
> > of stack space. That way, we don't have to worry about forgetting to GC
> > it, and we can use standard functions rather than rolling our own.
> 
> Yeah, I'd prefer using Lisp_Vectors too, and it was actually implemented
> at some point, but removed again, see
> 
>   https://yhetil.org/emacs-devel/87edc1rzig.fsf@gmail.com/
> 
> I vaguely remember a longer thread about GC in json.c at the time. Could
> be that that was before igc became a realistic possibility, don't
> remember.
> 
> And yes, I've forgotten about it, and should actually have fixed this
> long ago :-).

Please be sure to measure performance.  json.c is performance-critical
in many applications nowadays, that's why it was implemented in C.





^ permalink raw reply	[flat|nested] 25+ messages in thread

* bug#74547: 31.0.50; igc: assertion failed in buffer.c
  2024-12-01 15:30                   ` Óscar Fuentes
  2024-12-01 15:48                     ` Gerd Möllmann
@ 2024-12-01 15:58                     ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2024-12-01 16:24                       ` Óscar Fuentes
  1 sibling, 1 reply; 25+ messages in thread
From: Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-12-01 15:58 UTC (permalink / raw)
  To: Óscar Fuentes; +Cc: Gerd Möllmann, 74547, geza.herman

Óscar Fuentes <oscarfv@telefonica.net> writes:

> Pip Cet <pipcet@protonmail.com> writes:
>
>> commit 85fbd342d3b4a8afabe8078e19be9b45fe3e20d2
>> Author: Pip Cet <pipcet@protonmail.com>
>> Date:   Sun Dec 1 12:46:08 2024 +0000
>
> Pip, is that your local repo? Do you intend to push the changes soon or
> should I apply them as patches over scratch/igc? Today I plan to do
> quite a lot of work with lsp-mode.

I've pushed the first patch to scratch/igc.  It'd be great if you could
run it for a while to see whether it fixes the problem!

Thanks!

Pip






^ permalink raw reply	[flat|nested] 25+ messages in thread

* bug#74547: 31.0.50; igc: assertion failed in buffer.c
  2024-12-01 15:58                     ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2024-12-01 16:24                       ` Óscar Fuentes
  0 siblings, 0 replies; 25+ messages in thread
From: Óscar Fuentes @ 2024-12-01 16:24 UTC (permalink / raw)
  To: Pip Cet; +Cc: Gerd Möllmann, 74547, geza.herman

Pip Cet <pipcet@protonmail.com> writes:

> Óscar Fuentes <oscarfv@telefonica.net> writes:
>
> I've pushed the first patch to scratch/igc.  It'd be great if you could
> run it for a while to see whether it fixes the problem!

Just built Emacs with the first patch and a long session of work is
underway. If Emacs doesn't crash today we can say with certainty that
the patch solves the problem... or hides it :-)

Thank you.





^ permalink raw reply	[flat|nested] 25+ messages in thread

* bug#74547: 31.0.50; igc: assertion failed in buffer.c
  2024-12-01 15:48                     ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2024-12-01 16:32                       ` Geza Herman
  2024-12-01 19:41                         ` Gerd Möllmann
  2024-12-01 21:15                         ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 2 replies; 25+ messages in thread
From: Geza Herman @ 2024-12-01 16:32 UTC (permalink / raw)
  To: Pip Cet, Gerd Möllmann; +Cc: 74547, Óscar Fuentes

[-- Attachment #1: Type: text/plain, Size: 1828 bytes --]

On 12/1/24 16:48, Pip Cet wrote:
> Gerd Möllmann<gerd.moellmann@gmail.com> writes:
>
>> Yeah, I'd prefer using Lisp_Vectors too, and it was actually implemented
>> at some point, but removed again, see
>>
>>    https://yhetil.org/emacs-devel/87edc1rzig.fsf@gmail.com/
>>
>> I vaguely remember a longer thread about GC in json.c at the time. Could
>> be that that was before igc became a realistic possibility, don't
>> remember.
> Okay, sounds like it's a political issue. I'll push the first patch
> which keeps changes to a minimum.
>
> Pip
>

Back then, the future of the new GC was a question, so Gerd said 
(https://lists.gnu.org/archive/html/emacs-devel/2024-03/msg00544.html) that
"Please don't take my GC efforts into consideration. That may succeed or 
not. But this is also a matter of good design, using the stack, (which 
BTW pdumper does, too), vs. bad design." That's why we went with the 
fastest implementation that doesn't use lisp vectors for storage. But we 
suspected that this JSON parser design will likely cause a problem with 
the new GC. So I think even if it turned out that the current problem 
was not caused by the parser, I still think that there should be 
something done about this JSON parser design to eliminate this potential 
problem. The lisp vector based approach was reverted because it added an 
extra pressure to the GC. For large JSON messages, it doesn't matter too 
much, but when the JSON is small, the extra GC time made the parser 
measurably slower. But, as far as I remember, that version hadn't have 
the small internal storage optimization yet. If we convert back to the 
vector based approach, the extra GC pressure will be smaller (compared 
to the original vector based approach without the internal storage), as 
for smaller sizes the vector won't be actually used.

Géza

[-- Attachment #2: Type: text/html, Size: 2770 bytes --]

^ permalink raw reply	[flat|nested] 25+ messages in thread

* bug#74547: 31.0.50; igc: assertion failed in buffer.c
  2024-12-01 16:32                       ` Geza Herman
@ 2024-12-01 19:41                         ` Gerd Möllmann
  2024-12-01 21:15                         ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
  1 sibling, 0 replies; 25+ messages in thread
From: Gerd Möllmann @ 2024-12-01 19:41 UTC (permalink / raw)
  To: Geza Herman; +Cc: Pip Cet, Óscar Fuentes, 74547

Geza Herman <geza.herman@gmail.com> writes:

> On 12/1/24 16:48, Pip Cet wrote:
>
>  Gerd Möllmann <gerd.moellmann@gmail.com> writes:
>
>  Yeah, I'd prefer using Lisp_Vectors too, and it was actually implemented
> at some point, but removed again, see
>
>   https://yhetil.org/emacs-devel/87edc1rzig.fsf@gmail.com/
>
> I vaguely remember a longer thread about GC in json.c at the time. Could
> be that that was before igc became a realistic possibility, don't
> remember.
>
>
> Okay, sounds like it's a political issue. I'll push the first patch
> which keeps changes to a minimum.
>
> Pip
>
> Back then, the future of the new GC was a question, so Gerd said
> (https://lists.gnu.org/archive/html/emacs-devel/2024-03/msg00544.html) that
> "Please don't take my GC efforts into consideration. That may succeed or not. But this is also a matter of good design,
> using the stack, (which BTW pdumper does, too), vs. bad design." That's why we went with the fastest implementation that
> doesn't use lisp vectors for storage. But we suspected that this JSON parser design will likely cause a problem with the
> new GC. So I think even if it turned out that the current problem was not caused by the parser, I still think that there
> should be something done about this JSON parser design to eliminate this potential problem. The lisp vector based
> approach was reverted because it added an extra pressure to the GC. For large JSON messages, it doesn't matter too much,
> but when the JSON is small, the extra GC time made the parser measurably slower. But, as far as I remember, that version
> hadn't have the small internal storage optimization yet. If we convert back to the vector based approach, the extra GC
> pressure will be smaller (compared to the original vector based approach without the internal storage), as for smaller
> sizes the vector won't be actually used.
>
> Géza

Sorry again for not remembering this earlier. It only resurfaced slowly
in my mind when I saw Pip's patch.





^ permalink raw reply	[flat|nested] 25+ messages in thread

* bug#74547: 31.0.50; igc: assertion failed in buffer.c
  2024-12-01 16:32                       ` Geza Herman
  2024-12-01 19:41                         ` Gerd Möllmann
@ 2024-12-01 21:15                         ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2024-12-04 19:11                           ` Geza Herman
  1 sibling, 1 reply; 25+ messages in thread
From: Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-12-01 21:15 UTC (permalink / raw)
  To: Geza Herman; +Cc: Gerd Möllmann, 74547, Óscar Fuentes

"Geza Herman" <geza.herman@gmail.com> writes:
>    On 12/1/24 16:48, Pip Cet wrote:
> Gerd M¶llmann <gerd.moellmann@gmail.com> writes:
>
>    Back then, the future of the new GC was a question, so Gerd said
>    (https://lists.gnu.org/archive/html/emacs-devel/2024-03/msg00544.html)
>    that
>    "Please don't take my GC efforts into consideration. That may succeed
>    or not. But this is also a matter of good design, using the stack,
>    (which BTW pdumper does, too), vs. bad design." That's why we went with
>    the fastest implementation that doesn't use lisp vectors for storage.
>    But we suspected that this JSON parser design will likely cause a
>    problem with the new GC. So I think even if it turned out that the
>    current problem was not caused by the parser, I still think that there
>    should be something done about this JSON parser design to eliminate
>    this potential problem. The lisp vector based approach was reverted
>    because it added an extra pressure to the GC. For large JSON messages,
>    it doesn't matter too much, but when the JSON is small, the extra GC
>    time made the parser measurably slower. But, as far as I remember, that
>    version hadn't have the small internal storage optimization yet. If we
>    convert back to the vector based approach, the extra GC pressure will
>    be smaller (compared to the original vector based approach without the
>    internal storage), as for smaller sizes the vector won't be actually
>    used.
>    G©za

Thank you for the summary, that makes sense. Is there a standard corpus
of JSON documents that you use to benchmark the code? That would be very
helpful, I think, since Eli correctly points out JSON parsing
performance is critical.

My gut feeling is that we should get rid of the object_workspace
entirely, instead modifying the general Lisp code to avoid performance
issues (and sacrifice some memory in the process, on most systems).

When building a hash table, we can do so directly and fine-tune the hash
table code not to reallocate too often. I'd imagine such fine tuning
would be generally useful (JSON-derived hash tables are unlikely to
exceed the initial 65 elements, but when they do, growing by a factor of
four might be appropriate).

When building a vector, we might want to introduce a `vtruncate'
function which destructively reduces a vector's size without
reallocating it. Again, I think that function would be useful in a few
other places.

Then we could start by allocating a 64-element vector, fill in the array
elements, grow it in the rare case that we exceed 64 elements, and
truncate it in the common case that fewer than 64 slots are used.  No
need to copy anything from the stack to the heap, the elements would
just appear where they are needed.

However, some memory would be wasted, and on low-memory systems, we
might want to define `vtruncate' and `hash-table-truncate' to reduce
memory usage.

Here's some code which might illustrate this idea, but WON'T WORK
yet, since the old GC requires vtruncate to do more work.

From 9c84c08fd9d4bb9c419025787663b7f7f2611952 Mon Sep 17 00:00:00 2001
From: Pip Cet <pipcet@protonmail.com>
Date: Sun, 1 Dec 2024 21:00:46 +0000
Subject: [PATCH] Optimize json.c performance

* src/alloc.c (Fvtruncate): New function.
(syms_of_alloc): Register it.
* src/fns.c (Fhash_table_truncate): New function.
(syms_of_fns): Register it.
* src/json.c (JSON_PARSER_INTERNAL_OBJECT_WORKSPACE_SIZE): Rename to ...
(JSON_PARSER_INITIAL_VECTOR_SIZE): ... this.
(struct json_parser): Remove object workspace.
(json_parser_init): Adjust to removed object workspace.
(json_make_object_workspace_for_slow_path,
json_make_object_workspace_for): Remove.
(json_parse_array): Parse directly to a heap vector, truncate it when
done.
(json_parse_object): Parse directly to a hash table, truncate it when
done.
---
 src/alloc.c |  25 +++++++++
 src/fns.c   |  13 +++++
 src/json.c  | 143 +++++++++++++---------------------------------------
 3 files changed, 74 insertions(+), 107 deletions(-)

diff --git a/src/alloc.c b/src/alloc.c
index 55126b1d551..b78c27ccf35 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -3935,6 +3935,30 @@ DEFUN ("vector", Fvector, Svector, 0, MANY, 0,
   return val;
 }
 
+DEFUN ("vtruncate", Fvtruncate, Svtruncate, 2, 2, 0,
+       doc: /* Truncate VECTOR so only the first LENGTH elements remain.
+
+Return a vector to be used instead of VECTOR, which may also be modified
+destructively.  This function is a performance optimization.  */)
+  (Lisp_Object length, Lisp_Object vector)
+{
+  CHECK_TYPE (FIXNATP (length), Qwholenump, length);
+  CHECK_TYPE (VECTORP (vector) &&
+	      PSEUDOVECTOR_TYPE (XVECTOR (vector)) == PVEC_NORMAL_VECTOR,
+	      Qvectorp, vector);
+  if (XFIXNAT (length) > ASIZE (vector))
+    signal_error ("vector too short", vector);
+  if (XFIXNAT (length) == 0)
+    return zero_vector;
+
+#ifdef HAVE_MPS
+  XVECTOR (vector)->header.size = XFIXNAT (length);
+  return vector;
+#else
+  return Fvector (XFIXNAT (length), XVECTOR (vector)->contents);
+#endif
+}
+
 DEFUN ("make-byte-code", Fmake_byte_code, Smake_byte_code, 4, MANY, 0,
        doc: /* Create a byte-code object with specified arguments as elements.
 The arguments should be the ARGLIST, bytecode-string BYTE-CODE, constant
@@ -8600,6 +8624,7 @@ syms_of_alloc (void)
   defsubr (&Sgarbage_collect_maybe);
   defsubr (&Smemory_info);
   defsubr (&Smemory_use_counts);
+  defsubr (&Svtruncate);
 #if defined GNU_LINUX && defined __GLIBC__ && \
   (__GLIBC__ > 2 || __GLIBC_MINOR__ >= 10)
 
diff --git a/src/fns.c b/src/fns.c
index f8191d72443..51bc7488457 100644
--- a/src/fns.c
+++ b/src/fns.c
@@ -6651,6 +6651,18 @@ DEFUN ("define-hash-table-test", Fdefine_hash_table_test,
   return Fput (name, Qhash_table_test, list2 (test, hash));
 }
 
+DEFUN ("hash-table-truncate", Fhash_table_truncate,
+       Shash_table_truncate, 1, 1, 0,
+       doc: /* Indicate that TABLE is unlikely to grow further.
+
+Returns TABLE, with its internal structures potentially reduced to fit
+the current number of elements precisely.  This function is a
+performance optimization.  */)
+  (Lisp_Object table)
+{
+  return table;
+}
+
 DEFUN ("internal--hash-table-histogram",
        Finternal__hash_table_histogram,
        Sinternal__hash_table_histogram,
@@ -7408,6 +7420,7 @@ syms_of_fns (void)
   defsubr (&Shash_table_rehash_threshold);
   defsubr (&Shash_table_size);
   defsubr (&Shash_table_test);
+  defsubr (&Shash_table_truncate);
   defsubr (&Shash_table_weakness);
   defsubr (&Shash_table_p);
   defsubr (&Sclrhash);
diff --git a/src/json.c b/src/json.c
index 0e17b893087..dd8e45003c4 100644
--- a/src/json.c
+++ b/src/json.c
@@ -535,7 +535,7 @@ DEFUN ("json-insert", Fjson_insert, Sjson_insert, 1, MANY,
 }
 
 
-#define JSON_PARSER_INTERNAL_OBJECT_WORKSPACE_SIZE 64
+#define JSON_PARSER_INITIAL_VECTOR_SIZE 64
 #define JSON_PARSER_INTERNAL_BYTE_WORKSPACE_SIZE 512
 
 struct json_parser
@@ -565,22 +565,8 @@ #define JSON_PARSER_INTERNAL_BYTE_WORKSPACE_SIZE 512
 
   size_t additional_bytes_count;
 
-  /* Lisp_Objects are collected in this area during object/array
-     parsing.  To avoid allocations, initially
-     internal_object_workspace is used.  If it runs out of space then
-     we switch to allocated space.  Important note: with this design,
-     GC must not run during JSON parsing, otherwise Lisp_Objects in
-     the workspace may get incorrectly collected. */
-  Lisp_Object internal_object_workspace
-  [JSON_PARSER_INTERNAL_OBJECT_WORKSPACE_SIZE];
-  Lisp_Object *object_workspace;
-  Lisp_Object object_workspace_vector;
-  size_t object_workspace_size;
-  size_t object_workspace_current;
-
-  /* String and number parsing uses this workspace.  The idea behind
-     internal_byte_workspace is the same as the idea behind
-     internal_object_workspace */
+  /* String and number parsing uses this workspace.  It starts out on
+     the stack, but moves to the heap if more space is needed.  */
   unsigned char
   internal_byte_workspace[JSON_PARSER_INTERNAL_BYTE_WORKSPACE_SIZE];
   unsigned char *byte_workspace;
@@ -638,12 +624,6 @@ json_parser_init (struct json_parser *parser,
 
   parser->additional_bytes_count = 0;
 
-  parser->object_workspace = parser->internal_object_workspace;
-  parser->object_workspace_size
-    = JSON_PARSER_INTERNAL_OBJECT_WORKSPACE_SIZE;
-  parser->object_workspace_current = 0;
-  parser->object_workspace_vector = Qnil;
-
   parser->byte_workspace = parser->internal_byte_workspace;
   parser->byte_workspace_end = (parser->byte_workspace
 				+ JSON_PARSER_INTERNAL_BYTE_WORKSPACE_SIZE);
@@ -657,50 +637,6 @@ json_parser_done (void *parser)
     xfree (p->byte_workspace);
 }
 
-/* Makes sure that the object_workspace has 'size' available space for
-   Lisp_Objects */
-NO_INLINE static void
-json_make_object_workspace_for_slow_path (struct json_parser *parser,
-					  size_t size)
-{
-  if (NILP (parser->object_workspace_vector))
-    {
-      parser->object_workspace_vector =
-	Fvector(parser->object_workspace_current, parser->object_workspace);
-    }
-  size_t needed_workspace_size
-    = (parser->object_workspace_current + size);
-  size_t new_workspace_size = parser->object_workspace_size;
-  while (new_workspace_size < needed_workspace_size)
-    {
-      if (ckd_mul (&new_workspace_size, new_workspace_size, 2))
-	{
-	  json_signal_error (parser, Qjson_out_of_memory);
-	}
-    }
-
-  Lisp_Object new_workspace_vector =
-    larger_vector (parser->object_workspace_vector,
-		   new_workspace_size - parser->object_workspace_size, -1);
-
-  Lisp_Object *new_workspace_ptr = XVECTOR (new_workspace_vector)->contents;
-
-  parser->object_workspace_vector = new_workspace_vector;
-  parser->object_workspace = new_workspace_ptr;
-  parser->object_workspace_size = new_workspace_size;
-}
-
-INLINE void
-json_make_object_workspace_for (struct json_parser *parser,
-				size_t size)
-{
-  if (parser->object_workspace_size - parser->object_workspace_current
-      < size)
-    {
-      json_make_object_workspace_for_slow_path (parser, size);
-    }
-}
-
 static void
 json_byte_workspace_reset (struct json_parser *parser)
 {
@@ -1258,10 +1194,18 @@ json_parse_number (struct json_parser *parser, int c)
 json_parse_array (struct json_parser *parser)
 {
   int c = json_skip_whitespace (parser);
-
-  const size_t first = parser->object_workspace_current;
   Lisp_Object result = Qnil;
+  ptrdiff_t index = 0;
 
+  switch (parser->conf.array_type)
+    {
+    case json_array_array:
+      result = make_vector (0, Qnil);
+      break;
+
+    default:
+      break;
+    }
   if (c != ']')
     {
       parser->available_depth--;
@@ -1277,10 +1221,15 @@ json_parse_array (struct json_parser *parser)
 	  switch (parser->conf.array_type)
 	    {
 	    case json_array_array:
-	      json_make_object_workspace_for (parser, 1);
-	      parser->object_workspace[parser->object_workspace_current]
-		= element;
-	      parser->object_workspace_current++;
+	      if (index == ASIZE (result))
+		{
+		  ptrdiff_t incr = ASIZE (result);
+		  if (incr == 0)
+		    incr = JSON_PARSER_INITIAL_VECTOR_SIZE;
+		  result = larger_vector (result, incr, -1);
+		}
+	      ASET (result, index, element);
+	      index++;
 	      break;
 	    case json_array_list:
 	      {
@@ -1310,18 +1259,8 @@ json_parse_array (struct json_parser *parser)
   switch (parser->conf.array_type)
     {
     case json_array_array:
-      {
-	size_t number_of_elements
-	  = parser->object_workspace_current - first;
-	result = make_vector (number_of_elements, Qnil);
-	for (size_t i = 0; i < number_of_elements; i++)
-	  {
-	    rarely_quit (~i);
-	    ASET (result, i, parser->object_workspace[first + i]);
-	  }
-	parser->object_workspace_current = first;
-	break;
-      }
+      result = Fvtruncate (result, make_fixnum (index));
+      break;
     case json_array_list:
       break;
     default:
@@ -1349,10 +1288,18 @@ json_parse_object_member_value (struct json_parser *parser)
 json_parse_object (struct json_parser *parser)
 {
   int c = json_skip_whitespace (parser);
-
-  const size_t first = parser->object_workspace_current;
   Lisp_Object result = Qnil;
 
+  switch (parser->conf.object_type)
+    {
+    case json_object_hashtable:
+      result = CALLN (Fmake_hash_table, QCtest, Qequal);
+      break;
+
+    default:
+      break;
+    }
+
   if (c != '}')
     {
       parser->available_depth--;
@@ -1374,11 +1321,7 @@ json_parse_object (struct json_parser *parser)
 	      {
 		Lisp_Object key = json_parse_string (parser, false, false);
 		Lisp_Object value = json_parse_object_member_value (parser);
-		json_make_object_workspace_for (parser, 2);
-		parser->object_workspace[parser->object_workspace_current] = key;
-		parser->object_workspace_current++;
-		parser->object_workspace[parser->object_workspace_current] = value;
-		parser->object_workspace_current++;
+		Fputhash (key, value, result);
 		break;
 	      }
 	    case json_object_alist:
@@ -1426,21 +1369,7 @@ json_parse_object (struct json_parser *parser)
     {
     case json_object_hashtable:
       {
-	EMACS_INT value = (parser->object_workspace_current - first) / 2;
-	result = make_hash_table (&hashtest_equal, value, Weak_None, false);
-	struct Lisp_Hash_Table *h = XHASH_TABLE (result);
-	for (size_t i = first; i < parser->object_workspace_current; i += 2)
-	  {
-	    hash_hash_t hash;
-	    Lisp_Object key = parser->object_workspace[i];
-	    Lisp_Object value = parser->object_workspace[i + 1];
-	    ptrdiff_t i = hash_lookup_get_hash (h, key, &hash);
-	    if (i < 0)
-	      hash_put (h, key, value, hash);
-	    else
-	      set_hash_value_slot (h, i, value);
-	  }
-	parser->object_workspace_current = first;
+	result = Fhash_table_truncate (result);
 	break;
       }
     case json_object_alist:
-- 
2.47.0






^ permalink raw reply related	[flat|nested] 25+ messages in thread

* bug#74547: 31.0.50; igc: assertion failed in buffer.c
  2024-12-01 21:15                         ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2024-12-04 19:11                           ` Geza Herman
  2024-12-22 10:29                             ` Óscar Fuentes
  0 siblings, 1 reply; 25+ messages in thread
From: Geza Herman @ 2024-12-04 19:11 UTC (permalink / raw)
  To: Pip Cet; +Cc: Gerd Möllmann, 74547, Óscar Fuentes


On 12/1/24 22:15, Pip Cet wrote:
> "Geza Herman" <geza.herman@gmail.com> writes:
>>     On 12/1/24 16:48, Pip Cet wrote:
>> Gerd M¶llmann <gerd.moellmann@gmail.com> writes:
>>
>>     Back then, the future of the new GC was a question, so Gerd said
>>     (https://lists.gnu.org/archive/html/emacs-devel/2024-03/msg00544.html)
>>     that
>>     "Please don't take my GC efforts into consideration. That may succeed
>>     or not. But this is also a matter of good design, using the stack,
>>     (which BTW pdumper does, too), vs. bad design." That's why we went with
>>     the fastest implementation that doesn't use lisp vectors for storage.
>>     But we suspected that this JSON parser design will likely cause a
>>     problem with the new GC. So I think even if it turned out that the
>>     current problem was not caused by the parser, I still think that there
>>     should be something done about this JSON parser design to eliminate
>>     this potential problem. The lisp vector based approach was reverted
>>     because it added an extra pressure to the GC. For large JSON messages,
>>     it doesn't matter too much, but when the JSON is small, the extra GC
>>     time made the parser measurably slower. But, as far as I remember, that
>>     version hadn't have the small internal storage optimization yet. If we
>>     convert back to the vector based approach, the extra GC pressure will
>>     be smaller (compared to the original vector based approach without the
>>     internal storage), as for smaller sizes the vector won't be actually
>>     used.
>>     G©za
> Thank you for the summary, that makes sense. Is there a standard corpus
> of JSON documents that you use to benchmark the code? That would be very
> helpful, I think, since Eli correctly points out JSON parsing
> performance is critical.

I'm not aware of such a corpus. When I developed the new JSON parser, 
the performance difference was so large so it was obvious that the new 
parser is faster. But I did benchmarks on JSONs which was generated by 
LSP communication (maybe I can share this one, if there is interest, but 
I need to anonymize it first), and also I did a benchmark on all the 
JSONs I found on my computer.

But this time, the performance difference is expected to be smaller, 
using lisp vectors shouldn't have a very large effect on performance. 
I'd check the performance with small JSONs, but large enough ones where 
the (non-internal) object_workspace is actually get used (make sure to 
run a lot of iterations, so the amortized GC time will be included in 
the result). For larger JSONs, we shouldn't have a difference, as all 
the other allocations (which store the actual result of the parsing) 
should hide the additional lisp vector allocation cost. At least, this 
is my theory.


> My gut feeling is that we should get rid of the object_workspace
> entirely, instead modifying the general Lisp code to avoid performance
> issues (and sacrifice some memory in the process, on most systems).
object_workspace is only grown once for the lifetime of one parsing. 
Once it is grown to the needed size, the only extra cost when parsing a 
value is to copy the data to its final place from the object_workspace. 
Truncate based solution does the same copy, but it also needs to grow 
the hashtable/array for each value, so it executes more allocations and 
copies than the current solution. So I'd prefer if we kept 
object_workspace. If the only solution is to convert it to a lisp 
vector, then I think we should do that. But again, this is just my 
theory. If we try the truncate based solution, and if it turns out that 
it's not significantly slower, then it can be a good solution as well.






^ permalink raw reply	[flat|nested] 25+ messages in thread

* bug#74547: 31.0.50; igc: assertion failed in buffer.c
  2024-12-04 19:11                           ` Geza Herman
@ 2024-12-22 10:29                             ` Óscar Fuentes
  0 siblings, 0 replies; 25+ messages in thread
From: Óscar Fuentes @ 2024-12-22 10:29 UTC (permalink / raw)
  To: 74547-done; +Cc: Gerd Möllmann, Pip Cet, Geza Herman

After extensive use, I can say with great confidence that this bug is
fixed.

Closing. Thanks to all.





^ permalink raw reply	[flat|nested] 25+ messages in thread

end of thread, other threads:[~2024-12-22 10:29 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-11-26 18:35 bug#74547: 31.0.50; igc: assertion failed in buffer.c Óscar Fuentes
2024-11-27  6:54 ` Gerd Möllmann
2024-12-01 10:49   ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-12-01 12:05     ` Gerd Möllmann
2024-12-01 12:17       ` Gerd Möllmann
2024-12-01 12:30         ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-12-01 12:39           ` Gerd Möllmann
2024-12-01 12:57             ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-12-01 13:30               ` Gerd Möllmann
2024-12-01 14:58                 ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-12-01 15:18                   ` Gerd Möllmann
2024-12-01 15:48                     ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-12-01 16:32                       ` Geza Herman
2024-12-01 19:41                         ` Gerd Möllmann
2024-12-01 21:15                         ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-12-04 19:11                           ` Geza Herman
2024-12-22 10:29                             ` Óscar Fuentes
2024-12-01 15:55                     ` Eli Zaretskii
2024-12-01 15:23                   ` Eli Zaretskii
2024-12-01 15:30                   ` Óscar Fuentes
2024-12-01 15:48                     ` Gerd Möllmann
2024-12-01 15:58                     ` Pip Cet via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-12-01 16:24                       ` Óscar Fuentes
2024-12-01 13:18         ` Óscar Fuentes
2024-12-01 13:44           ` Gerd Möllmann

Code repositories for project(s) associated with this external index

	https://git.savannah.gnu.org/cgit/emacs.git
	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.