Im writing a programme that opens and openGL windows with an image and connects to my android device where the user uses the device as a sort of trackpad to pan and zoom in and out. All is working fine however the programme gets stuck in the glutMainLoop and will not proceed with accepting data from the device. Apparently glutIdleFunc is the solution to my problem however i cant see how to implement this in my code without getting a memory error? Could someone show me how to put the function into my code so it runs the connection code as well as the opengl stuff?
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <string.h>
#include <strings.h>
#include <vrpn_Shared.h>
#include <vrpn_Analog.h>
#include <vector>
#include <GL/freeglut.h>
#include <imageviewer.h>
using namespace std;
int done = 0;
int accepted = 0; // Signals that the program should exit
unsigned tracker_stride = 1; // Every nth report will be printed
//-------------------------------------
// This section contains the data structure that holds information on
// the devices that are created. For each named device, a remote of each
// type analog is created.
class device_info {
public:
char *name;
vrpn_Analog_Remote *ana;
};
const unsigned MAX_DEVICES = 2;
//-------------------------------------
// This section contains the data structure that is used to determine how
// often to print a report for each sensor of each tracker. Each element
// contains a counter that is used by the callback routine to keep track
// of how many it has skipped. There is an element for each possible sensor.
// A new array of elements is created for each new tracker object, and a
// pointer to it is passed as the userdata pointer to the callback handlers.
class t_user_callback {
public:
char t_name[vrpn_MAX_TEXT_LEN];
vector<unsigned> t_counts ;
};
//Callback handlers
void VRPN_CALLBACK handle_analog (void *userdata, const vrpn_ANALOGCB a)
{
int i;
const char *name = (const char *)userdata;
printf("Input from %s:\n \n %5.0f", name, a.channel[0]);
for (i = 1; i < a.num_channel; i++) {
printf(" %5.0f \n", a.channel[1]);
}
printf(" \n");
}
int main (int argc, char * argv [])
{
int print_for_tracker = 1; // Print tracker reports?
int print_for_button = 1; // Print button reports?
int print_for_analog = 1; // Print analog reports?
int print_for_dial = 1; // Print dial reports?
int print_for_text = 1; // Print warning/error messages?
device_info device_list[MAX_DEVICES];
unsigned num_devices = 0;
int i;
// Parse arguments, creating objects
for (i = 1; i < argc; i++) {
if (!strcmp(argv[i], "-notracker")) {
print_for_tracker = 0;
} else if (!strcmp(argv[i], "-nobutton")) {
print_for_button = 0;
} else if (!strcmp(argv[i], "-noanalog")) {
print_for_analog = 0;
} else if (!strcmp(argv[i], "-nodial")) {
print_for_dial = 0;
} else if (!strcmp(argv[i], "-notext")) {
print_for_text = 0;
} else if (!strcmp(argv[i], "-trackerstride")) {
if (tracker_stride <= 0) {
fprintf(stderr, "-trackerstride argument must be 1 or greater\n");
return -1;
}
} else { // Create a device and connect to it.
device_info *dev;
// Name the device and open it as everything
dev = &device_list[num_devices];
dev->name = argv[i];
dev->ana = new vrpn_Analog_Remote(dev->name);
if (print_for_analog) {
printf(" Analog");
dev->ana->register_change_handler(dev->name, handle_analog);
}
printf(".\n");
num_devices++;
}
}
// main interactive loop
printf("Press ^C to exit.\n");
while ( ! done ) {
unsigned i;
// Let all the devices do their things
for (i = 0; i < num_devices; i++) {
device_list[i].ana->mainloop();
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
glutInitWindowSize(400,300);
glutInitWindowPosition(200,100);
glutCreateWindow("ImageViewer");
init();
glutDisplayFunc(display);
glutMotionFunc(drag);
glutMouseFunc(mouse);
// glutIdleFunc(IdleFunc);
glutMainLoop();
}
}
return 0;
}
glut is fine if it can manage all of the input devices, and everything is event-driven from the inputs that it manages. Once you have unmanaged input devices or non-event-based processing, you probably want to use something other than glut. Your other alternative is to fork and run your asynchronous stuff in a separate process (or thread).
Related
I'm trying to build an android c++ app using tflite. I failed to compile the .so file on my own so I got some pre-compiled one's from the internet. I've created a dummy project to test it and it works just fine. However when I implement it on my project everything falls apart. I've checked whether the inputs are right, they are, the size is right, initialization is fine, it's almost identical with my dummy project, so what could be the issue?
Here is my code:
tflite.cpp:
#include "tflite.hpp"
tflite::tflite(uint8_t *data, size_t size)
{
try
{
lib_tflite::ErrorReporter* error_reporter;
this->m_env = lib_tflite::FlatBufferModel::BuildFromBuffer((const char *)data, size, error_reporter);
lib_tflite::ops::builtin::BuiltinOpResolver resolver;
lib_tflite::InterpreterBuilder(*this->m_env, resolver)(&m_interpreter);
if (m_interpreter->AllocateTensors() != kTfLiteOk)
{
throw std::runtime_error("Failed to allocate tensor");
}
m_interpreter->SetNumThreads(2);
this->m_input_node_count = m_interpreter->inputs().size();
this->m_output_node_count = m_interpreter->outputs().size();
for (size_t idx = 0; idx < this->m_input_node_count; ++idx)
{
int input = m_interpreter->inputs()[idx];
auto height = m_interpreter->tensor(input)->dims->data[1];
auto width = m_interpreter->tensor(input)->dims->data[2];
auto channels = m_interpreter->tensor(input)->dims->data[3];
std::vector<int> res = {(int)this->m_input_node_count, channels, width, height};
this->m_inputDims.push_back(res);
const TfLiteTensor* input_tensor = m_interpreter->input_tensor(idx);
size_t element_count = 1;
for (int i = 0; i < input_tensor->dims->size; i++)
{
element_count *= input_tensor->dims->data[i];
}
this->m_input_elem_size.push_back(element_count);
}
for (size_t idx = 0; idx < this->m_output_node_count; ++idx)
{
int output = m_interpreter->outputs()[idx];
auto height = m_interpreter->tensor(output)->dims->data[1];
auto width = m_interpreter->tensor(output)->dims->data[2];
auto channels = m_interpreter->tensor(output)->dims->data[3];
std::vector<int> res = {(int)this->m_output_node_count, channels, width, height};
this->m_outputDims.push_back(res);
const TfLiteTensor* output_tensor = m_interpreter->output_tensor(idx);
int element_count = 1;
for (int i = 0; i < output_tensor->dims->size; i++) {
element_count *= output_tensor->dims->data[i];
}
this->m_output_elem_size.push_back(element_count);
}
for (size_t idx = 0; idx < this->m_input_node_count; ++idx)
{
this->m_input_buffer.emplace_back(this->m_input_elem_size[idx], 0
);
}
for (size_t idx = 0; idx < this->m_output_node_count; ++idx)
{
this->m_output_buffer.emplace_back(this->m_output_elem_size[idx], 0
);
}
}
bool tflite::run(std::vector<float> &t_out_buffer,
std::vector<float> &t_cls_buffer,
std::vector<float> &t_buffer,
size_t region_size) noexcept
{
for(size_t idx = 0; idx < this->m_input_node_count; idx++)
{
float* data_ptr = m_interpreter->typed_input_tensor<float>(idx);
memcpy(data_ptr, t_buffer.data(), this->m_input_elem_size[idx]);
}
// This is where it fails
if (kTfLiteOk != this->m_interpreter->Invoke())
{
log_error("Failed to invoke\n");
return false;
}
for(size_t idx = 0; idx < this->m_output_node_count; idx++)
{
float* output = this->m_interpreter->typed_output_tensor<float>(idx);
this->m_output_buffer[idx] = std::vector<float> (output,
output + this->m_output_elem_size[idx]);
}
t_cls_buffer = this->m_output_buffer[0];
t_out_buffer = m_output_buffer[1];
}
/* end_of_file */
tflite.hpp:
#ifndef TFLITE_DRIVER_HPP
#define TFLITE_DRIVER_HPP
#include <memory>
#include "tensorflow/lite/interpreter.h"
#include "tensorflow/lite/kernels/register.h"
#include "tensorflow/lite/model.h"
#include "tensorflow/lite/optional_debug_tools.h"
namespace lib_tflite = ::tflite;
class tflite
{
public:
tflite() = delete;
virtual ~tflite() noexcept = default;
tflite(tflite &&) = delete;
tflite & operator=(tflite &&) = delete;
tflite(const tflite &) = delete;
tflite & operator=(tflite &) = delete;
tflite(uint8_t *data, size_t size);
bool run( std::vector<float> &t_out_buffer,
std::vector<float> &t_cls_buffer,
std::vector<float> &t_buffer,
size_t region_size) noexcept;
private:
lib_tflite::ErrorReporter* error_reporter;
lib_tflite::ops::builtin::BuiltinOpResolver resolver;
std::unique_ptr<lib_tflite::FlatBufferModel> m_env;
std::unique_ptr<lib_tflite::Interpreter> m_interpreter;
std::vector<const char *> m_input_names;
std::vector<const char *> m_output_names;
size_t m_input_node_count;
size_t m_output_node_count;
std::vector<lib_tflite::Tensor> m_inputTensors;
std::vector<lib_tflite::Tensor> m_outputTensors;
std::vector<size_t> m_input_elem_size;
std::vector<size_t> m_output_elem_size;
std::vector<std::vector<int>> m_inputDims;
std::vector<std::vector<int>> m_outputDims;
std::vector<std::vector<float>> m_input_buffer;
std::vector<std::vector<float>> m_output_buffer;
std::unique_ptr<lib_tflite::MemoryAllocation> m_memory_info;
};
#endif // TFLITE_DRIVER_HPP
/* end_of_file */
Note that my project runs on 2 threads, one get's the input and the other calls tflite. Like I've said the input's are indeed correct. The constructor is ran once, but the run function runs every frame.
Here is the output I get when I run it:
E/libc: Access denied finding property "ro.mediatek.platform"
E/libc: Access denied finding property "ro.chipname"
A/libc: Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x13c6759bfc61 in tid 27936 (processing), pid 27893 (ample.nerveblox)
I've debugged and found out the line this error happens is where I call this->m_interpreter->Invoke() inside the run function.
access denied error seems like there is no property for "ro.mediatek.platform" & "ro.chipname" if you run the "adb shell getprop".
So, I think, "ro.mediatek.platform" & "ro.chipname" are not a property.
I use superpowered, I need send midi note to a controller midi.
The problem is that I saw a function send(int deviceID, unsigned char *data, int bytes);
Where in their source code say:
deviceID: Device identifier.
data: Raw MIDI data.
bytes: Number of
bytes.
I don't know the values that I need put exactly on data and bytes to work.
The raw midi could be 0x80 - 0x48 - 0x00(start of C4 note, pitch= 72, See values)
And the bytes 1001nnnn0kkkkkkk0kkkkkkk(note on event See values) for example?
Something like that:
SuperpoweredUSBMIDI::send(deviceID, reinterpret_cast(0x80 - 0x48 - 0x00), 1001nnnn0kkkkkkk0kkkkkkk);
The problem that always crash, and I can't debug or get the error for the reason that I use the mobile with otg to replicate the error.
When I find a solution, I will put it as soon as I can.
I'm newbie with markdown, sorry for any mistakes and my English grammar.
Edit: I'm using the example project that they have on GitHub for testing purposes, specifically the simpleusb project. (source)
I make a small modifications and work, but with this specifically I try with many ways and nothing. I think this simple macrochange at least could work if I insert well the values
class simpleusb.cpp:
#include <jni.h>
#include <math.h>
#include <SuperpoweredCPU.h>
#include <AndroidIO/SuperpoweredUSBAudio.h>
#include <malloc.h>
#include <pthread.h>
// Called when the application is initialized. You can initialize SuperpoweredUSBSystem
// at any time btw. Although this function is marked __unused, it's due Android Studio's
// annoying warning only. It's definitely used.
__unused jint JNI_OnLoad (
JavaVM * __unused vm,
void * __unused reserved
) {
SuperpoweredUSBSystem::initialize(NULL, NULL, NULL, NULL, NULL);
return JNI_VERSION_1_6;
}
// Called when the application is closed. You can destroy SuperpoweredUSBSystem at any time btw.
// Although this function is marked __unused, it's due Android Studio's annoying warning only.
// It's definitely used.
__unused void JNI_OnUnload (
JavaVM * __unused vm,
void * __unused reserved
) {
SuperpoweredUSBSystem::destroy();
}
// A helper structure for sine wave output.
typedef struct sineWaveOutput {
float mul;
unsigned int step;
} sineWaveOutput;
// This is called periodically for audio I/O. Audio is always 32-bit floating point,
// regardless of the bit depth preference. (SuperpoweredUSBAudioProcessingCallback)
static bool audioProcessing (
void *clientdata,
int __unused deviceID,
float *audioIO,
int numberOfSamples,
int samplerate,
int __unused numInputChannels,
int numOutputChannels
) {
// If audioIO is NULL, then it's the very last call, IO is closing.
if (!audioIO) {
// Free memory for sine wave struct.
free(clientdata);
return true;
}
sineWaveOutput *swo = (sineWaveOutput *)clientdata;
if (swo->mul == 0.0f) swo->mul = (2.0f * float(M_PI) * 300.0f) / float(samplerate);
// Output sine wave on all output channels.
for (int n = 0; n < numberOfSamples; n++) {
float v = sinf(swo->step++ * swo->mul) * 0.5f;
for (int c = 0; c < numOutputChannels; c++) *audioIO++ = v;
}
return true; // Return false for silence, true if we put audio output into audioIO.
}
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
static int latestMidiCommand = -1;
static int latestMidiChannel = 0;
static int latestMidiNumber = 0;
static int latestMidiValue = 0;
// This is called when some MIDI data is coming in.
// We are doing some primitive MIDI data processing here.
static void onMidiReceived (
void * __unused clientdata,
int __unused deviceID,
unsigned char *data,
int bytes
) {
while (bytes > 0) {
if (*data > 127) {
int command = *data >> 4;
switch (command) {
case 8: // note off
case 9: // note on
case 11: // control change
pthread_mutex_lock(&mutex);
// store incoming MIDI data
latestMidiCommand = command;
latestMidiChannel = *data++ & 15;
latestMidiNumber = *data++;
latestMidiValue = *data++;
pthread_mutex_unlock(&mutex);
bytes -= 3;
break;
default:
data++;
bytes--;
}
} else {
data++;
bytes--;
}
}
}
// Beautifying the ugly Java-C++ bridge (JNI) with these macros.
#define PID com_superpowered_simpleusb_SuperpoweredUSBAudio // Java package name and class name. Don't forget to update when you copy this code.
#define MAKE_JNI_FUNCTION(r, n, p) extern "C" JNIEXPORT r JNICALL Java_ ## p ## _ ## n
#define JNI(r, n, p) MAKE_JNI_FUNCTION(r, n, p)
// This is called by the SuperpoweredUSBAudio Java object when a USB device is connected.
JNI(jint, onConnect, PID) (
JNIEnv *env,
jobject __unused obj,
jint deviceID,
jint fd,
jbyteArray rawDescriptor
) {
jbyte *rd = env->GetByteArrayElements(rawDescriptor, NULL);
int dataBytes = env->GetArrayLength(rawDescriptor);
int r = SuperpoweredUSBSystem::onConnect(deviceID, fd, (unsigned char *)rd, dataBytes);
env->ReleaseByteArrayElements(rawDescriptor, rd, JNI_ABORT);
// r is 0 if SuperpoweredUSBSystem can't do anything with the connected device.
// r & 2 is true if the device has MIDI. Start receiving events.
if (r & 2) {
SuperpoweredUSBMIDI::startIO(deviceID, NULL, onMidiReceived);
//TODO HERE IT'S THE PROBLEM: error: integer literal is too large to be represented in any integer type
SuperpoweredUSBMIDI::send(deviceID, reinterpret_cast<unsigned char *>(0x80 - 0x48 - 0x00), 100100010011100000000011);
//FINISH PROBLEM
}
// r & 1 is true if the device has audio. Start output.
if (r & 1) {
// allocate struct for sine wave oscillator
sineWaveOutput *swo = (sineWaveOutput *)malloc(sizeof(sineWaveOutput));
if (swo) {
swo->mul = 0.0f;
swo->step = 0;
SuperpoweredCPU::setSustainedPerformanceMode(true);
// Our preferred settings: 44100 Hz, 16 bits, 0 input channels, 256 output channels,
// low latency. Superpowered will set up the audio device as close as it can to these.
SuperpoweredUSBAudio::easyIO (
deviceID, // deviceID
44100, // sampling rate
16, // bits per sample
0, // numInputChannels
256, // numOutputChannels
SuperpoweredUSBLatency_Low, // latency
swo, // clientData
audioProcessing // SuperpoweredUSBAudioProcessingCallback
);
}
}
return r;
}
// This is called by the SuperpoweredUSBAudio Java object when a USB device is disconnected.
JNI(void, onDisconnect, PID) (
JNIEnv * __unused env,
jobject __unused obj,
jint deviceID
) {
SuperpoweredUSBSystem::onDisconnect(deviceID);
SuperpoweredCPU::setSustainedPerformanceMode(false);
}
#undef PID
#define PID com_superpowered_simpleusb_MainActivity
// This is called by the MainActivity Java object periodically.
JNI(jintArray, getLatestMidiMessage, PID) (
JNIEnv *env,
jobject __unused obj
) {
jintArray ints = env->NewIntArray(4);
jint *i = env->GetIntArrayElements(ints, 0);
pthread_mutex_lock(&mutex);
i[0] = latestMidiCommand;
i[1] = latestMidiChannel;
i[2] = latestMidiNumber;
i[3] = latestMidiValue;
pthread_mutex_unlock(&mutex);
env->ReleaseIntArrayElements(ints, i, 0);
return ints;
}
The other important class but I don't change on this problem, MainActivity:
#RequiresApi(api = Build.VERSION_CODES.M)
public class MainActivity extends AppCompatActivity implements SuperpoweredUSBAudioHandler {
private Handler handler;
private TextView textView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.text);
SuperpoweredUSBAudio usbAudio = new SuperpoweredUSBAudio(getApplicationContext(), this);
usbAudio.check();
// Update UI every 40 ms.
Runnable runnable = new Runnable() {
#Override
public void run() {
int[] midi = getLatestMidiMessage();
switch (midi[0]) {
case 8: textView.setText(String.format(Locale.ENGLISH, "Note Off, CH %d, %d, %d",
midi[1] + 1, midi[2], midi[3]));
break;
case 9: textView.setText(String.format(Locale.ENGLISH, "Note On, CH %d, %d, %d",
midi[1] + 1, midi[2], midi[3]));
break;
case 11: textView.setText(String.format(Locale.ENGLISH, "Control Change, CH %d, %d, %d",
midi[1] + 1, midi[2], midi[3]));
break;
}
handler.postDelayed(this, 40);
}
};
handler = new Handler();
handler.postDelayed(runnable, 40);
/*Not look, only for testing purposes and for remember what use.
byte[] buffer = new byte[32];
int numBytes = 0;
int channel = 6; // MIDI channels 1-16 are encoded as 0-15.
buffer[numBytes++] = (byte)(0x90 + (channel - 1)); // note on
buffer[numBytes++] = (byte)60; // pitch is middle C
buffer[numBytes++] = (byte)127; // max velocity
int offset = 0;*/
}
public void onUSBAudioDeviceAttached(int deviceIdentifier) {
}
public void onUSBMIDIDeviceAttached(int deviceIdentifier) {
}
public void onUSBDeviceDetached(int deviceIdentifier) {
}
// Function implemented in the native library.
private native int[] getLatestMidiMessage();
static {
System.loadLibrary("SuperpoweredExample");
}
}
Error that I can't build app finally:
Build command failed.
Error while executing process D:\Users\ramoc\AppData\Local\Android\sdk\cmake\3.6.4111459\bin\cmake.exe with arguments {--build F:\PROYECTOFIN\SuperpoweredUSBExample\simpleusb\.externalNativeBuild\cmake\debug\arm64-v8a --target SuperpoweredExample}
[1/2] Building CXX object CMakeFiles/SuperpoweredExample.dir/simpleusb.cpp.o
FAILED: D:\Users\ramoc\AppData\Local\Android\sdk\ndk-bundle\toolchains\llvm\prebuilt\windows-x86_64\bin\clang++.exe --target=aarch64-none-linux-android --gcc-toolchain=D:/Users/ramoc/AppData/Local/Android/sdk/ndk-bundle/toolchains/aarch64-linux-android-4.9/prebuilt/windows-x86_64 --sysroot=D:/Users/ramoc/AppData/Local/Android/sdk/ndk-bundle/sysroot -DSuperpoweredExample_EXPORTS -IF:/PROYECTOFIN/SuperpoweredUSBExample/simpleusb/src/main/jni/src/main/jni -IF:/PROYECTOFIN/SuperpoweredUSBExample/simpleusb/../../../Superpowered -isystem D:/Users/ramoc/AppData/Local/Android/sdk/ndk-bundle/sources/cxx-stl/gnu-libstdc++/4.9/include -isystem D:/Users/ramoc/AppData/Local/Android/sdk/ndk-bundle/sources/cxx-stl/gnu-libstdc++/4.9/libs/arm64-v8a/include -isystem D:/Users/ramoc/AppData/Local/Android/sdk/ndk-bundle/sources/cxx-stl/gnu-libstdc++/4.9/include/backward -isystem D:/Users/ramoc/AppData/Local/Android/sdk/ndk-bundle/sysroot/usr/include/aarch64-linux-android -D__ANDROID_API__=21 -g -DANDROID -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -Wa,--noexecstack -Wformat -Werror=format-security -fsigned-char -IF:\PROYECTOFIN\SuperpoweredUSBExample\simpleusb\..\..\..\Superpowered -O0 -fno-limit-debug-info -fPIC -MD -MT CMakeFiles/SuperpoweredExample.dir/simpleusb.cpp.o -MF CMakeFiles\SuperpoweredExample.dir\simpleusb.cpp.o.d -o CMakeFiles/SuperpoweredExample.dir/simpleusb.cpp.o -c F:\PROYECTOFIN\SuperpoweredUSBExample\simpleusb\src\main\jni\simpleusb.cpp
F:\PROYECTOFIN\SuperpoweredUSBExample\simpleusb\src\main\jni\simpleusb.cpp:129:100: error: integer literal is too large to be represented in any integer type
SuperpoweredUSBMIDI::send(deviceID, reinterpret_cast<unsigned char *>(0x80 - 0x48 - 0x00), 100100010011100000000011);
^
F:\PROYECTOFIN\SuperpoweredUSBExample\simpleusb\src\main\jni\simpleusb.cpp:129:100: warning: implicit conversion from 'unsigned long long' to 'int' changes value from 7976667151972931595 to 887068683 [-Wconstant-conversion]
SuperpoweredUSBMIDI::send(deviceID, reinterpret_cast<unsigned char *>(0x80 - 0x48 - 0x00), 100100010011100000000011);
~~~~~~~~~~~~~~~~~~~ ^~~~~~~~~~~~~~~~~~~~~~~~
1 warning and 1 error generated.
ninja: build stopped: subcommand failed.
Maybe it's for the documentation, very newbie with jni or too complex to me for now to understand 100%.
Ok, so here's what send is saying:
send(int deviceID, unsigned char *data, int bytes);
Send to deviceId a pointer to a buffer called data that has a certain number of bytes.
So when you say:
SuperpoweredUSBMIDI::send(deviceID, reinterpret_cast(0x80 - 0x48 - 0x00), 100100010011100000000011);
What you are essentially saying is "subtract these 3 numbers: 0x80 - 0x48 - 0x00", then re-interpret that number as a pointer to a buffer somewhere in memory. That buffer in memory contains 100100010011100000000011 bytes of data that I want you to read.
To fix this, we would send the data like this:
unsigned char* send_buffer[32] = {0}; // zero out buffer to use as scratch
send_buffer[0] = 0x90;
send_buffer[1] = 0x48;
send_buffer[2] = 0x00;
SuperpoweredUSBMIDI::send(deviceID, send_buffer, 3);
i thought midi had a check sum value (byte) appended to the sequence - is that done in your code or in the library code?
the message should be an array of unsigned char and pass the address of the array (name)
well that's what id have done in C when I was programming midi.
I'm trying to make a c program which triggers CVE-2017-10661.
As far as I understand because might_cancel mechanism it isn't properly protected if you make parallel operations on the file descriptor you can cause a crash.
I believe these parallel operations are read, poll etc right?
Currently i have written this piece of code.
#include <sys/timerfd.h>
#include <sys/poll.h>
#include <sys/epoll.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <unistd.h>
int main(int ac, char *av[])
{
int timerfd;
int epollfd;
struct itimerspec timerValue;
uint64_t exp;
ssize_t s;
/* set timerfd */
timerfd = timerfd_create(CLOCK_MONOTONIC, 0);
if (timerfd < 0) {
printf("failed to create timer fd\n");
exit(1);
}
bzero(&timerValue, sizeof(timerValue));
timerValue.it_value.tv_sec = 1;
timerValue.it_value.tv_nsec = 0;
timerValue.it_interval.tv_sec = 1;
timerValue.it_interval.tv_nsec = 0;
/* start timer */
if (timerfd_settime(timerfd, 0, &timerValue, NULL) < 0) {
printf("could not start timer\n");
exit(1);
}
s = read( timerfd, &exp, sizeof(uint64_t));
exit(0);
}
As you can see i set up a timer and then i only do a reading operation. Is there any way t trigger the bug by doing mupltiple read or pollings?
The race condition is triggered by timerfd_settime() -> timerfd_setup_cancel() -> timerfd_setup_cancel(). So you should use multiple threads to do timerfd_settime with the flag as TFD_TIMER_ABSTIME|TFD_TIMER_CANCEL_ON_SET.
Here is the POC I found online.
I'm experiencing an infinite loop trying to trace simple hello world using ptrace() on Android ARM64 emulator that emulates AARCH64. I'm not sure why it is not stopping. I'm trying to trace a hello world program and get all executed instructions but it seems that this condition never returns false: while (WIFSTOPPED(wait_status))
int main(int argc, char** argv)
{
pid_t child_pid;
if(argc < 2)
{
fprintf(stderr, "Expected a program name as argument\n");
return -1;
}
child_pid = fork();
if (child_pid == 0)
run_target(argv[1]);
else if (child_pid > 0)
run_debugger(child_pid);
else
{
perror("fork");
return -1;
}
return 0;
}
void run_target(const char* programname)
{
printf("target started. will run '%s'\n", programname);
/* Allow tracing of this process */
if (ptrace(PTRACE_TRACEME, 0, 0, 0) < 0)
{
perror("ptrace");
return;
}
/* Replace this process's image with the given program */
execl(programname, programname, 0);
}
void run_debugger(pid_t child_pid)
{
int wait_status;
unsigned icounter = 0;
printf("debugger started\n");
/* Wait for child to stop on its first instruction */
wait(&wait_status);
while (WIFSTOPPED(wait_status))
{
icounter++;
struct user_pt_regs regs;
struct iovec io;
io.iov_base = ®s;
io.iov_len = sizeof(regs);
if (ptrace(PTRACE_GETREGSET, child_pid, (void*)NT_PRSTATUS, (void*)&io) == -1)
printf("BAD REGISTER REQUEST\n");
unsigned instr = ptrace(PTRACE_PEEKTEXT, child_pid, regs.pc, 0);
printf("icounter = %u. PCP = 0x%08x. instr = 0x%08x\n", icounter, regs.pc, instr);
/* Make the child execute another instruction */
if (ptrace(PTRACE_SINGLESTEP, child_pid, 0, 0) < 0)
{
perror("ptrace");
return;
}
/* Wait for child to stop on its next instruction */
wait(&wait_status);
}
printf("the child executed %u instructions\n", icounter);
}
I have some problems when using the dynamic loading API (<dlfcn.h>: dlopen(), dlclose(), etc) on Android.
I'm using NDK standalone toolchain (version 8) to compile the applications and libraries.
The Android version is 2.2.1 Froyo.
Here is the source code of the simple shared library.
#include <stdio.h>
int iii = 0;
int *ptr = NULL;
__attribute__((constructor))
static void init()
{
iii = 653;
}
__attribute__((destructor))
static void cleanup()
{
}
int aaa(int i)
{
printf("aaa %d\n", iii);
}
Here is the program source code which uses the mentioned library.
#include <dlfcn.h>
#include <stdlib.h>
#include <stdio.h>
int main()
{
void *handle;
typedef int (*func)(int);
func bbb;
printf("start...\n");
handle = dlopen("/data/testt/test.so", RTLD_LAZY);
if (!handle)
{
return 0;
}
bbb = (func)dlsym(handle, "aaa");
if (bbb == NULL)
{
return 0;
}
bbb(1);
dlclose(handle);
printf("exit...\n");
return 0;
}
With these sources everything is working fine, but when I try to use some STL functions or classes, the program crashes with a segmentation fault, when the main() function exits, for example when using this source code for the shared library.
#include <iostream>
using namespace std;
int iii = 0;
int *ptr = NULL;
__attribute__((constructor))
static void init()
{
iii = 653;
}
__attribute__((destructor))
static void cleanup()
{
}
int aaa(int i)
{
cout << iii << endl;
}
With this code, the program crashes with segmentation fault after or the during main() function exit.
I have tried couple of tests and found the following results.
Without using of STL everything is working fine.
When use STL and do not call dlclose() at the end, everything is working fine.
I tried to compile with various compilation flags like -fno-use-cxa-atexit or -fuse-cxa-atexit, the result is the same.
What is wrong in my code that uses the STL?
Looks like I found the reason of the bug. I have tried another example with the following source files:
Here is the source code of the simple class:
myclass.h
class MyClass
{
public:
MyClass();
~MyClass();
void Set();
void Show();
private:
int *pArray;
};
myclass.cpp
#include <stdio.h>
#include <stdlib.h>
#include "myclass.h"
MyClass::MyClass()
{
pArray = (int *)malloc(sizeof(int) * 5);
}
MyClass::~MyClass()
{
free(pArray);
pArray = NULL;
}
void MyClass::Set()
{
if (pArray != NULL)
{
pArray[0] = 0;
pArray[1] = 1;
pArray[2] = 2;
pArray[3] = 3;
pArray[4] = 4;
}
}
void MyClass::Show()
{
if (pArray != NULL)
{
for (int i = 0; i < 5; i++)
{
printf("pArray[%d] = %d\n", i, pArray[i]);
}
}
}
As you can see from the code I did not used any STL related stuff.
Here is the source files of the functions library exports.
func.h
#ifdef __cplusplus
extern "C" {
#endif
int SetBabe(int);
int ShowBabe(int);
#ifdef __cplusplus
}
#endif
func.cpp
#include <stdio.h>
#include "myclass.h"
#include "func.h"
MyClass cls;
__attribute__((constructor))
static void init()
{
}
__attribute__((destructor))
static void cleanup()
{
}
int SetBabe(int i)
{
cls.Set();
return i;
}
int ShowBabe(int i)
{
cls.Show();
return i;
}
And finally this is the source code of the programm that uses the library.
main.cpp
#include <dlfcn.h>
#include <stdlib.h>
#include <stdio.h>
#include "../simple_lib/func.h"
int main()
{
void *handle;
typedef int (*func)(int);
func bbb;
printf("start...\n");
handle = dlopen("/data/testt/test.so", RTLD_LAZY);
if (!handle)
{
printf("%s\n", dlerror());
return 0;
}
bbb = (func)dlsym(handle, "SetBabe");
if (bbb == NULL)
{
printf("%s\n", dlerror());
return 0;
}
bbb(1);
bbb = (func)dlsym(handle, "ShowBabe");
if (bbb == NULL)
{
printf("%s\n", dlerror());
return 0;
}
bbb(1);
dlclose(handle);
printf("exit...\n");
return 0;
}
Again as you can see the program using the library also does not using any STL related stuff, but after run of the program I got the same segmentation fault during main(...) function exit. So the issue is not connected to STL itself, and it is hidden in some other place. Then after some long research I found the bug.
Normally the destructors of static C++ variables are called immediately before main(...) function exit, if they are defined in main program, or if they are defined in some library and you are using it, then the destructors should be called immediately before dlclose(...).
On Android OS all destructors(defined in main program or in some library you are using) of static C++ variables are called during main(...) function exit. So what happens in our case? We have cls static C++ variable defined in library we are using. Then immediately before main(...) function exit we call dlclose(...) function, as a result library closed and cls becomes non valid. But the pointer of cls is stored somewhere and it's destructor should be called during main(...) function exit, and because at the time of call it is already invalid, we get segmentation fault. So the solution is to not call dlclose(...) and everything should be fine. Unfortunately with this solution we cannot use attribute((destructor)) for deinitializing of something we want to deinitialize, because it is called as a result of dlclose(...) call.
I have a general aversion to calling dlclose(). The problem is that you must ensure that nothing will try to execute code in the shared library after it has been unmapped, or you will get a segmentation fault.
The most common way to fail is to create an object whose destructor is defined in or calls code defined in the shared library. If the object still exists after dlclose(), your app will crash when the object is deleted.
If you look at logcat you should see a debuggerd stack trace. If you can decode that with the arm-eabi-addr2line tool you should be able to determine if it's in a destructor, and if so, for what class. Alternatively, take the crash address, strip off the high 12 bits, and use that as an offset into the library that was dlclose()d and try to figure out what code lives at that address.
I encountered the same headache on Linux. A work-around that fixes my segfault is to put these lines in the same file as main(), so that dlclose() is called after main returns:
static void* handle = 0;
void myDLClose(void) __attribute__ ((destructor));
void myDLClose(void)
{
dlclose(handle);
}
int main()
{
handle = dlopen(...);
/* ... real work ... */
return 0;
}
The root cause of dlclose-induced segfault may be that a particular implementation of dlclose() does not clean up the global variables inside the shared object.
You need to compile with -fpic as a compiler flag for the application that is using dlopen() and dlclose(). You should also try error handling via dlerror() and perhaps checking if the assignment of your function pointer is valid, even if it's not NULL the function pointer could be pointing to something invalid from the initialization, dlsym() is not guaranteed to return NULL on android if it cannot find a symbol. Refer to the android documentation opposed to the posix compliant stuff, not everything is posix compliant on android.
You should use extern "C" to declare you function aaa()