0

I am trying to solve a problem for code wars, but my code gives an error. I've tested the code on code blocks and it works, but when I test it on their website it gives me some strange error. I looked it on the internet and found out that it might be a segmentation fault because of a deref of a null pointer, but I dont know how to fix it. This is my code and the error. Can you tell me plase what is the problem and why it works on code block, but on the compiler on the website it doesn't.(P.S. Please excuse my english, Im from Romania).

#include <iostream>
#include <vector>
#include <bits/stdc++.h>
using namespace std;

long queueTime(std::vector<int> costumers, int n) {
    vector<int> q;
    int j, x;
    long t;
    for (j = 0; j < n; j++)
        q.push_back(costumers[j]);
    int u = costumers.size();

    while (j <= u) {
        x = *min_element(q.begin(), q.end());
        t = t + x;
        for (int i = 0; i < n; i++) {
            q[i] = q[i] - x;
            if (q[i] == 0) {
                q[i] = costumers[j];
                j++;
            }
        }
    }
    t += *max_element(q.begin(), q.end());
    return t;
}
 Error message:

UndefinedBehaviorSanitizer:DEADLYSIGNAL
==1==ERROR: UndefinedBehaviorSanitizer: SEGV on unknown address 0x000000000000 (pc 0x00000042547b bp 0x000000000000 sp 0x7ffec8fa0510 T1)
==1==The signal is caused by a READ memory access.
==1==Hint: address points to the zero page.
==1==WARNING: invalid path to external symbolizer!
==1==WARNING: Failed to use and restart external symbolizer!
    #0 0x42547a  (/workspace/test+0x42547a)
    #1 0x427ffc  (/workspace/test+0x427ffc)
    #2 0x42686e  (/workspace/test+0x42686e)
    #3 0x426435  (/workspace/test+0x426435)
    #4 0x42609b  (/workspace/test+0x42609b)
    #5 0x42aad5  (/workspace/test+0x42aad5)
    #6 0x42581d  (/workspace/test+0x42581d)
    #7 0x7fc90f605b96  (/lib/x86_64-linux-gnu/libc.so.6+0x21b96)
    #8 0x404489  (/workspace/test+0x404489)

