Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Regression] SIGSEGV on 1.6.2 on C function call, works on 1.0.0 up to 1.6.0 #19378

Closed
arkanoid87 opened this issue Jan 13, 2022 · 8 comments
Closed

Comments

@arkanoid87
Copy link
Contributor

Forum post:

https://forum.nim-lang.org/t/8796

Repo with minimal test case and C version to compare

https://github.com/arkanoid87/futhest

Re-posting forum thread here:

I've been scratching my head solving a SIGSEGV on my machine when using futhark. I've reduced the problem to a self contained Nim and C files with no external nim packages involved, just plain C linkage.

The C program compiles and runs correctly, the Nim program goes SIGSEGV while calling C function, but they should be 1:1

You can find dockerfiles for reproducible builds and Makefile here: https://github.com/arkanoid87/futhest.

shared header.h

int addition(int num1, int num2) {
    return num1+num2;
}

futhest.c

#include <assert.h>
#include <stdio.h>
#include "clang-c/Index.h"


enum CXChildVisitResult
visitor(CXCursor cursor, CXCursor parent, CXClientData clientData) {
    CXFile file;
    unsigned int line;
    unsigned int column;
    unsigned int offset;

    CXSourceLocation loc = clang_getCursorLocation(cursor);
    clang_getFileLocation(loc, &file, &line, &column, &offset);

    CXString filename = clang_getFileName(file);   
    printf("%s [%d:%d, %d]\n", clang_getCString(filename), line, column, offset);
    clang_disposeString(filename);

    return CXChildVisit_Continue;
}

int main (void) { 
    CXIndex Idx = clang_createIndex(0, 0);

    CXTranslationUnit TU = clang_parseTranslationUnit(Idx, 
        "src/header.h", NULL, 0, NULL, 0, 0);

    assert(TU != NULL);

    CXCursor cursor = clang_getTranslationUnitCursor(TU);

    clang_visitChildren(cursor, visitor, NULL);

    clang_disposeTranslationUnit(TU);

    printf("END");
}

C Output:

./futhest_c 
src/header.h [1:5, 4]
END⏎

futhest.nim

type
  CXIndex = pointer
  CXTranslationUnit = pointer
  CXCursor* {.bycopy.} = object
    kind*: byte
    xdata*: cint
    data*: array[3, pointer]

#[
CINDEX_LINKAGE CXIndex clang_createIndex(int excludeDeclarationsFromPCH,
                                         int displayDiagnostics);
]#
proc createIndex*(excludeDeclarationsFromPCH: cint; displayDiagnostics: cint): CXIndex {.
    importc: "clang_createIndex", cdecl.}


#[
CINDEX_LINKAGE CXTranslationUnit
clang_parseTranslationUnit(CXIndex CIdx,
                           const char *source_filename,
                           const char *const *command_line_args,
                           int num_command_line_args,
                           struct CXUnsavedFile *unsaved_files,
                           unsigned num_unsaved_files,
                           unsigned options);
]#
proc parseTranslationUnit*(CIdx: CXIndex; source_filename: cstring;
                          command_line_args: cstringArray;
                          num_command_line_args: cint;
                          unsaved_files: pointer;
                          num_unsaved_files: cuint; options: cuint): CXTranslationUnit {.
    importc: "clang_parseTranslationUnit", cdecl.}


#[
  CINDEX_LINKAGE CXCursor clang_getTranslationUnitCursor(CXTranslationUnit);
]#
proc getTranslationUnitCursor*(a1: CXTranslationUnit): CXCursor {.
    importc: "clang_getTranslationUnitCursor", cdecl.}


#[
  CINDEX_LINKAGE void clang_disposeTranslationUnit(CXTranslationUnit);
]#
proc disposeTranslationUnit*(a1: CXTranslationUnit) {.importc: "clang_disposeTranslationUnit", cdecl.}


# ----------------------------------------------------------------------------


var
  index = createIndex(0, 0)
  unit = parseTranslationUnit(index, "src/header.h".cstring, nil, 0, nil, 0, 0)

