StanzaOrg / lbstanza-old

L.B. Stanza Programming Language
Other
216 stars 23 forks source link

lostanza String with `const char *` #172

Closed callendorph closed 1 year ago

callendorph commented 2 years ago

Hi,

I'm trying to wrap the gsl_strerror function but I'm having a lot of trouble. This seems pretty straight forward so I'm wondering if I'm doing something wrong.

Here is my stanza package for a small (hopefully) repeatable test case:

defpackage gsl/TestStr :
  import core

extern get_some_msg : () -> ptr<byte>

public lostanza defn get-some-msg () -> ref<String> :
  val msg:ptr<byte> = get_some_msg()
  return String(msg)

Here is a small C file with the function to import:


const char * get_some_msg() {
  return "Const String Message";
}

This is very similar to what the gsl_strerror function does.

I can then build by adding this to my package file:

packages gsl/* defined-in "src/"

package gsl/TestStr requires :
  ccfiles:
    "src/justatest.c"

...

From the Stanza repo - I think String should create a new char buffer and copy the passed char pointer null-terminated string into it.

When I run this test - I get a Seg Fault

[Test 3] const-str-test                                                                                                 
Segmentation fault (core dumped) 

For some reason - the const char * here always seg-faults. I've tried passing the msg:ptr<byte> to clib/strlen and clib/memcpy. Both of those also segfault on the msg object.

I think the const char * here is going to be placed in a different memory section.

So I then tried this C file:

const char *some_silly_msg = "Const String Message";

const char * get_some_msg() {
  return some_silly_msg;
}

So that I could find the const char * in memory. This program still seg faults.

$ readelf -a ./gsl-tests.exe | grep -C 4 some_silly_msg
 61356: 000000000056e6c0    88 FUNC    GLOBAL DEFAULT   14 gsl_vector_long_get
 61357: 0000000000585f40    62 FUNC    GLOBAL DEFAULT   14 cblas_csscal
 61358: 000000000056b060    52 FUNC    GLOBAL DEFAULT   14 gsl_vector_uint_set_zero
 61359: 00000000005738b0    93 FUNC    GLOBAL DEFAULT   14 gsl_error
 61360: 0000000000820ca8     8 OBJECT  GLOBAL DEFAULT   25 some_silly_msg
 61361: 000000000056ca70   118 FUNC    GLOBAL DEFAULT   14 gsl_vector_complex_float_
 61362: 0000000000569c90   132 FUNC    GLOBAL DEFAULT   14 gsl_vector_alloc
 61363: 0000000000570720    97 FUNC    GLOBAL DEFAULT   14 gsl_blas_caxpy
 61364: 000000000056ffa0    85 FUNC    GLOBAL DEFAULT   14 gsl_blas_sdsdot

So it is definitely there.

$ readelf -e ./gsl-tests.exe
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x401d60
  Start of program headers:          64 (bytes into file)
  Start of section headers:          5136928 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         9
  Size of section headers:           64 (bytes)
  Number of section headers:         38
  Section header string table index: 35

Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  [ 0]                   NULL             0000000000000000  00000000
       0000000000000000  0000000000000000           0     0     0
  [ 1] .interp           PROGBITS         0000000000400238  00000238
       000000000000001c  0000000000000000   A       0     0     1
  [ 2] .note.ABI-tag     NOTE             0000000000400254  00000254
       0000000000000020  0000000000000000   A       0     0     4
  [ 3] .note.gnu.build-i NOTE             0000000000400274  00000274
       0000000000000024  0000000000000000   A       0     0     4
  [ 4] .gnu.hash         GNU_HASH         0000000000400298  00000298
       0000000000000100  0000000000000000   A       5     0     8
  [ 5] .dynsym           DYNSYM           0000000000400398  00000398
       0000000000000900  0000000000000018   A       6     1     8
  [ 6] .dynstr           STRTAB           0000000000400c98  00000c98
       0000000000000307  0000000000000000   A       0     0     1
  [ 7] .gnu.version      VERSYM           0000000000400fa0  00000fa0
       00000000000000c0  0000000000000002   A       5     0     2
  [ 8] .gnu.version_r    VERNEED          0000000000401060  00001060
       00000000000000a0  0000000000000000   A       6     3     8
  [ 9] .rela.dyn         RELA             0000000000401100  00001100
       0000000000000540  0000000000000018   A       5     0     8
  [10] .rela.plt         RELA             0000000000401640  00001640
       0000000000000378  0000000000000018  AI       5    24     8
  [11] .init             PROGBITS         00000000004019b8  000019b8
       000000000000001a  0000000000000000  AX       0     0     4
  [12] .plt              PROGBITS         00000000004019e0  000019e0
       0000000000000260  0000000000000010  AX       0     0     16
  [13] .plt.got          PROGBITS         0000000000401c40  00001c40
       0000000000000118  0000000000000000  AX       0     0     8
  [14] .text             PROGBITS         0000000000401d60  00001d60
       0000000000197ab0  0000000000000000  AX       0     0     16
  [15] .fini             PROGBITS         0000000000599810  00199810
       0000000000000009  0000000000000000  AX       0     0     4
  [16] .rodata           PROGBITS         0000000000599820  00199820
       0000000000000d15  0000000000000000   A       0     0     16
  [17] .eh_frame_hdr     PROGBITS         000000000059a538  0019a538
       0000000000001214  0000000000000000   A       0     0     4
  [18] .eh_frame         PROGBITS         000000000059b750  0019b750
       00000000000067c4  0000000000000000   A       0     0     8
  [19] .init_array       INIT_ARRAY       00000000007a2c40  001a2c40
       0000000000000008  0000000000000000  WA       0     0     8
  [20] .fini_array       FINI_ARRAY       00000000007a2c48  001a2c48
       0000000000000008  0000000000000000  WA       0     0     8
  [21] .jcr              PROGBITS         00000000007a2c50  001a2c50
       0000000000000008  0000000000000000  WA       0     0     8
  [22] .dynamic          DYNAMIC          00000000007a2c58  001a2c58
       00000000000001f0  0000000000000010  WA       6     0     8
  [23] .got              PROGBITS         00000000007a2e48  001a2e48
       00000000000001b8  0000000000000008  WA       0     0     8
  [24] .got.plt          PROGBITS         00000000007a3000  001a3000
       0000000000000140  0000000000000008  WA       0     0     8
  [25] .data             PROGBITS         00000000007a3140  001a3140
       000000000007db70  0000000000000000  WA       0     0     8
  [26] .bss              NOBITS           0000000000820cc0  00220cb0
       0000000000000048  0000000000000000  WA       0     0     32
  [27] .comment          PROGBITS         0000000000000000  00220cb0
       0000000000000034  0000000000000001  MS       0     0     1
  [28] .debug_aranges    PROGBITS         0000000000000000  00220ce4
       00000000000016e0  0000000000000000           0     0     1
  [29] .debug_info       PROGBITS         0000000000000000  002223c4
       000000000002d720  0000000000000000           0     0     1
  [30] .debug_abbrev     PROGBITS         0000000000000000  0024fae4
       0000000000007c00  0000000000000000           0     0     1
  [31] .debug_line       PROGBITS         0000000000000000  002576e4
       0000000000012c6d  0000000000000000           0     0     1
  [32] .debug_str        PROGBITS         0000000000000000  0026a351
       0000000000003b9e  0000000000000001  MS       0     0     1
  [33] .debug_loc        PROGBITS         0000000000000000  0026deef
       000000000007c8f7  0000000000000000           0     0     1
  [34] .debug_ranges     PROGBITS         0000000000000000  002ea7e6
       000000000000bf30  0000000000000000           0     0     1
  [35] .shstrtab         STRTAB           0000000000000000  004e60b9
       0000000000000165  0000000000000000           0     0     1
  [36] .symtab           SYMTAB           0000000000000000  002f6718
       00000000001691b8  0000000000000018          37   60973     8
  [37] .strtab           STRTAB           0000000000000000  0045f8d0
       00000000000867e9  0000000000000000           0     0     1
...

So the address 0000000000820ca8 puts it some where at the end of the .data section. The .data section runs from 0x7a3140 to 0x820cb0. The length of the string is 21 bytes meaning the end of the const string is 0x820cbd. The next section .bss starts at 0x820cc0. So I don't think there is an overlap issue. I'm not totally sure why it isn't into the string table but I'm guessing it is because of the way I've used the global variable some_silly_msg.

Anyway - Thoughts ? Have you tried this before ? Is there something wrong with my setup ?

CuppoJava commented 2 years ago

I'm really sorry. This is caused by the lack of a meaningful error message that repeatedly trips people up. It's been on our backlog for a while.

You have an external function called get_some_msg that is declared in C, and hence needs to be called with the C calling convention.

public lostanza defn get-some-msg () -> ref<String> :
  val msg:ptr<byte> = get_some_msg()  ; <-- This line is incorrect.
  return String(msg)

Here is the fix for it:

public lostanza defn get-some-msg () -> ref<String> :
  val msg:ptr<byte> = call-c get_some_msg()
  return String(msg)

This is a common mistake, and can easily waste a lot of time, so we're planning on adding an error message to catch this case.

callendorph commented 2 years ago

Yup - that was it. I had used the call-c construct for the elementary functions but I just brain farted on this one I guess.

This is a common mistake, and can easily waste a lot of time, so we're planning on adding an error message to catch this case.

Ya - that would be great.