Segfault when allocating empty MutableArrayArray#
Summary
GHC 9.2.4 generates incorrect code that always segfaults when allocating an empty MutableArrayArray#
. GHC 9.0.2 and GHC 8.10.7 do not have this problem.
Steps to reproduce
Build and run this program:
{-# language MagicHash #-}
{-# language UnboxedTuples #-}
import GHC.Exts
import GHC.IO (IO(IO))
main :: IO ()
main = do
putStrLn "Begin"
sz <- IO $ \s0 -> case newArrayArray# 0# s0 of
(# s1, buf #) -> (# s1, I# (sizeofMutableArrayArray# buf) #)
print sz
putStrLn "End"
Expected behavior
The program should print:
Begin
0
End
Environment
- GHC version used: 9.2.4
Comments
On GHC HEAD, ArrayArray#
has been removed entirely in favor of Array#
, and Array#
does not have this problem. I think that all that is needed is a fix for the GHC 9.2 series. With git blame
on a copy of the GHC source from Jan 2022, I see:
a7c0387d20c rts/PrimOps.cmm (Simon Marlow 2012-10-03 09:30:56 +0100 454) stg_newArrayArrayzh ( W_ n /* words */ )
021a0dd265f rts/PrimOps.cmm (Manuel M T Chakravarty 2011-12-07 22:40:14 +1100 455) {
a6939ec29a9 rts/PrimOps.cmm (Johan Tibell 2014-03-20 07:58:10 +0100 456) W_ words, size, p;
a6939ec29a9 rts/PrimOps.cmm (Johan Tibell 2014-03-20 07:58:10 +0100 457) gcptr arr;
021a0dd265f rts/PrimOps.cmm (Manuel M T Chakravarty 2011-12-07 22:40:14 +1100 458)
a7c0387d20c rts/PrimOps.cmm (Simon Marlow 2012-10-03 09:30:56 +0100 459) MAYBE_GC_N(stg_newArrayArrayzh, n);
021a0dd265f rts/PrimOps.cmm (Manuel M T Chakravarty 2011-12-07 22:40:14 +1100 460)
021a0dd265f rts/PrimOps.cmm (Manuel M T Chakravarty 2011-12-07 22:40:14 +1100 461) // the mark area contains one byte for each 2^MUT_ARR_PTRS_CARD_BITS words
021a0dd265f rts/PrimOps.cmm (Manuel M T Chakravarty 2011-12-07 22:40:14 +1100 462) // in the array, making sure we round up, and then rounding up to a whole
021a0dd265f rts/PrimOps.cmm (Manuel M T Chakravarty 2011-12-07 22:40:14 +1100 463) // number of words.
021a0dd265f rts/PrimOps.cmm (Manuel M T Chakravarty 2011-12-07 22:40:14 +1100 464) size = n + mutArrPtrsCardWords(n);
021a0dd265f rts/PrimOps.cmm (Manuel M T Chakravarty 2011-12-07 22:40:14 +1100 465) words = BYTES_TO_WDS(SIZEOF_StgMutArrPtrs) + size;
30a1eeea37e rts/PrimOps.cmm (Ben Gamari 2017-09-26 15:09:13 -0400 466) ("ptr" arr) = ccall allocateMightFail(MyCapability() "ptr",words);
30a1eeea37e rts/PrimOps.cmm (Ben Gamari 2017-09-26 15:09:13 -0400 467) if (arr == NULL) {
30a1eeea37e rts/PrimOps.cmm (Ben Gamari 2017-09-26 15:09:13 -0400 468) jump stg_raisezh(base_GHCziIOziException_heapOverflow_closure);
30a1eeea37e rts/PrimOps.cmm (Ben Gamari 2017-09-26 15:09:13 -0400 469) }
46d05ba03d1 rts/PrimOps.cmm (Johan Tibell 2014-03-13 22:24:24 +0100 470) TICK_ALLOC_PRIM(SIZEOF_StgMutArrPtrs, WDS(size), 0);
021a0dd265f rts/PrimOps.cmm (Manuel M T Chakravarty 2011-12-07 22:40:14 +1100 471)
021a0dd265f rts/PrimOps.cmm (Manuel M T Chakravarty 2011-12-07 22:40:14 +1100 472) SET_HDR(arr, stg_MUT_ARR_PTRS_DIRTY_info, W_[CCCS]);
021a0dd265f rts/PrimOps.cmm (Manuel M T Chakravarty 2011-12-07 22:40:14 +1100 473) StgMutArrPtrs_ptrs(arr) = n;
021a0dd265f rts/PrimOps.cmm (Manuel M T Chakravarty 2011-12-07 22:40:14 +1100 474) StgMutArrPtrs_size(arr) = size;
021a0dd265f rts/PrimOps.cmm (Manuel M T Chakravarty 2011-12-07 22:40:14 +1100 475)
d159041b440 rts/PrimOps.cmm (Ben Gamari 2021-01-06 11:20:44 -0500 476) // Initialize card table to all-clean.
d159041b440 rts/PrimOps.cmm (Ben Gamari 2021-01-06 11:20:44 -0500 477) setCardsValue(arr, 0, n, 0);
d159041b440 rts/PrimOps.cmm (Ben Gamari 2021-01-06 11:20:44 -0500 478)
021a0dd265f rts/PrimOps.cmm (Manuel M T Chakravarty 2011-12-07 22:40:14 +1100 479) // Initialise all elements of the array with a pointer to the new array
021a0dd265f rts/PrimOps.cmm (Manuel M T Chakravarty 2011-12-07 22:40:14 +1100 480) p = arr + SIZEOF_StgMutArrPtrs;
021a0dd265f rts/PrimOps.cmm (Manuel M T Chakravarty 2011-12-07 22:40:14 +1100 481) for:
12056292280 rts/PrimOps.cmm (Andreas Klebinger 2018-01-29 18:25:00 -0500 482) if (p < arr + SIZEOF_StgMutArrPtrs + WDS(n)) (likely: True) {
f7c8c3d47be rts/PrimOps.cmm (Ian Lynagh 2013-06-09 14:48:32 +0100 483) W_[p] = arr;
f7c8c3d47be rts/PrimOps.cmm (Ian Lynagh 2013-06-09 14:48:32 +0100 484) p = p + WDS(1);
f7c8c3d47be rts/PrimOps.cmm (Ian Lynagh 2013-06-09 14:48:32 +0100 485) goto for;
021a0dd265f rts/PrimOps.cmm (Manuel M T Chakravarty 2011-12-07 22:40:14 +1100 486) }
021a0dd265f rts/PrimOps.cmm (Manuel M T Chakravarty 2011-12-07 22:40:14 +1100 487)
a7c0387d20c rts/PrimOps.cmm (Simon Marlow 2012-10-03 09:30:56 +0100 488) return (arr);
021a0dd265f rts/PrimOps.cmm (Manuel M T Chakravarty 2011-12-07 22:40:14 +1100 489) }
The only non-ancient change is this addition from @bgamari in Jan 2021:
// Initialize card table to all-clean.
setCardsValue(arr, 0, n, 0);
I can't tell whether or not setCardsValue
gets messed up when n = 0
though.