doAssert not unit.isNil

var cursor = getTranslationUnitCursor(unit) # SIGSEGV

# never reached
disposeTranslationUnit(unit)

echo "END"

Nim output:

./futhest
Traceback (most recent call last)
/home/jack/nim/futhest/src/futhest.nim(57) futhest
SIGSEGV: Illegal storage access. (Attempt to read from nil?)
fish: “./futhest” terminated by signal SIGSEGV (Address boundary error)

Additional Information

  • 1.7.1 devel 9888a29: SIGSEGV
  • 1.6.2: SIGSEGV
  • 1.6.0: OK
  • 1.4.8: OK
  • 1.2.0: OK
  • 1.0.0: OK
@ghost
Copy link

ghost commented Jan 13, 2022

Isn't this a duplicate of #19342 ?

@ringabout
Copy link
Member

ringabout commented Jan 13, 2022

I think so, too.

type
  CXCursor* {.bycopy.} = object
    kind*: byte
    xdata*: cint
    data*: array[3, pointer]

is passed by reference but shouldn't.

@arkanoid87
Copy link
Contributor Author

arkanoid87 commented Jan 13, 2022

I think so, too.

type
  CXCursor* {.bycopy.} = object
    kind*: byte
    xdata*: cint
    data*: array[3, pointer]

is passed by reference but shouldn't.

The SIGSEGV happens in cland_getTranslationUnitCursor(unit) function, specifically here https://github.com/llvm/llvm-project/blob/ef32c611aa214dea855364efd7ba451ec5ec3f74/clang/tools/libclang/CIndex.cpp#L4208
According to gdb

See PMunch/futhark#11 for some backlog

@ringabout
Copy link
Member

ringabout commented Jan 13, 2022

It may be related: #19385

Sorry, I cannot test this issue locally, I don't get clang installed (I use windows and it is a hassle to use/install clang).

@arkanoid87
Copy link
Contributor Author

arkanoid87 commented Jan 13, 2022

It may be related: #19385

Sorry, I cannot test this issue locally, I don't get clang installed (I use windows and it is a hassle to use/install clang).

In the repository you find two Dockerfiles, one for Ubuntu and one for Alpine-linux. Both should work on Docker for windows, too (untested though)

Both replicate the problem

@ringabout
Copy link
Member

In the repository you find two Dockerfiles, one for Ubuntu and one for Alpine-linux. Both should work on Docker for windows, too (untested though)

I see, thanks

@ghost
Copy link

ghost commented Jan 13, 2022

Closing as a duplicate of #19342, as I said in https://forum.nim-lang.org/t/8796 that's the actual cause, not sure why you opened a separate issue. The crash happens in the libclang function - yes, but that's only because Nim passes an invalid number of arguments to it because it applies NRVO to a bycopy object.

From the generated C code you can see that the clang_getTranslationUnitCursor function is called with two arguments but it should in fact be called with one:

N_LIB_PRIVATE N_NIMCALL(void, NimMainModule)(void) {
{
	index__futhest_22 = clang_createIndex(((int) 0), ((int) 0));
	unit__futhest_23 = clang_parseTranslationUnit(index__futhest_22, "src/header.h", ((NCSTRING*) NIM_NIL), ((int) 0), NIM_NIL, ((unsigned int) 0), ((unsigned int) 0));
	{
		if (!!(!((unit__futhest_23 == 0)))) goto LA3_;
		failedAssertImpl__systemZassertions_56(((NimStringDesc*) &TM__FOvY5sgE9cCQaUMA1Y2m1uQ_2));
	}
	LA3_: ;
	clang_getTranslationUnitCursor(unit__futhest_23, (&cursor__futhest_29));
	clang_disposeTranslationUnit(unit__futhest_23);
	echoBinSafe(TM__FOvY5sgE9cCQaUMA1Y2m1uQ_3, 1);
}

@ghost ghost closed this as completed Jan 13, 2022
@arkanoid87
Copy link
Contributor Author

I've been impatient, you're right.

Thanks for the explanation.

This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants