Why does my median of medians quick select algorithm segfault? - c++

I'm having a hard time finding the fault in my code that causes my median of medians quick select algorithm to segfault when the input is even moderately large. The output is correct, when I do get output. Below is the full code which causes a segfault on my system with the given test parameters.
#include <iostream>
#include <vector>
#include <cstdlib>
#include <algorithm>
using namespace std;
void swap(vector<int> &A, const uint &index1, const uint &index2)
{
int temp = A.at(index1);
A.at(index1) = A.at(index2);
A.at(index2) = temp;
}
void insertionSort(vector<int> &A, const int &begin, const int &end)
{
// Begin inner loop from each element
for(int i=begin; i<end; i++)
{
// If current item is smaller than the next, swap them.
for(int j=i; j>begin && A.at(j-1)>A.at(j); j--)
{
swap(A, j, j-1);
}
}
}
int partition(vector<int> &A, const int &begin, const int &end, const int &pivot)
{
int left = begin, right = end - 1;
while(left<right)
{
while(A.at(left)<pivot && left<=right)
{
left++;
}
while(A.at(right)>pivot && right>=left)
{
right--;
}
if(left>=right)
{
break;
}
else if(A.at(left)==A.at(right))
{
left++;
continue;
}
swap(A, left, right);
}
return --left;
}
int linearSelect(vector<int> &A, const int &begin, const int &end, const int &k, const int &groupSize)
{
int elements = (end-begin),
numOfGroups = (elements/groupSize);
vector<int> medians;
// Base case, input is small. Just sort and return element at k.
if(elements<(groupSize*2))
{
//insertionSort(A, begin, end);
sort(A.begin(), A.end());
return A.at(begin+k);
}
int i = 0;
// Divide and sort full groups.
for(int g=0; g<numOfGroups; g++, i+=groupSize)
{
//insertionSort(A, i, i+groupSize);
sort(A.begin()+i, A.begin()+(i+groupSize));
medians.push_back(A.at(i+(groupSize/2)));
}
// Sort remainder group if there is one.
if(i<elements)
{
//insertionSort(A, i, i+(elements%groupSize));
sort(A.begin()+i, A.begin()+(i+(elements%groupSize)));
medians.push_back(A.at(i+((elements%groupSize)/2)));
}
// Find median of medians, then partition around that.
int median = linearSelect(medians, 0, medians.size(), medians.size()/2, groupSize),
pivot = partition(A, begin, end, median),
lessSize = pivot - begin + 1;
// Answer is in lesser group
if(k<lessSize)
{
return linearSelect(A, begin, pivot, k, groupSize);
}
// Answer is in greater group.
else if(k>lessSize)
{
return linearSelect(A, pivot+1, end, k-lessSize, groupSize);
}
// Answer is at k
else
{
return A.at(k);
}
}
int main()
{
vector<int> A;
for(int i=0; i<1000; i++)
{
A.push_back(i);
}
cout << linearSelect(A, 0, A.size(), 50, 7) << endl;
return 0;
}

