Search code examples
c++runtimellvmllvm-iraddress-sanitizer

Error in LLVM IR or runtime library produces SEGV


I'm writing a programming language called PPL.

In PPL integer literals are arbitrary width by default. This is archived with using pointer to GMP's mpz_class for integers.

However, when compiling -1, there is an error from address sanitiser:

==92833==ERROR: AddressSanitizer: SEGV on unknown address 0x000100000006 (pc 0x000105564bc4 bp 0x000105019f14 sp 0x00016ce45e50 T0)
==92833==The signal is caused by a UNKNOWN memory access.
    #0 0x105564bc4 in __gmpz_neg+0x14 (libgmp.10.dylib:arm64+0x14bc4) (BuildId: efc29ca33b2a3664976db890d76d3d0832000000200000000100000000000c00)

Here are parts of runtime, related to the problem:


// Temporary solution for not leaking memory,
// as I haven't implemented memory management yet
std::unordered_set<mpz_class> values;

// PPL's big integer type
using Integer = const mpz_class *;

extern "C" {

// Used to create integer from literal
Integer _IntegerConstructorFromCString(const char *string)
{
    assert(string);
    // Inserts value and returns pointer to it
    return &*values.emplace(mpz_class(string)).first;
}

/// - <:Integer> -> Integer
Integer _MinusInteger(Integer value)
{
    // I checked in debugger, here value is 0x000100000006,
    // which isn't a pointer I returned from _IntegerConstructorFromCString

    assert(value); 
    // Inserts value and returns pointer to it
    return &*values.emplace(-*value).first;
}

} // extern "C"

Here is LLVM IR generated by PPL's compiler:

@.str = private unnamed_addr constant [2 x i8] c"1\00", align 1

// Code for "-1" top level expression
define void @_top_level_code() {
  // Create integer from "1"
  %1 = call ptr @_IntegerConstructorFromCString(ptr getelementptr inbounds ([2 x i8], ptr @.str, i32 0, i32 0))
  // Get -1
  %2 = call ptr @"- <:Integer>"(ptr %1)
  ret void
}

// Function from runtime
declare ptr @_MinusInteger(ptr %0)

// PPL's operator that hides runtime function invokation
define ptr @"- <:Integer>"(ptr %a) {
  %1 = load ptr, ptr %a, align 8
  %2 = call ptr @_MinusInteger(ptr %1)
  ret ptr %2
}

What's wrong with my code?

P.S: may the problem be in the way I access function argument without alloca? Or I don't dereference a pointer somewhere? (hard to say for me, as all of them are opaque)


Solution

  • I solved the problem with removing load of function arguments.

    Instead of:

    define ptr @"- <:Integer>"(ptr %a) {
      %1 = load ptr, ptr %a, align 8 // This is wrong for some reason.
      // Looks like arguments aren't pointers themself
    
    
      %2 = call ptr @_MinusInteger(ptr %1)
      ret ptr %2
    }
    

    Compiler now generates:

    define ptr @"- <:Integer>"(ptr %a) {
      %1 = call ptr @_MinusInteger(ptr %a)
      ret ptr %1
    }