0
  1. I am trying to create a Bool Array class which takes a string of integers and converts them into bool arrays. Once I have 2 Bool Array variables I perform Karatsuba Multiplication.

Below is where the actual error arises from.

explicit BoolArray(BoolArray const &ref, int start) : dimensions_{ref.dimensions_-1} {
                //std::cout << ref << std::endl;
                //std::cout << "Start" << std::endl;
                //std::cout << ref.dimensions_-1 << std::endl;
                //std::cout << dimensions_ << std::endl;
                //std::cout << start << std::endl;
                sign_ = false;
                //std::cout << "Make_unique" << std::endl;
                arr_ = std::make_unique<bool[]>(dimensions_); //Line doesn't run in some cases
                //std::cout << "Make_unique Accomplished" << std::endl;
                std::memcpy(arr_.get(),ref.arr_.get()+start,dimensions_*sizeof(bool));
                //std::cout << *this << std::endl;
            }

These are my private variables.

mutable unsigned int dimensions_;
mutable std::unique_ptr<bool[]> arr_;

I used GDB to find out where the error was occurring, and it pointed to this specific function call. I then use print statements to determine what exact line wasn't running and it was the make_unique line.

Now the interesting bit here is, say I were to multiply a 5000 digit number by a 5000 digit number. It's first converted to a bool array occurs. It is then multiplied, the multiplication occurs perfectly and it returns another bool array.

In the case of 13000 digits however, when multiplying them together I specifically get the error: malloc(): invalid size (unsorted) error.

Now, I'm not expecting someone to debug this but I am looking for reasons why std::make_unique<bool []>(x), could break?

Thank you

Edit: I have just used valgrind and I seem to be getting many ==14286== Invalid read of size 1 ==14286== Invalid write of size 1 , but the output I was getting has been fine so far. I even tried this for simple multiplication between 1 and 1. And I'm getting quite a bit of errors with valgrind, but I thought it was just running smoothly though. Edit:

