www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - yet another segfault - array out of bound is not caught by try catch

reply seany <seany uni-bonn.de> writes:
I have now this function, as a private member in a Class :


         double calculate_lineLength( int i)  {
             field.rawData [] * rd;                   // ignore 
the details, this works;
             rd = cast (field.rawData [] *)  dataSet; // ignore 
the details, this works;

             auto l = this.allLines[i];               // this is 
defined as
                                                      // int [][] 
allLines =
                                                      //           
  new int [][] (0,0)
                                                      // in case 
of failure, this is empty
             double r = 0;
             try {
                 writeln("l ", l);                    // prints []
                 writeln("i ", i);                    // prints i, 
in this case, i is set to 0
                 writeln(l.length);                   // prints 0
                 writeln("l0 ", l[0]);                // segfault 
- i want it to be caught
                 write("will print");
                 writeln("rd", (*rd));
                 write("will not print...");
                 auto p0 = (*rd)[l[0]];
                 auto p1 = (*rd)[l[1]];
     	    r = calculate_geoDistance_vincenty(p0.lat,p1.lat, 
p0.lon, p1.lon);
             } catch (RangeError er) {
                 writeln("range error");
             }
                 return r;
         }


Compile with `dub build --compiler=ldc2 `. this should enable 
array bound checking options.


I am debugging with gdb :

`gdb ./myprogram`

Then, in gdb console :

`run arg1 arg2 `

Result is :

         91753
         91754
         91755
         91756
         [New Thread 0x7ffff7560640 (LWP 45344)]
         [New Thread 0x7fffeffff640 (LWP 45345)]
         [New Thread 0x7ffff6d5f640 (LWP 45346)]
         [New Thread 0x7ffff655e640 (LWP 45347)]
         [New Thread 0x7ffff5d5d640 (LWP 45348)]
         [New Thread 0x7ffff555c640 (LWP 45349)]
         [New Thread 0x7ffff4d5b640 (LWP 45350)]
         [New Thread 0x7fffef7fe640 (LWP 45351)]
         [New Thread 0x7fffeeffd640 (LWP 45352)]
         [New Thread 0x7fffee7fc640 (LWP 45353)]
         [New Thread 0x7fffedffb640 (LWP 45354)]
         [New Thread 0x7fffed7fa640 (LWP 45355)]
         [New Thread 0x7fffecff9640 (LWP 45356)]
         [New Thread 0x7fffbffff640 (LWP 45357)]
         [New Thread 0x7fffbf7fe640 (LWP 45358)]
         [New Thread 0x7fffbeffd640 (LWP 45359)]
         [New Thread 0x7fffbe7fc640 (LWP 45360)]
         [New Thread 0x7fffbdffb640 (LWP 45361)]
         [New Thread 0x7fffbd7fa640 (LWP 45362)]
         getting LINES done
         alllines: []
         l []
         i 0
         0
         Thread 1 "myprogram" received signal SIGSEGV, 
Segmentation fault.
         _D14analysisEngine9geoEngine20calculate_lineLengthMFiZd 
(this=<optimized out>, i=0) at source/analysisEngine.d:15526
         15526
         writeln("l0 ", l[0]);

So, to see what is going on, i use the command `bt`:



_D14analysisEngine9geoEngine20calculate_lineLengthMFiZd 
(this=<optimized out>, i=0) at source/analysisEngine.d:15526

_D14analysisEngine9geoEngine13add_turnLinesMFZv (this=<optimized 
out>) at source/analysisEngine.d:7387

_D14analysisEngine9geoEngine15analyze_tillageMFZv 
(this=0x7ffff756a000) at source/analysisEngine.d:5329

source/AI.d:123


Okey, I know where to look for : it's the line asking for 
`writeln("l0 ", l[0]);`.


     But should it not be caught by range error ? If I do `print 
l`in gdb, i find :
         $1 = {length = 0, ptr = 0x0}

With `print l[0]` i get: `Attempt to take address of value not 
located in memory.`. I believe the array printing syntax is 
valid; see 
[here](https://phoenix.goucher.edu/~kelliher/cs23/gdb.html).

What absolute rookie mistake am I committing? What does it mean : 
"Attempt to take address of value not located in memory" ? I am 
not even calling / accessing a pointer. I am trying to extract a 
value outside an array bound.

I imagine they all have their addresses. But with the bound 
checking operation in place, would the bound error be triggered 
before the attempt to take unavailable address error has a chance 
to trigger?

Thank you.
Sep 17 2021
next sibling parent Nicholas Wilson <iamthewilsonator hotmail.com> writes:
On Friday, 17 September 2021 at 11:10:33 UTC, seany wrote:
 I have now this function, as a private member in a Class :
             } catch (RangeError er) {
I can't remember if you can catch an index OOB error but try `catch (Throwable er)` will work if it is catchable at all and you can figure out what kind of Error you have by printing its name.
  "Attempt to take address of value not located in memory" ? I 
 am not even calling / accessing a pointer. I am trying to 
 extract a value outside an array bound.
`Type[]` arrays in D are effectively struct {size_t length; Type* ptr; } under the hood. Your problem is the array has no elements which is why trying to extract a value outside an array bound is an irrecoverable error.
 with the bound checking operation in place, would the bound 
 error be triggered before the attempt to take unavailable 
 address error has a chance to trigger?
with a null array of zero length `arr`, `arr[0]` with bounds check enabled will fail the bounds check before it tries to dereference the pointer. if you try `arr.ptr[0]` to bypass the bounds checking (which is a very bad idea!) you will then try to load from an invalid memory address and crash.
Sep 17 2021
prev sibling parent reply jfondren <julian.fondren gmail.com> writes:
On Friday, 17 September 2021 at 11:10:33 UTC, seany wrote:
 Compile with `dub build --compiler=ldc2 `. this should enable 
 array bound checking options.
By default, yes. run `dub -v build --compiler=ldc2` to see the exact commands that dub runs.
     But should it not be caught by range error ?
Based on what you've said, yes it should.
 If I do `print l`in gdb, i find :
         $1 = {length = 0, ptr = 0x0}
 With `print l[0]` i get: `Attempt to take address of value not 
 located in memory.`.
i.e., a segfault. null (or 0x0 (or 0)) isn't part of the memory addresses your program is allowed to access, so memory protection prevents the attempt to access it.
 What absolute rookie mistake am I committing?
From this it doesn't sound like you are committing one, but if you're wanting bounds checking to be a normal part of program logic, and not something that only ever happens due to a programmer's error, then I think you're cutting against the grain of the language, where - bounds checking is easily removed from all but safe functions with normal flags - flags exist to remove it from safe functions also - the *Error family of exceptions, including RangeError are not intended to be catchable - raising and immediately catching an exception like this is slower and more verbose than an explicit test. Rather than returning an empty array on an error and expecting a caller to catch RangeError, you could throw a normal exception on error, and then you have tools like `std.exception.ifThrown` to make dealing with that exception nicer.
Sep 17 2021
parent russhy <russhy gmail.com> writes:
Double check in your dub.json file and see if you haven't changed 
your buildoptions


DEBUG:

it's caught: https://run.dlang.io/is/F8HkD8


RELEASE:

segfault as expected: https://run.dlang.io/is/oLU2M3


And make sure to use latest version of ldc
Sep 18 2021