When I instrument your program with Address Sanitizer (-fsanitize=address using recent GCC), it reports:
ASAN:DEADLYSIGNAL
=================================================================
==97243==ERROR: AddressSanitizer: stack-overflow on address 0x7fffda79bff8 (pc 0x7f3999017979 bp 0x7fffda79c880 sp 0x7fffda79c000 T0)
#0 0x7f3999017978 in __asan::asan_memalign(unsigned long, unsigned long, __sanitizer::BufferedStackTrace*, __asan::AllocType) ../../../../libsanitizer/asan/asan_allocator.cc:702
#1 0x7f39990b1c48 in operator new(unsigned long) ../../../../libsanitizer/asan/asan_new_delete.cc:60
#2 0x404708 in __gnu_cxx::new_allocator<int>::allocate(unsigned long, void const*) /usr/local/gcc-svn-r239225/include/c++/7.0.0/ext/new_allocator.h:104
#3 0x403dc5 in std::allocator_traits<std::allocator<int> >::allocate(std::allocator<int>&, unsigned long) /usr/local//gcc-svn-r239225/include/c++/7.0.0/bits/alloc_traits.h:416
#4 0x403599 in std::_Vector_base<int, std::allocator<int> >::_M_allocate(unsigned long) /usr/local/gcc-svn-r239225/include/c++/7.0.0/bits/stl_vector.h:172
#5 0x402b5c in void std::vector<int, std::allocator<int> >::_M_realloc_insert<int const&>(__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, int const&) /usr/local/gcc-svn-r239225/include/c++/7.0.0/bits/vector.tcc:399
#6 0x40279e in std::vector<int, std::allocator<int> >::push_back(int const&) /usr/local/gcc-svn-r239225/include/c++/7.0.0/bits/stl_vector.h:954
#7 0x401d71 in linearSelect(std::vector<int, std::allocator<int> >&, int const&, int const&, int const&, int const&) /tmp/t.cc:77
#8 0x4020e4 in linearSelect(std::vector<int, std::allocator<int> >&, int const&, int const&, int const&, int const&) /tmp/t.cc:100
#9 0x4020e4 in linearSelect(std::vector<int, std::allocator<int> >&, int const&, int const&, int const&, int const&) /tmp/t.cc:100
#10 0x4020e4 in linearSelect(std::vector<int, std::allocator<int> >&, int const&, int const&, int const&, int const&) /tmp/t.cc:100
#11 0x4020e4 in linearSelect(std::vector<int, std::allocator<int> >&, int const&, int const&, int const&, int const&) /tmp/t.cc:100
#12 0x4020e4 in linearSelect(std::vector<int, std::allocator<int> >&, int const&, int const&, int const&, int const&) /tmp/t.cc:100
...
Conclusion: your recursion base case is busted. Looking at crash with GDB:
(gdb) bt -20
#20941 0x00000000004020e5 in linearSelect (A=std::vector of length 143, capacity 256 = {...}, begin=#0x7fffffffc0b4: 38, end=#0x7fffffffda50: 72, k=#0x7fffffffc0b8: 33, groupSize=#0x7fffffffdcd0: 7) at t.cc:100
#20942 0x00000000004020e5 in linearSelect (A=std::vector of length 143, capacity 256 = {...}, begin=#0x7fffffffc244: 38, end=#0x7fffffffda50: 72, k=#0x7fffffffc248: 33, groupSize=#0x7fffffffdcd0: 7) at t.cc:100
#20943 0x00000000004020e5 in linearSelect (A=std::vector of length 143, capacity 256 = {...}, begin=#0x7fffffffc3d4: 38, end=#0x7fffffffda50: 72, k=#0x7fffffffc3d8: 33, groupSize=#0x7fffffffdcd0: 7) at t.cc:100
#20944 0x00000000004020e5 in linearSelect (A=std::vector of length 143, capacity 256 = {...}, begin=#0x7fffffffc564: 38, end=#0x7fffffffda50: 72, k=#0x7fffffffc568: 33, groupSize=#0x7fffffffdcd0: 7) at t.cc:100
#20945 0x00000000004020e5 in linearSelect (A=std::vector of length 143, capacity 256 = {...}, begin=#0x7fffffffc6f4: 38, end=#0x7fffffffda50: 72, k=#0x7fffffffc6f8: 33, groupSize=#0x7fffffffdcd0: 7) at t.cc:100
#20946 0x00000000004020e5 in linearSelect (A=std::vector of length 143, capacity 256 = {...}, begin=#0x7fffffffc884: 38, end=#0x7fffffffda50: 72, k=#0x7fffffffc888: 33, groupSize=#0x7fffffffdcd0: 7) at t.cc:100
#20947 0x00000000004020e5 in linearSelect (A=std::vector of length 143, capacity 256 = {...}, begin=#0x7fffffffca14: 38, end=#0x7fffffffda50: 72, k=#0x7fffffffca18: 33, groupSize=#0x7fffffffdcd0: 7) at t.cc:100
#20948 0x00000000004020e5 in linearSelect (A=std::vector of length 143, capacity 256 = {...}, begin=#0x7fffffffcba4: 38, end=#0x7fffffffda50: 72, k=#0x7fffffffcba8: 33, groupSize=#0x7fffffffdcd0: 7) at t.cc:100
#20949 0x00000000004020e5 in linearSelect (A=std::vector of length 143, capacity 256 = {...}, begin=#0x7fffffffcd34: 38, end=#0x7fffffffda50: 72, k=#0x7fffffffcd38: 33, groupSize=#0x7fffffffdcd0: 7) at t.cc:100
#20950 0x00000000004020e5 in linearSelect (A=std::vector of length 143, capacity 256 = {...}, begin=#0x7fffffffcec4: 38, end=#0x7fffffffda50: 72, k=#0x7fffffffcec8: 33, groupSize=#0x7fffffffdcd0: 7) at t.cc:100
#20951 0x00000000004020e5 in linearSelect (A=std::vector of length 143, capacity 256 = {...}, begin=#0x7fffffffd054: 38, end=#0x7fffffffda50: 72, k=#0x7fffffffd058: 33, groupSize=#0x7fffffffdcd0: 7) at t.cc:100
#20952 0x00000000004020e5 in linearSelect (A=std::vector of length 143, capacity 256 = {...}, begin=#0x7fffffffd1e4: 38, end=#0x7fffffffda50: 72, k=#0x7fffffffd1e8: 33, groupSize=#0x7fffffffdcd0: 7) at t.cc:100
#20953 0x00000000004020e5 in linearSelect (A=std::vector of length 143, capacity 256 = {...}, begin=#0x7fffffffd374: 38, end=#0x7fffffffda50: 72, k=#0x7fffffffd378: 33, groupSize=#0x7fffffffdcd0: 7) at t.cc:100
#20954 0x00000000004020e5 in linearSelect (A=std::vector of length 143, capacity 256 = {...}, begin=#0x7fffffffd504: 38, end=#0x7fffffffda50: 72, k=#0x7fffffffd508: 33, groupSize=#0x7fffffffdcd0: 7) at t.cc:100
#20955 0x00000000004020e5 in linearSelect (A=std::vector of length 143, capacity 256 = {...}, begin=#0x7fffffffd694: 38, end=#0x7fffffffda50: 72, k=#0x7fffffffd698: 33, groupSize=#0x7fffffffdcd0: 7) at t.cc:100
#20956 0x00000000004020e5 in linearSelect (A=std::vector of length 143, capacity 256 = {...}, begin=#0x7fffffffd824: 38, end=#0x7fffffffda50: 72, k=#0x7fffffffd828: 33, groupSize=#0x7fffffffdcd0: 7) at t.cc:100
#20957 0x00000000004020e5 in linearSelect (A=std::vector of length 143, capacity 256 = {...}, begin=#0x7fffffffdbe0: 0, end=#0x7fffffffda50: 72, k=#0x7fffffffdb48: 71, groupSize=#0x7fffffffdcd0: 7) at t.cc:100
#20958 0x0000000000402041 in linearSelect (A=std::vector of length 143, capacity 256 = {...}, begin=#0x7fffffffdbe0: 0, end=#0x7fffffffdb44: 143, k=#0x7fffffffdb48: 71, groupSize=#0x7fffffffdcd0: 7) at t.cc:95
#20959 0x0000000000401f42 in linearSelect (A=std::vector of length 1000, capacity 1024 = {...}, begin=#0x7fffffffdca4: 0, end=#0x7fffffffdca8: 1000, k=#0x7fffffffdcac: 50, groupSize=#0x7fffffffdcd0: 7) at t.cc:88
#20960 0x0000000000402356 in main () at t.cc:118
we can see that 3rd and all subsequent recursive calls get the same parameters, leading to infinite recursion.