UndefinedBehaviorSanitizer can not provide additional info.
==1==ABORTING
mch
  • 9,424
  • 2
  • 28
  • 42
  • 1
    Consider spending some time to put together a [mcve] along with the input you're using and any expected output. The limits of the input are important as well. – Retired Ninja Oct 27 '20 at 07:05
  • if `n > customers.size()` then the first loop has undefined behaviour. Both `n` and `customers` are passed by the caller, so there is no assurance that what is passed doesn't cause undefined behaviour. The behaviour of the code after that (for loop in a while loop) also accesses `customers[j]` where `j` is incremented a number of times that depends on the vector elements, so I wouldn't be surprised if there is more undefined behaviour there. – Peter Oct 27 '20 at 07:13
  • This is the first input given to my function, Assert::That(queueTime(std::vector{}, 1), Equals(0));. It gives me an emty vector so I put an if statment: ```if(costumers.size()==0) return t;``` and now it dont get that error anyomre but I get another one. Expected: equal to 10 Actual: 29551. I think it returns me the address of t, im not sure. This is the input given for that error Assert::That(queueTime(std::vector{1,2,3,4}, 1), Equals(10));. – Cristyantm97 Oct 27 '20 at 07:31
  • @Cristyantm97 - That's not surprising at all. My previous comment is because, even on a casual look, I could see multiple possibilities for undefined behaviour. Virtually EVERY place where your code uses `j` as an array (or vector) index has possibility of undefined behaviou, because the values `j` can take depend on data passed by the caller, and arrays/vectors have a finite number of elements. Do bounds checking on the value of `j` (i.e. report if it is an invalid index BEFORE using it as an index) and you'll see numerous problems. – Peter Oct 27 '20 at 07:38
  • 1
    `#include ` -- [no, please](https://stackoverflow.com/questions/31816095/why-should-i-not-include-bits-stdc-h). `using namespace std;` -- [no, please](https://stackoverflow.com/questions/1452721/why-is-using-namespace-std-considered-bad-practice). – DevSolar Oct 27 '20 at 08:08
  • I managed to solve the problem with j. Everything works fine now. Thank you! – Cristyantm97 Oct 27 '20 at 08:17
  • 1
    I saw that the majority of people dont use "using namespace std" why is that? @DevSolar – Cristyantm97 Oct 27 '20 at 08:29
  • `costumers[j]` where `while (j <= u)`, where `int u = costumers.size();` will cause out-of-bounds access when `j==u`. Please explain what the code is supposed to do... as it is not clear from the code. – JHBonarius Oct 27 '20 at 08:39
  • @Cristyantm97: I linked the top SO question to that end. In one line, it pollutes the global namespace, introduces ambiguities and can result in surprising errors. – DevSolar Oct 27 '20 at 08:45

1 Answers1

1

SEGV would indicate that there is a segmentation fault happening somewhere so you are on the right track with your debugging. Looking at the code you have provided there are few tips that might help you narrow down where things are going wrong.

The first thing that sticks out is that seem to be taking a local copy of costumers on this line:

for (j = 0; j < n; j++) q.push_back(costumers[j]);

Here you make the assumption that n is less or equal to costumers.size() and if n is larger than this then this will try to read from beyond the end of the vector. An alternative here is to use the = operator instead:

vector<int> q = costumers;

If you actually only wanted the first n elements of costumers copied to q then you could use:

if(n < q.size()){
    q.resize(n);
}

to shrink it to size afterwards.

Another general style point is that it is good practice to something called "Resource allocation is initialization" (RAII): at the top of your queueTime function you have a bunch of variables declared but not initialized to values:

int j, x;
long t;

The problem here is that these will often be initialized to junk values and if you forget to initialize them later then you may be reading these junk values without knowing. Try instead to declare the variable at the point in the code you assign a value to it, eg fo j:

for(int j = 0; ... )

and x

int x = *min_element(q.begin(), q.end());

or in the case where you need t everywhere in the function scope, at least assign an initial value when you declare it

long t = 0;

Finally when using algorithms that return iterators it is generally good practice to check that they are valid before dereferencing them ie. writing:

auto itr_min_elem = min_element(q.begin(), q.end());
if(itr_min_elem == q.end()){
    continue;
}
int x = *itr_min_elem;

so that if q is empty and min_element returns an end iterator then you don't try to dereference it.

Sorry for the wall of text but I hope these offer some help for debugging your function.

As a general note to your question about why it was working on code blocks but not on the website could come down to a number of reasons, likely related to how the code is being compiled. Some compilers will initialize memory to 0s in debug builds and this can have the effect of uninitialized variables behaving nicely in debug but in an undefined way in release. Also depending on the environment the code is executed in there may be differences in the memory layout so reading past the end of an array in one environment may just give junk while in another you may be indexing into protected memory or outside of your programs allocated memory. This would cause the platform running your code to be very unhappy and force it to abort.

Dharman
  • 30,962
  • 25
  • 85
  • 135
geoff3jones
  • 605
  • 1
  • 7
  • 17
  • I assigned values for every uninitialized variables, and I put an if statement ``` if(n>costumers.size()){ t=*max_element(costumers.begin(), costumers.end()); return t; ``` Everything seems to work fine now. Thank you so much for your time! Sorry for the text organiztion, it is my first question on this website. @geoff3jones – Cristyantm97 Oct 27 '20 at 08:24
  • "Here you make the assumption that n is the same size as costumers.size()" No, as I read the function he assumes that `n <= customers.size()`, because he re-uses the end value of `j` in the `while (j <= u)` loop – JHBonarius Oct 27 '20 at 08:37
  • "when using algorithms that return iterators it is generally good practice". That depends. doesn't it? `min_element` will only return `end` if `size=0`. If you have guarantees that size is never 0, then the check is not necessary, – JHBonarius Oct 27 '20 at 09:01
  • @JHBonarius re size assumptions true this should read `<=` I'll edit to reflect this, on the second point I would still argue that is it still good practice when you are starting out to check your iterators are valid, but indeed if you can reason about the code to optimise away the need to check then great. But as an optimisation pass, removing the check on the iterator being valid wont often save much time compared to running the algorithm itself. – geoff3jones Oct 27 '20 at 12:29