I think what's been causing the errors so far have been this specific function. Please note that, the else statement is basically the code reused (I know I can also do this without the if statement), but using the code below I am getting the valgrind errors, which I will copy paste below.

 friend BoolArray operator+(BoolArray &x, BoolArray  &y) {
                if (x.size() <= y.size()) {
                    int max = y.size();
                    int min = x.size();
                    int mSize = max;
                    auto ret = BoolArray(++mSize);
                    bool remainder = 0;

                    for (; min >= 0; --min) {
                        ret[mSize] = output_[remainder][ y[max] ][x[min] ];
                        remainder = carry_[remainder][ y[max] ][ x[min] ];
                        --max;
                        --mSize;
                    }
                    
                    for (; max >= 0; --max) {
                        ret[mSize] = output_[remainder][ y[max] ][ 0 ];
                        remainder = carry_[remainder][ y[max] ][ 0 ];
                        --mSize;
                    }

                    if (remainder) {
                        ret[mSize] = 1;
                    } else {
                        auto newRet = BoolArray(ret,1);
                        return newRet;
                    }
                    return ret;

Valgrind Error

==14457== Invalid read of size 1
==14457==    at 0x10BABA: BigNum::operator+(BigNum::BoolArray&, BigNum::BoolArray&) (DataStructure.cpp:422)
==14457==    by 0x10A65A: main (DataStructure.cpp:693)
==14457==  Address 0x4da8f52 is 0 bytes after a block of size 2 alloc'd
==14457==    at 0x483C583: operator new[](unsigned long) (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==14457==    by 0x10C26F: std::_MakeUniq<bool []>::__array std::make_unique<bool []>(unsigned long) (unique_ptr.h:863)
==14457==    by 0x10AB46: BigNum::BoolArray::BoolArray(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (DataStructure.cpp:58)
==14457==    by 0x10A5CD: main (DataStructure.cpp:688)
==14457==
==14457== Invalid read of size 1
==14457==    at 0x10BAD9: BigNum::operator+(BigNum::BoolArray&, BigNum::BoolArray&) (DataStructure.cpp:422)
==14457==    by 0x10A65A: main (DataStructure.cpp:693)
==14457==  Address 0x4da8dc2 is 0 bytes after a block of size 2 alloc'd
==14457==    at 0x483C583: operator new[](unsigned long) (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==14457==    by 0x10C26F: std::_MakeUniq<bool []>::__array std::make_unique<bool []>(unsigned long) (unique_ptr.h:863)
==14457==    by 0x10AB46: BigNum::BoolArray::BoolArray(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (DataStructure.cpp:58)
==14457==    by 0x10A57F: main (DataStructure.cpp:687)
==14457==
==14457== Invalid write of size 1
==14457==    at 0x10BB19: BigNum::operator+(BigNum::BoolArray&, BigNum::BoolArray&) (DataStructure.cpp:422)
==14457==    by 0x10A65A: main (DataStructure.cpp:693)
==14457==  Address 0x4da93e3 is 0 bytes after a block of size 3 alloc'd
==14457==    at 0x483C583: operator new[](unsigned long) (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==14457==    by 0x10C26F: std::_MakeUniq<bool []>::__array std::make_unique<bool []>(unsigned long) (unique_ptr.h:863)
==14457==    by 0x10ADAF: BigNum::BoolArray::BoolArray(unsigned int const&) (DataStructure.cpp:72)
==14457==    by 0x10BA8A: BigNum::operator+(BigNum::BoolArray&, BigNum::BoolArray&) (DataStructure.cpp:418)
==14457==    by 0x10A65A: main (DataStructure.cpp:693)
==14457==
==14457== Invalid read of size 1
==14457==    at 0x10BB3C: BigNum::operator+(BigNum::BoolArray&, BigNum::BoolArray&) (DataStructure.cpp:423)
==14457==    by 0x10A65A: main (DataStructure.cpp:693)
==14457==  Address 0x4da8f52 is 0 bytes after a block of size 2 alloc'd
==14457==    at 0x483C583: operator new[](unsigned long) (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==14457==    by 0x10C26F: std::_MakeUniq<bool []>::__array std::make_unique<bool []>(unsigned long) (unique_ptr.h:863)
==14457==    by 0x10AB46: BigNum::BoolArray::BoolArray(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (DataStructure.cpp:58)
==14457==    by 0x10A5CD: main (DataStructure.cpp:688)
==14457==
==14457== Invalid read of size 1
==14457==    at 0x10BB5B: BigNum::operator+(BigNum::BoolArray&, BigNum::BoolArray&) (DataStructure.cpp:423)
==14457==    by 0x10A65A: main (DataStructure.cpp:693)
==14457==  Address 0x4da8dc2 is 0 bytes after a block of size 2 alloc'd
==14457==    at 0x483C583: operator new[](unsigned long) (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==14457==    by 0x10C26F: std::_MakeUniq<bool []>::__array std::make_unique<bool []>(unsigned long) (unique_ptr.h:863)
==14457==    by 0x10AB46: BigNum::BoolArray::BoolArray(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (DataStructure.cpp:58)
==14457==    by 0x10A57F: main (DataStructure.cpp:687)
==14457==
10 <- This is my output.

The code I am running which calls the + overload

    auto m1 = BigNum::BoolArray("1"); //[01]
    auto m2 = BigNum::BoolArray("1"); //[01]

    std::cout << m1.size() << std::endl;
    std::cout << m2.size() << std::endl;

    std::cout << m1 + m2 << std::endl; //[10]

So, now I think I need to figure out why the + overload is giving me these specific errors..

Steveit
  • 51
  • 1
  • 9
  • 2
    Consider putting together a [mcve]. You could have memory corruption somewhere else that makes this allocation fail. Figure out the sequence of events that triggers it and work backwards from there to find the actual source. – Retired Ninja Sep 11 '21 at 02:16
  • Maybe your `memcpy` reads out of bounds .Seems like that might happen if `start > 1` – M.M Sep 11 '21 at 02:31
  • 1
    What value does `dimensions_` have when `make_unique()` fails? Because of the `-1` when `dimensions_` is initialized, you will get a very large value if `ref.dimensions_` is 0. Personally, I would get rid of `dimensions_` completely, and change `arr_` into a `std::vector` – Remy Lebeau Sep 11 '21 at 02:32
  • What exactly is a `BoolArray`? We can't see any of the code that would give us an idea whether the `memcpy` reads out of bounds or not. – David Schwartz Sep 11 '21 at 02:32
  • @M.M The start value will never be greater than 1, it will only be 1 for that piece of code there. – Steveit Sep 11 '21 at 02:45
  • @Remy Lebeau dimensions_ had the value 1671 when the error was generated. – Steveit Sep 11 '21 at 02:45
  • @DavidSchwartz Bool Array is just meant to be a sequence of binary numbers. The specific role of that function is to copy from index 1. So, [0010010] -> [010010] – Steveit Sep 11 '21 at 02:46
  • 1
    Could you use [`std::bitset`](https://en.cppreference.com/w/cpp/utility/bitset) for your purposes? Or [`std::vector`](https://en.cppreference.com/w/cpp/container/vector_bool)? – dreamlax Sep 11 '21 at 02:50
  • @dreamlax I honestly wish I could but, std::vector is very slow. std::bitset, i would need to know the size at the beginning. But at the same time is it possible for dynamically allocate size for std::bitset through the use of unique_ptr? – Steveit Sep 11 '21 at 02:54
  • 1
    @Steveit the only way I know for `std::make_unique(1671)` to fail is if you have either run out of memory, or have otherwise corrupted memory beforehand. – Remy Lebeau Sep 11 '21 at 03:02
  • @RemyLebeau what are the ways memory can be corrupted? Can it be corrupted through Invalid read of size 1 and write of size 1 errors generated from valgrind? – Steveit Sep 11 '21 at 03:11
  • @Steveit "*what are the ways memory can be corrupted?*" - seriously? – Remy Lebeau Sep 11 '21 at 03:26
  • @RemyLebeau I know the ways memory can obviously be corrupted but I don't understand how it specifically makes -> make_unqiue break? – Steveit Sep 11 '21 at 10:31
  • Might not be relevant but `auto ret = BoolArray(++mSize);` and later `ret[mSize] = …`. Assuming the BoolArray index is zero-based, won’t that cause trouble (unless `BoolArray(int)` constructor adds one to the size internally). – DS_London Sep 11 '21 at 12:36
  • @Steveit memory corruption would affect `make_unique()` if the allocator it uses internally to allocate the array is corrupted. – Remy Lebeau Sep 11 '21 at 16:23
  • @DS_London yea it turns out that was the problem along with a couple of things. My operator overload wasn't picking it up since I had no checks, and I was doing pointer arithmetic to get the actual object instead, so that messed it up quite a bit. – Steveit Sep 12 '21 at 00:07

1 Answers1

0

I have edited my code, so it turns out Remy was right that I have corrupted memory beforehand by accessing stuff that I was not meant to be as my operator overloads for [] were poorly written so I did not realise I was going out of bounds. So I had to adjust the code in my + operator overload. int max = y.size();

                    int mSize = max+1;
                    max--;
                    int min = x.size();
                    min--;
                    auto ret = BoolArray(mSize);
                    mSize--;
                    bool remainder = 0;

TO something like that, I know its very ugly but gets the job done. Anyone thank you, but at the same time I'd like to know this would specifically affect whats happening with the make_unique function.

Steveit
  • 51
  • 1
  • 9