Related

Compile-Time Base64 Decoding in C++

Is it possible to decode base64 encoded data to binary data at compile-time?
I think of something that looks like this:
constexpr auto decoded = decodeBase64<"SGVsbG8=">();
or
constexpr auto decoded = decodeBase64("SGVsbG8=");
I have no special requirements fo the resulting type of decoded.
I found it surprisingly hard to google for a constexpr base64 decoder, so I adapted the one here:
https://gist.github.com/tomykaira/f0fd86b6c73063283afe550bc5d77594
Since that's MIT licensed, (sigh), be sure to slap this somewhere in the source file:
/**
* The MIT License (MIT)
* Copyright (c) 2016 tomykaira
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
To return a string from a constexpr function, you need to return a char array. Because you can't return an array or std::string, an std::array is the best option. But there is a problem - due to a standards oversight, until C++17 the [] operator of std::array is non-const. You can work around that by inheriting and adding a constructor though:
template <size_t N>
struct fixed_string : std::array<char, N> {
constexpr fixed_string(const char (&input)[N]) : fixed_string(input, std::make_index_sequence<N>{}) {}
template <size_t... Is>
constexpr fixed_string(const char (&input)[N], std::index_sequence<Is...>) : std::array<char, N>{ input[Is]... } {}
};
Change the decoder to use that instead of std::string, and it seems to work as constexpr. Requires C++14 because C++11 constexpr functions can only have one return statement:
template <size_t N>
constexpr const std::array<char, ((((N-1) >> 2) * 3) + 1)> decode(const char(&input)[N]) {
constexpr unsigned char kDecodingTable[] = {
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64,
64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64,
64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64
};
static_assert(((N-1) & 3) == 0, "Input data size is not a multiple of 4");
char out[(((N-1) >> 2) * 3) + 1] {0};
size_t out_len = (N-1) / 4 * 3;
if (input[(N-1) - 1] == '=') out_len--;
if (input[(N-1) - 2] == '=') out_len--;
for (size_t i = 0, j = 0; i < N-1;) {
uint32_t a = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast<int>(input[i++])];
uint32_t b = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast<int>(input[i++])];
uint32_t c = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast<int>(input[i++])];
uint32_t d = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast<int>(input[i++])];
uint32_t triple = (a << 3 * 6) + (b << 2 * 6) + (c << 1 * 6) + (d << 0 * 6);
if (j < out_len) out[j++] = (triple >> 2 * 8) & 0xFF;
if (j < out_len) out[j++] = (triple >> 1 * 8) & 0xFF;
if (j < out_len) out[j++] = (triple >> 0 * 8) & 0xFF;
}
return fixed_string<(((N-1) >> 2) * 3) + 1>(out);
}
Usage:
constexpr auto x = decode("aGVsbG8gd29ybGQ=");
/*...*/
printf(x.data()); // hello world
Demo: https://godbolt.org/z/HFdk6Z
updated to address helpful feedback from Marek R and Frank
parktomatomi's answer helped a lot to find this solution.
Using C++17 and std::array this seems to work.
The base64 decoder is based on the answer https://stackoverflow.com/a/34571089/3158571
constexpr size_t decodeBase64Length(const char *s)
{
size_t len = std::char_traits<char>::length(s);
if (s[len - 2] == '=')
return (len / 4) * 3 - 2;
else if(s[len -1] == '=')
return (len / 4) * 3 - 1;
else
return (len / 4) * 3 ;
}
constexpr std::array<int, 256> prepareBase64DecodeTable() {
std::array<int, 256> T{ 0 }; // breaks constexpr: T.fill(-1) or missing initialization
for (int i = 0; i < 256; i++)
T[i] = -1;
for (int i = 0; i < 64; i++)
T["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[i]] = i;
return T;
}
// based on https://stackoverflow.com/a/34571089/3158571
template<int N>
constexpr std::array<std::byte, N> decodeBase64(const char *b64Str)
{
constexpr auto T = prepareBase64DecodeTable();
std::array<std::byte, N> out = { std::byte(0) };
int valb = -8;
for (size_t i = 0, val = 0, posOut = 0; i < std::char_traits<char>::length(b64Str) && T[b64Str[i]] != -1; i++) {
val = (val << 6) + T[b64Str[i]];
valb += 6;
if (valb >= 0) {
out[posOut++] = std::byte((val >> valb) & 0xFF);
valb -= 8;
}
}
return out;
}
Usage is not perfect as I can not deduce the length of the resulting array without passing it explicitly as template parameter:
#define B64c "SGVsbG8xMg=="
constexpr auto b64 = decodeBase64<decodeBase64Length(B64c)>(B64c); // array<byte,7>
Demo at https://godbolt.org/z/-DX2-m

illegal, left operand has type 'DWORD [29]'

I'm pretty new to C++ and I'm really stuck here.
if (bAk == 1)
{
int fireRate = 134;
if (shotTiming < 30)
{
int valueX = (AssaultRifle::recoilTableX[shotTiming] * 0.48) + shakerNum;
int smoothingX = valueX / 5;
int valueY = (AssaultRifle::recoilTableY[shotTiming] * 0.48) + shakerNum;
int smoothingY = valueY / 5;
Sleep(3);
for (int i = 0; i < 5; i++)
{
mouse_move(valueX, valueY);
Sleep(fireRate / 5);
}
shotTiming++;
cout << valueX;
}
}
The only build error I am getting at this point is illegal, left operand has type 'DWORD [29]' Both int values of recoilTable are saying that the AssaultRifle namespace must have arithmetic or unscoped enum type. I just need to be put in the right direction of finishing it.
#pragma once
#include <Windows.h>
namespace AssaultRifle
{
const size_t MAX_INDEX_WEAPON = 1;
const size_t MAX_INDEX_RECOIL = 29;
DWORD recoilTableY[MAX_INDEX_WEAPON][MAX_INDEX_RECOIL] = {
{ 40, 48, 48, 48, 33, 33, 28, 24, 16, 13, 18, 22, 24, 29, 33, 33, 33, 29, 22, 20, 17, 17, 17, 17, 20, 27, 27, 27, 26 }
};
DWORD recoilTableX[MAX_INDEX_WEAPON][MAX_INDEX_RECOIL] = {
{ -36, 5, -59, -49, 3, 20, 25, 45, 43, 32, 82, 8, 43, -32, -25, -40, -35, -32, -43 , -42, -42, -55, -25, 15, 20, 35, 50, 62, 40 }
};
}
Your recoilTableX and recoilTableY arrays are both 2-dimensional 1:
DWORD recoilTableY[<# elements in first dimension>][<# elements in second dimension>] = {...};
DWORD recoilTableX[<# elements in first dimension>][<# elements in second dimension>] = {...};
But when reading individual values from the arrays, your code is indexing into only the first dimension. That is why you are getting the error, as you can't access an entire array as a single integer like you are attempting to do. You have to specify indexes for ALL of the available dimensions.
Change this:
AssaultRifle::recoilTableX[shotTiming]
AssaultRifle::recoilTableY[shotTiming]
To this instead:
AssaultRifle::recoilTableX[0][shotTiming]
AssaultRifle::recoilTableY[0][shotTiming]
MAX_INDEX_WEAPON is 1, so there is only 1 slot in the first dimension of the arrays, so the ONLY valid index in the first dimension is 0, which makes the first dimension pretty useless and should be removed, unless you are planning on adding values for additional weapons in the future.
MAX_INDEX_RECOIL is 29, so there are 29 slots in the second dimension of the arrays, so the ONLY valid indexes in the second dimension are 0..28 inclusive, but your code allows index 29 to be accessed.
The NAMES of your MAX_INDEX_WEAPON and MAX_INDEX_RECOIL constants are misleading, as they are not actually being used as indexes at all.
1: also, your arrays should be declared as const.
Try this instead:
#pragma once
#include <Windows.h>
namespace AssaultRifle
{
const size_t MAX_WEAPONS = 1;
const size_t MAX_RECOILS = 29;
const int recoilTableY[MAX_WEAPONS][MAX_RECOILS] = {
{ { 40, 48, 48, 48, 33, 33, 28, 24, 16, 13, 18, 22, 24, 29, 33, 33, 33, 29, 22, 20, 17, 17, 17, 17, 20, 27, 27, 27, 26 } }
};
const int recoilTableX[MAX_WEAPONS][MAX_RECOILS] = {
{ { -36, 5, -59, -49, 3, 20, 25, 45, 43, 32, 82, 8, 43, -32, -25, -40, -35, -32, -43 , -42, -42, -55, -25, 15, 20, 35, 50, 62, 40 } }
};
}
if (bAk == 1)
{
int fireRate = 134;
if (shotTiming < AssaultRifle::MAX_RECOILS)
{
int valueX = (AssaultRifle::recoilTableX[0][shotTiming] * 0.48) + shakerNum;
int smoothingX = valueX / 5;
int valueY = (AssaultRifle::recoilTableY[0][shotTiming] * 0.48) + shakerNum;
int smoothingY = valueY / 5;
Sleep(3);
for (int i = 0; i < 5; i++)
{
mouse_move(valueX, valueY);
Sleep(fireRate / 5);
}
shotTiming++;
cout << valueX;
}
}

lock free concurrency example; why is it not safe?

I am trying to learn about concurrency in C++ and in doing so I am experimenting to see what works and what does not work. The example below is not well designed and I know there are much better ways of designing it but I would like to know why it seems that thread 1 and thread 2 are able to overwrite each other in the shared array. I thought the operations to the shared flag_atomic variable with the acquire/release semantics above and below the loading and writing of the shared idx_atomic index would prevent thread 1 and thread 2 retrieving the same index values regardless of the idx_atomic operation memory tags?
For reference I am using MSVC and x64.
#include <iostream>
#include <vector>
#include <atomic>
#include <thread>
#include <chrono>
using namespace std::chrono; // for ""ms operator
const size_t c_size = 40;
std::vector<int> shared_array;
std::atomic<bool> sync_start_atomic = false;
std::atomic<bool> flag_atomic = false;
std::atomic<size_t> idx_atomic = 0;
void thread1_x() {
bool expected_flag = false;
size_t temp_idx = 0;
while (!sync_start_atomic.load(std::memory_order_relaxed));
for (size_t i = 0; i < (c_size / 2); ++i) {
while (flag_atomic.compare_exchange_weak(expected_flag, true, std::memory_order_acq_rel, std::memory_order_acquire)) {
expected_flag = false;
}
temp_idx = idx_atomic.load(std::memory_order_relaxed);
idx_atomic.store((temp_idx + 1), std::memory_order_relaxed);
flag_atomic.store(false, std::memory_order_release);
shared_array[temp_idx] = i;
}
}
void thread2_x() {
bool expected_flag = false;
size_t temp_idx = 0;
while (!sync_start_atomic.load(std::memory_order_relaxed));
for (size_t i = 0; i < (c_size / 2); ++i) {
while (flag_atomic.compare_exchange_weak(expected_flag, true, std::memory_order_acq_rel, std::memory_order_acquire)) {
expected_flag = false;
}
temp_idx = idx_atomic.load(std::memory_order_relaxed);
idx_atomic.store((temp_idx + 1), std::memory_order_relaxed);
flag_atomic.store(false, std::memory_order_release);
shared_array[temp_idx] = i + 100;
}
}
void main(){
shared_array.reserve(c_size);
shared_array.assign(c_size, 0);
std::thread tn_1(thread1_x);
std::thread tn_2(thread2_x);
std::this_thread::sleep_for(60ms);
sync_start_atomic.store(true, std::memory_order_relaxed);
tn_1.join();
tn_2.join();
for (size_t i = 0; i < c_size; ++i) {
std::cout << shared_array[i] << " ";
}
std::cout << "\n";
}
Example real output:
100, 1, 101, 2, 3, 102, 4, 103, 104, 6, 106, 8, 108, 9, 10, 109, 11, 110, 12, 111, 14, 112, 113, 16, 17, 18, 115, 19, 116, 117, 118, 119, 0, 0, 0, 0, 0, 0, 0, 0.
Example expected output:
0, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 1, 2, 114, 3, 115, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 116, 16, 117, 17, 118, 18, 119, 19.
Your example output indicates that both threads are accessing the idx_atomic concurrently, which indicates a problem with your flag_atomic loop. The condition check you are using is backwards. compare_exchange_weak will return the result of the flag_atomic == expected_flag comparison - in other words, it returns true when the value is updated. Since you want to exit the loop when this happens, the comparison should be
while (!flag_atomic.compare_exchange_weak(expected_flag, true, std::memory_order_acq_rel, std::memory_order_acquire))

Tests finish with exit code 139 (interrupted by signal 11: SIGSEGV)

I'm a CS student and one of the classes I'm taking this semester requires me to complete different assignments (in C++) and then test them with unit-tests written by our professor.
Link to the repository with tests and the skeleton of the exercises
All of the tests form la1 worked just fine. Sadly most of them stopped working just as I started testing code from lab2 exercises. All the tests print the same message to the console:
Running main() from gtest_main.cc
Process finished with exit code 139 (interrupted by signal 11: SIGSEGV)
Today, after I've completed the lab2->greatestproduct exercise
Given an array of integers, write a function, maxProductFinderK, that can be obtained from any k integers in the array.
I checked all of the tests by hand and the result I've gotten were all correct so I don't think my code is the real issue here.
Is there anything that I could double-check to solve this problem? So far I've tried:
creating new CMakeLists.txt file (I don't think that's the problem since I use a template to create them)
cloning the repository with exercises again
Using different solutions just to make sure the code itself is not the problem
I'm running all the tests in CLion (with the latest update) on MacOS 10.13.3 if that's relevant.
// Edit: just as requested I added the code here in case the link will stop working.
Solution to the assignment:
int GreatestProduct(const std::vector<int> &numbers, int k) {
if ( numbers.size() > 0) {
std::vector<int> largestK = numbers;
std::sort(largestK.begin(), largestK.end());
if (k == 0) {
return 0;
} else if (k == 1) {
return largestK.at(largestK.size() - 1);
}
largestK.erase(largestK.begin(), largestK.end() - (k)); // remove all but k largest elements
std::vector<int> smallestK = numbers;
std::sort(smallestK.begin(), smallestK.end());
smallestK.erase(smallestK.begin(),
smallestK.begin() + k - (k % 2)); // remove all but k-(k%2) smallest elements
int mustContain = (k % 2) * (largestK.at(0) - 1) + 1;
//make sure that largestK and smallestK are the same size
if (k % 2 != 0) {
largestK.erase(largestK.begin());
}
std::vector<int> final;
int currentLargest = 0;
int currentSmallest = 0;
int greatestProduct = 1;
while (currentLargest + currentSmallest < k - (k % 2)) {
int firstOption = largestK.at(currentLargest) * largestK.at(currentLargest + 1);
int secondOption = smallestK.at(currentSmallest) * smallestK.at(currentSmallest + 1);
if (mustContain * firstOption > mustContain * secondOption) {
final.push_back(firstOption);
currentLargest += 2;
} else {
final.push_back(secondOption);
currentSmallest += 2;
}
}
for (int element : final) {
greatestProduct *= element;
}
return greatestProduct;
} else {
return 0;
} }
First out of 3 test. This one's the easiest since it always assumes that k = 2 and it doesn't test negative integers.
#include <GreatestProduct.h>
#include <gtest/gtest.h>
#include <MemLeakTest.h>
#include <StringUtility.h>
using TestParam = std::pair<std::pair<std::vector<int>, int>, int>;
class GreatestProductOfStep1Tests : public ::testing::TestWithParam<TestParam>, MemLeakTest {
};
TEST_P(GreatestProductOfStep1Tests, GreatestProductOfPositiveNumbersNfixedTo2ShouldReturnExpectedResult) {
const TestParam &p = GetParam();
int expected = p.second;
const std::vector<int> &numbers = p.first.first;
int N = p.first.second;
EXPECT_EQ(expected, GreatestProduct(numbers, N))
<< "Did call GreatestProductOf(" << utility::ToString<int>(numbers) << ", " << N << ")\n";
}
std::vector<TestParam> greatest_product_test_positive_n_eq_2_data{
{{{0, 1, 2, 3, 4}, 2}, 12},
{{{6, 6, 6}, 2}, 36},
{{{9, 8, 3, 5, 8, 1, 3, 5, 10}, 2}, 90},
{{{17, 5, 9, 1000, 15689, 57, 89, 10, 89, 283, 197, 0, 0, 132, 45, 78, 18, 15, 89,
19203, 98, 14, 78, 45, 35, 23, 24, 25, 46, 45, 756, 7567, 123, 890, 99, 98, 51,
991, 9123, 8912, 89534, 8923, 1823, 7385, 91, 1748, 1, 1, 893, 2813,
1381, 23, 563, 645, 24, 24, 51, 839, 38, 34, 35, 123, 324, 9283, 22, 19}, 2}, 1719321402},
{{{1, 1}, 2}, 1},
{{{0, 1}, 2}, 0},
{{{3789, 999}, 2}, 3785211}};
INSTANTIATE_TEST_CASE_P(GreatestProductOfStep1Tests,
GreatestProductOfStep1Tests,
::testing::ValuesIn(greatest_product_test_positive_n_eq_2_data));

c++ casting to byte (unit8_t) during subtraction won't force underflow like I expect; output is int16_t; why?

Note that byte is an 8-bit type (uint8_t) and unsigned int is a 16-bit type (uint16_t).
The following doesn't produce the results that I expect. I expect it to underflow and the result to always be a uint8_t, but it becomes a signed int (int16_t) instead!!! Why?
Focus in on the following line of code in particular: (byte)seconds - tStart
I expect its output to ALWAYS be an unsigned 8-bit value (uint8_t), but it is instead outputting a signed 16-bit value: int16_t.
How do I get the result of the subraction to always be a uint8_t type?
while (true)
{
static byte tStart = 0;
static unsigned int seconds = 0;
seconds++;
//Print output from microcontroller
typeNum((byte)seconds); typeString(", "); typeNum(tStart); typeString(", ");
typeNum((byte)seconds - tStart); typeString("\n");
if ((byte)seconds - tStart >= (byte)15)
{
typeString("TRUE!\n");
tStart = seconds; //update
}
}
Sample output:
Column 1 is (byte)seconds, Column 2 is tStart, Column 3 is Column 1 minus Column 2 ((byte)seconds - tStart)
Notice that Column 3 becomes negative (int8_t) once Column 1 overflows from 255 to 0. I expect (and want) it to remain a positive (unsigned) 8-bit value by underflowing instead.
196, 195, 1
197, 195, 2
198, 195, 3
199, 195, 4
200, 195, 5
201, 195, 6
202, 195, 7
203, 195, 8
204, 195, 9
205, 195, 10
206, 195, 11
207, 195, 12
208, 195, 13
209, 195, 14
210, 195, 15
TRUE!
211, 210, 1
212, 210, 2
213, 210, 3
214, 210, 4
215, 210, 5
216, 210, 6
217, 210, 7
218, 210, 8
219, 210, 9
220, 210, 10
221, 210, 11
222, 210, 12
223, 210, 13
224, 210, 14
225, 210, 15
TRUE!
226, 225, 1
227, 225, 2
228, 225, 3
229, 225, 4
230, 225, 5
231, 225, 6
232, 225, 7
233, 225, 8
234, 225, 9
235, 225, 10
236, 225, 11
237, 225, 12
238, 225, 13
239, 225, 14
240, 225, 15
TRUE!
241, 240, 1
242, 240, 2
243, 240, 3
244, 240, 4
245, 240, 5
246, 240, 6
247, 240, 7
248, 240, 8
249, 240, 9
250, 240, 10
251, 240, 11
252, 240, 12
253, 240, 13
254, 240, 14
255, 240, 15
TRUE!
0, 255, -255
1, 255, -254
2, 255, -253
3, 255, -252
4, 255, -251
5, 255, -250
6, 255, -249
7, 255, -248
8, 255, -247
9, 255, -246
10, 255, -245
11, 255, -244
12, 255, -243
13, 255, -242
14, 255, -241
15, 255, -240
16, 255, -239
17, 255, -238
18, 255, -237
19, 255, -236
20, 255, -235
21, 255, -234
22, 255, -233
23, 255, -232
24, 255, -231
25, 255, -230
26, 255, -229
27, 255, -228
28, 255, -227
29, 255, -226
30, 255, -225
31, 255, -224
32, 255, -223
33, 255, -222
34, 255, -221
35, 255, -220
Here is the typeNum function from above:
//--------------------------------------------------------------------------------------------
//typeNum (overloaded)
//-see AVRLibC int to string functions: http://www.nongnu.org/avr-libc/user-manual/group__avr__stdlib.html
//--------------------------------------------------------------------------------------------
//UNSIGNED:
void typeNum(uint8_t myNum)
{
char buffer[4]; //3 for the number (up to 2^8 - 1, or 255 max), plus 1 char for the null terminator
utoa(myNum, buffer, 10); //base 10 number system
typeString(buffer);
}
void typeNum(uint16_t myNum)
{
char buffer[6]; //5 for the number (up to 2^16 - 1, or 65535 max), plus 1 char for the null terminator
utoa(myNum, buffer, 10); //base 10 number system
typeString(buffer);
}
void typeNum(uint32_t myNum)
{
char buffer[11]; //10 chars for the number (up to 2^32 - 1, or 4294967295 max), plus 1 char for the null terminator
ultoa(myNum, buffer, 10); //base 10 number system
typeString(buffer);
}
//SIGNED:
void typeNum(int8_t myNum)
{
char buffer[5]; //4 for the number (down to -128), plus 1 char for the null terminator
itoa(myNum, buffer, 10); //base 10 number system
typeString(buffer);
}
void typeNum(int16_t myNum)
{
char buffer[7]; //6 for the number (down to -32768), plus 1 char for the null terminator
itoa(myNum, buffer, 10); //base 10 number system
typeString(buffer);
}
void typeNum(int32_t myNum)
{
char buffer[12]; //11 chars for the number (down to -2147483648), plus 1 char for the null terminator
ltoa(myNum, buffer, 10); //base 10 number system
typeString(buffer);
}
So I figured it out:
The answer is very simple, but the understanding behind it is not.
Answer:
(How to fix it):
Instead of using (byte)seconds - tStart, use (byte)((byte)seconds - tStart). That's it! Problem solved! All you need to do is cast the output of the mathematical operation (a subtraction in this case) to a byte as well, and it's fixed! Otherwise it returns as a signed int, which produces the errant behavior.
So, why does this happen?
Answer:
In C, C++, and C#, there is no such thing as a mathematical operation on a byte! Apparently the assembly level functions required for operators like +, -, etc, don't exist for byte inputs. Instead, all bytes are first implicitly cast (promoted) to an int before the operation is conducted, then the mathematical operation is conducted on ints, and when it is completed, it returns an int too!
So, this code (byte)seconds - tStart is implicitly cast (promoted in this case) by the compiler as follows: (int)(byte)seconds - (int)tStart...and it returns an int too. Confusing, eh? I certainly thought so!
Here's some more reading on the matter:
(the more asterisks, *, the more useful)
*****byte + byte = int... why? <--ESPECIALLY USEFUL
*****Implicit type conversion rules in C++ operators <--ESPECIALLY USEFUL. This answer here shows when implicit casts take place, and states, "Note. The minimum size of operations is int. So short/char are promoted to int before the operation is done."
*****Google search for "c++ does implicit casting occur with comparisons?"
https://www.tutorialspoint.com/cprogramming/c_type_casting.htm
http://www.improgrammer.net/type-casting-c-language/
Google search for "c++ implicit casting"
http://www.cplusplus.com/doc/tutorial/typecasting/
http://en.cppreference.com/w/cpp/language/implicit_conversion
http://en.cppreference.com/w/cpp/language/operator_comparison
Now let's look at some real C++ examples:
Here is a full C++ program you can compile and run to test expressions to see what the return type is, and if it has been implicitly cast by to the compiler to something you don't intend:
#include <iostream>
using namespace std;
//----------------------------------------------------------------
//printTypeAndVal (overloaded function)
//----------------------------------------------------------------
//UNSIGNED:
void printTypeAndVal(uint8_t myVal)
{
cout << "uint8_t = " << (int)myVal << endl; //(int) cast is required to prevent myVal from printing as a char
}
void printTypeAndVal(uint16_t myVal)
{
cout << "uint16_t = " << myVal << endl;
}
void printTypeAndVal(uint32_t myVal)
{
cout << "uint32_t = " << myVal << endl;
}
void printTypeAndVal(uint64_t myVal)
{
cout << "uint64_t = " << myVal << endl;
}
//SIGNED:
void printTypeAndVal(int8_t myVal)
{
cout << "int8_t = " << (int)myVal << endl; //(int) cast is required to prevent myVal from printing as a char
}
void printTypeAndVal(int16_t myVal)
{
cout << "int16_t = " << myVal << endl;
}
void printTypeAndVal(int32_t myVal)
{
cout << "int32_t = " << myVal << endl;
}
void printTypeAndVal(int64_t myVal)
{
cout << "int64_t = " << myVal << endl;
}
//FLOATING TYPES:
void printTypeAndVal(float myVal)
{
cout << "float = " << myVal << endl;
}
void printTypeAndVal(double myVal)
{
cout << "double = " << myVal << endl;
}
void printTypeAndVal(long double myVal)
{
cout << "long double = " << myVal << endl;
}
//----------------------------------------------------------------
//main
//----------------------------------------------------------------
int main()
{
cout << "Begin\n\n";
//Test variables
uint8_t u1 = 0;
uint8_t u2 = 1;
//Test cases:
//for a single byte, explicit cast of the OUTPUT from the mathematical operation is required to get desired *unsigned* output
cout << "uint8_t - uint8_t:" << endl;
printTypeAndVal(u1 - u2); //-1 (bad)
printTypeAndVal((uint8_t)u1 - (uint8_t)u2); //-1 (bad)
printTypeAndVal((uint8_t)(u1 - u2)); //255 (fixed!)
printTypeAndVal((uint8_t)((uint8_t)u1 - (uint8_t)u2)); //255 (fixed!)
cout << endl;
//for unsigned 2-byte types, explicit casting of the OUTPUT is required too to get desired *unsigned* output
cout << "uint16_t - uint16_t:" << endl;
uint16_t u3 = 0;
uint16_t u4 = 1;
printTypeAndVal(u3 - u4); //-1 (bad)
printTypeAndVal((uint16_t)(u3 - u4)); //65535 (fixed!)
cout << endl;
//for larger standard unsigned types, explicit casting of the OUTPUT is ***NOT*** required to get desired *unsigned* output! IN THIS CASE, NO IMPLICIT PROMOTION (CAST) TO A LARGER *SIGNED* TYPE OCCURS.
cout << "unsigned int - unsigned int:" << endl;
unsigned int u5 = 0;
unsigned int u6 = 1;
printTypeAndVal(u5 - u6); //4294967295 (good--no fixing is required)
printTypeAndVal((unsigned int)(u5 - u6)); //4294967295 (good--no fixing was required)
cout << endl;
return 0;
}
You can also run this program online here: http://cpp.sh/6kjgq
Here is the output. Notice that both the single unsigned byte uint8_t - uint8_t case, and the dual unsigned byte uint16_t - uint16_t case each were implicitly cast (promoted) by the C++ compiler to a 4-byte signed int32_t (int) variable type. This is the behavior that you need to notice. Therefore, the result of those subtractions is negative, which is the unusual behavior that originally confused me, since I had anticipated it would instead underflow to become the unsigned variable's maximum value instead (since we are doing 0 - 1). In order to achieve the desired underflow then, I had to explicitly cast the output result of the subtraction to the desired unsigned type, not just the inputs. For the unsigned int case, however, this explicit cast of the result was NOT required.
Begin
uint8_t - uint8_t:
int32_t = -1
int32_t = -1
uint8_t = 255
uint8_t = 255
uint16_t - uint16_t:
int32_t = -1
uint16_t = 65535
unsigned int - unsigned int:
uint32_t = 4294967295
uint32_t = 4294967295
Here's another brief program example to show that the single unsigned byte (unsigned char) variables are being promoted to signed ints (int) when operated upon.
#include <stdio.h>
int main(int argc, char **argv)
{
unsigned char x = 130;
unsigned char y = 130;
unsigned char z = x + y;
printf("%u\n", x + y); // Prints 260.
printf("%u\n", z); // Prints 4.
}
Output:
260
4
Test here: http://cpp.sh/84eo