Segmentation fault with Dict

Can anyone let me know why I got Segmentation fault with this code:

struct Number(Copyable & Movable):
    var a: Int128 
    fn __init__(out self, owned a: Int128):
        self.a = a

fn main():
    var number = Dict[String, Number]()
    for idx in range(5):
        print("Adding number", idx)
        number[String(idx)] = Number(Int128(idx))
$ mojo life.mojo
Adding number 0
Adding number 1
Please submit a bug report to https://github.com/modular/modular/issues and include the crash backtrace along with all the relevant source codes.
Stack dump:
0.	Program arguments: mojo life.mojo
Stack dump without symbol names (ensure you have llvm-symbolizer in your PATH or set the environment var `LLVM_SYMBOLIZER_PATH` to point to it):
0  mojo                      0x000055f29485d6ab
1  mojo                      0x000055f29485b449
2  mojo                      0x000055f29485dd5a
3  libc.so.6                 0x00007f1af9c67070
4  libc.so.6                 0x00007f1af9cc0334
5  libc.so.6                 0x00007f1af9c66fbe gsignal + 30
6  libAsyncRTMojoBindings.so 0x00007f1afbdb2ac2
7  libc.so.6                 0x00007f1af9c67070
8  (error)                   0x00007f1a04002595
mojo crashed!
Please file a bug report.
Segmentation fault (core dumped)

this doesn’t crash for me with a recent build. I think I saw someone talking about Int128 → String having a bug and crashing, I think that recently got fixed, can you try it out with the most recent nightly?

I have just updated it to Mojo 25.5.0.dev2025061405 (b81f396d), and it still crashes.

I’ve also experimented with this and found that the segfault occurs only when there are at least two dictionary fields in the struct. I guess original question also had dicts in the struct, or maybe it was another question on the forums, though I can’t find it now.
The code below works fine; however, if you include commented lines, it will segfault. If you then also replace Int128 with Int64 or smaller, this would also work fine.

struct A(Writable, Copyable & Movable):
    var number: Int128
    var dict: Dict[String, Int]
    # var dict2: Dict[String, Int]

    fn __init__(out self, number: Int128, dict: Dict[String, Int], dict2: Dict[String, Int]):
        self.number = number
        self.dict = dict
        # self.dict2 = dict2


    fn __copyinit__(out self, existing: Self):
        print('copying')
        self.number = existing.number
        self.dict = existing.dict
        # self.dict2 = existing.dict2

    fn __moveinit__(out self, owned existing: Self):
        print('moving')
        self.number = existing.number
        self.dict = existing.dict
        # self.dict2 = existing.dict2

    
    fn write_to[W: Writer](self, mut writer: W) -> None:
        self.write_dict(writer, self.dict)
        writer.write(",")
        # self.write_dict(writer, self.dict2)

    @staticmethod
    fn write_dict[W: Writer, K: KeyElement & Writable, V: Copyable & Movable & Writable](mut writer: W, dict: Dict[K, V]) -> None:
        writer.write("{")
        first = True
        for entry in dict.items():
            if not first: writer.write(',')
            writer.write(entry.key, ":", entry.value)
            first = False
        writer.write("}")


def main():
    var structs = Dict[Int, A]()
    for i in range(2):
        d1 = Dict[String, Int]()
        d2 = Dict[String, Int]()
        structs[i] = A(i, d1, d2)
    for i in range(1):
        print(structs[i])

UPD:
This is the simplest program I found that crashes for me on the latest nightly, it won’t crash when you replace key type from String to Int or value type to something less than Int128

fn main():
    var number = Dict[String, Int128]()
    for idx in range(2):
        number[String(idx)] = Int128(idx)

I think it’s related to this: UInt256 returns wrong value - #6 by sora

When printing numbers > 64 bits it’s overwriting the inline array and corrupting the program.

In my latest example, I’m only populating the dictionary—there aren’t any print statements, so I’m not sure if that’s the same issue here.

It might be the String(idx), which also goes through the int formatting methods I think.

@clattner Can you let me know the nightly version that you are running?

To me it sounds as if this could be another version of this bug: [BUG] UB in Variant when using SIMD · Issue #4578 · modular/modular · GitHub
The Dict uses Variant internally, so that the issue above causes the following issue in Dict, which resembles the one reported here: [BUG] Segfault if using a struct based on SIMD as key in Dict · Issue #3781 · modular/modular · GitHub

1 Like

It has been a long time. Is there a fix?

Not that I am aware of. This has been blocking a project of mine for a long time now. Maybe someone from the modular staff can provide us with some insight as to when a fix may be expected.

1 Like

[stdlib] Fix int formatting to not go out of bounds, add MIN and MAX for 128 and 256 sized integers by sstadick · Pull Request #4852 · modular/modular · GitHub fixes both this issue, and the original issue UInt256 returns wrong value - #6 by sora.

The tests show the fix for format_int working. I also checked that:

fn main():
    var number = Dict[String, Int128]()
    for idx in range(2):
        number[String(idx)] = Int128(idx)

failed before the fix and works after.

Well, I guess that didn’t fix it all the way. The ubuntu test runner seg-faulted with that minimal dict example in there. My changes at least fix it on mac. So @samufi’s issue does seem to also be in play.