Segmentation fault when creating custom tcl channel driver - c++

I am trying to create custom tcl channel and use it to get the output of tcl Interpreter. I added the implementation of few function of Tcl_ChannelType but I am getting segfault.
#include <tcl.h>
#include <iostream>
int driverBlockModeProc(ClientData instanceData, int mode) {
std::cout << "driverBlockModeProc\n";
return 0;
}
int driverCloseProc(ClientData instanceData, Tcl_Interp *interp) {
std::cout << "driverCloseProc\n";
return 0;
}
int driverInputProc(ClientData instanceData, char* buf, int bufSize, int *errorCodePtr) {
std::cout << "driverInputProc\n";
return 0;
}
int driverOutputProc(ClientData instanceData, const char* buf, int toWrite, int *errorCodePtr) {
std::cout << "driverOutputProc\n";
return 0;
}
int main() {
Tcl_ChannelType *typePtr = new Tcl_ChannelType;
typePtr->blockModeProc = driverBlockModeProc;
typePtr->outputProc = driverOutputProc;
typePtr->closeProc = driverCloseProc;
typePtr->inputProc = driverInputProc;
typePtr->seekProc = NULL;
typePtr->setOptionProc = NULL;
typePtr->getOptionProc = NULL;
typePtr->watchProc = NULL;
typePtr->getHandleProc = NULL;
typePtr->close2Proc = NULL;
typePtr->blockModeProc = NULL;
typePtr->flushProc = NULL;
typePtr->handlerProc = NULL;
typePtr->wideSeekProc = NULL;
typePtr->threadActionProc = NULL;
ClientData data = new char[200];
Tcl_CreateChannel(typePtr, "im_chanel", data, TCL_WRITABLE | TCL_READABLE);
}
I cant debug the segfault because its source are not available. I think the segfault is because a function is called which is NULL. I only need to use the channel to get the output of interpreter. Which functions I needn't implement here and is it right direction to solve the problem.

You're advised to download the source to Tcl when working at this level. I'm not sure what version you're using, but all official distributions of the source going back a very long way are on the SourceForge file distribution system; pick the exact match for the version you've got.
Creating a custom channel driver is not easy. There's a significant amount of complexity involved, and it isn't especially well-documented what “methods” within the channel driver type are mandatory and what are optional. (They're not C++ methods in a class — Tcl is pure C code for reasons too long to go into here — but they function in a conceptually similar way.)
If we look at the documentation for Tcl_CreateChannel, we see (quite a long way down that page) a definition of the channel type structure. The channel type structure should be statically allocated (Tcl's implementation assumes very strongly that it never changes location) and the following fields must be set to something meaningful:
typeName — This is the name of the channel type, useful for debugging!
version — This is the version of the channel type; you should set it to the latest version supported by your target source level. (You're recommended to use at least TCL_CHANNEL_VERSION_2 or things get rather more complex.)
closeProc or close2Proc — Channels must be closeable, but you have two choices for ways to do it. Bidirectional channels ought to use the close2Proc, but aren't strictly required to.
inputProc — Only needed if you're reading; take care to handle this correctly.
outputProc — Only needed if you're writing; take care to handle this correctly.
watchProc — Called to tell the channel driver to install itself into the event system so as to receive suitable events (as instructed by the supplied bitmask). Channels that don't have backing OS handles use timer events, or simply never actually generate events (in which case they'll never become readable or writable from the perspective of fileevent).
Looking at your code, I see that you're missing a watchProc. I know it's hard to see (not many people write channel drivers, to be honest, so the documentation isn't very hard “tested”) but it's really necessary.

Related

Is There a Function Like "pthread_getcancelstate"?

The Linux Pthread Library includes 2 functions to set a threads' cancel state and cancel type:
int pthread_setcancelstate(int state, int *oldstate)
int pthread_setcanceltype(int type, int *oldtype)
How can I receive those states and types? Is there a function like pthread_getcancelstate or pthread_getcanceltype? I searched on the Internet and I didn't found solutions.
Since the functions pthread_setcancelstate() and pthread_setcanceltype() return the old state via the argument list, you can call the functions to set the 'safe' state/type (PTHREAD_CANCEL_DISABLE and PTHREAD_CANCEL_DEFERRED, I think), and if the old state/type was not the same, call the function a second time to reinstate the old state/type. There doesn't seem to be a 'no-op' value for the new state/type.
int pthread_getcancelstate(int *oldstate)
{
int dont_care;
int rc = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, oldstate);
if (rc == 0 && *oldstate != PTHREAD_CANCEL_DISABLE)
rc = pthread_setcancelstate(*oldstate, &dont_care);
return rc;
}
int pthread_getcanceltype(int *oldtype)
{
int dont_care;
int rc = pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, oldtype);
if (rc == 0 && *oldtype != PTHREAD_CANCEL_DEFERRED)
rc = pthread_setcanceltype(*oldtype, &dont_care);
return rc;
}
The other state is PTHREAD_CANCEL_ENABLE and the other type is PTHREAD_CANCEL_ASYNCHRONOUS.
The manual pages for these functions on macOS do say that it is permissible to pass a null pointer for the old state/type, so it would be possible to eliminate the dont_care variable on macOS. However, neither the POSIX specification nor the manual page on (RHEL 7.4) Linux say that a null pointer is permissible. The code above should work safely on both those platforms.
The code is also trespassing on the namespace reserved for use by the implementation — the implementation could choose to add either or both pthread_getcancelstate() or pthread_getcanceltype() (with the same or a different interface) and there'd be no option but to rename the functions shown above. Adding the _np (non-portable) suffix might not help either; the implementation could choose to use the name with the suffix.

Copy structure without pointers

I'm trying to create an interface between physical components (Arduinos) and flight simulator in order to control and display simulator events from self-built parts. I have started learning C++ in school, but have never been quite keen on it.
Yet the library I use to communicate with my flight simulator is written in C++ (it's called SimConnect) and so is the SDK of my payware airplane. Therefore I figured it's probably easier to get back into it than creating wrappers or such for another programming language.
Every time I receive new data from the simulator, I pass it into the function ProcessNGXData:
PMDG_NGX_Data* previousData;
bool alreadyProcessed = false;
void ProcessNGXData(PMDG_NGX_Data *data)
{
if (!alreadyProcessed || data->LTS_TaxiSw != previousData->LTS_TaxiSw) {
if (data->LTS_TaxiSw)
printf("Taxi Lights: [ON]\n");
else
printf("Taxi Lights: [OFF]\n");
}
if (!alreadyProcessed) {
alreadyProcessed = true;
}
previousData = data;
}
In other programming languages, this would probably work fine, hence I tried to implement it like this. However, C++ pointers are a slight bit more complicated to me.
The condition data->LTS_TaxiSw != previousData->LTS_TaxiSw never evaluates to true. From my understanding, that is because both data and previousData are pointers to exactly the same structure and thus can never be different.
With my little knowledge and not much understanding of those pointers, how would I do this? Is there a way to copy the structure, so they can differ?
Thanks in advance.
Declare previousData like this:
PMDG_NGX_Data previousData;
(without the asterisk). Now, when you want to 'save' the structure, do this:
previousData = *data;
(right hand side has an asterisk). Note that this assumes that PMDG_NGX_Data is copy-able and a fixed size. If it's an interface or an abstract class, then this won't be possible. Perhaps the API gives you a "Clone" or "Copy" method you can call.
If PMDG_NGX_Data is not too big to copy every ProcessNGXData you can try this:
PMDG_NGX_Data previousData;
bool alreadyProcessed = false;
void ProcessNGXData(PMDG_NGX_Data *data)
{
if (!alreadyProcessed || data->LTS_TaxiSw != previousData.LTS_TaxiSw) {
if (data->LTS_TaxiSw)
printf("Taxi Lights: [ON]\n");
else
printf("Taxi Lights: [OFF]\n");
}
if (!alreadyProcessed) {
alreadyProcessed = true;
}
previousData = *data;
}
If it is too big, you can create a struct that will hold only the fields you need to compare and will be initialized by PMDG_NGX_Data and initialize that struct every ProcessNGXData.

Returning Image Pointer to Erlang

I am trying to use openCV with the Erlang NIF.
So I want to do a basic thing and that's just to read a picture and send back the pointer to erlang.
and be able to again send back the pointer received to C and just show the pic
so the niftest.cpp look like this:
/* niftest.cpp */
#include "erl_nif.h"
#include <opencv/highgui.h>
#include <opencv/cv.h>
using namespace cv;
using namespace std;
static ErlNifResourceType* frame_res = NULL;
typedef struct _frame_t {
IplImage* _frame;
} frame_t;
//------------------------------------------------------------------------------
// NIF callbacks
//------------------------------------------------------------------------------
static void frame_cleanup(ErlNifEnv* env, void* arg) {
enif_free(arg);
}
static int load(ErlNifEnv* env, void** priv, ERL_NIF_TERM load_info)
{
ErlNifResourceFlags flags = (ErlNifResourceFlags) (ERL_NIF_RT_CREATE | ERL_NIF_RT_TAKEOVER);
frame_res = enif_open_resource_type(env, "niftest", "ocv_frame",
&frame_cleanup,
flags, 0);
return 0;
}
static ERL_NIF_TERM get_pic(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
IplImage* src = cvLoadImage("/home/khashayar/Downloads/pic.png");
cout << src->width << endl;
IplImage* gray = cvCreateImage(cvGetSize(src), IPL_DEPTH_8U, 1);
cvCvtColor(src, gray, CV_RGB2GRAY);
frame_t* frame = (frame_t*)enif_alloc_resource(frame_res, sizeof(frame_t));
frame->_frame = gray ;
ERL_NIF_TERM term = enif_make_resource(env, frame);
enif_release_resource(frame);
return enif_make_tuple2(env, enif_make_atom(env, "ok"), term);
}
static ERL_NIF_TERM show_pic(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]){
frame_t* frame;
if (!enif_get_resource(env, argv[0], frame_res, (void**) &frame)) {
return enif_make_badarg(env);
}
cvShowImage("YOOHOO", frame->_frame);
cvWaitKey(30);
return enif_make_atom(env, "ok");
}
static ErlNifFunc nif_funcs[] =
{
{"show_pic", 1, show_pic},
{"get_pic", 0, get_pic}
};
ERL_NIF_INIT(niftest,nif_funcs,load,NULL,NULL,NULL)
and my niftest.erl looks like this :
-module(niftest).
-compile(export_all).
init() ->
erlang:load_nif("./niftest", 0).
get_pic() ->
"NIF library not loaded".
show_pic(F) ->
"NIF library not loaded".
So now the problem is when I call the get_pic what I get in return is {ok, <<>>} and the Pointer is not valid at all.
when I cout the frame before making the enif_make_resource it has a value and I can see it but it returns empty to me!
What I am doing wrong?
I have read all the documentation and I really can't figure this out.
NOTE: you can compile the code with this command:
g++ -fPIC -shared -o niftest.so niftest.cpp -lopencv_core -lopencv_imgproc -lopencv_highgui -I /usr/lib64/erlang/usr/include/
and then run the erlang shell and call the init and get_pic function
NIF is the wrong solution to port OpenCV's High-level GUI.
Yet, to answer your question: the apparently empty binary in the {ok, <<>>} tuple you get is opaque from Erlang. This is a resource object as documented in erl_nif manual page.
Resource objects are garbage collector friendly. If no process refers to a given resource, the cleanup function will be called. They are typically the proper structure for embedding C or C++ pointers in your NIF.
IplImage* pointer is a perfect candidate for a resource object. You probably do not need the frame_t type as you can simply cast the pointer to IplImage**. The cleanup function should release memory and, in your example, call cvReleaseImage.
Since the pointer is opaque, you need to port accessor functions to provide data to Erlang. This really depends on the kind of data you would like to extract from the image. For example, you could port the cvEncodeImage function and convert the data from CvMat* to an erlang binary using enif_make_binary.
Also, as a side note, instead of returning the list "NIF library not loaded", you should call erlang:nif_error/1,2 in stub functions.
The proper approach to port an API such as OpenCV's High GUI would be an external driver (or a C-node).
There are several reasons, including:
NIF calls should return quickly (calling cvWaitKey is a poor candidate for a NIF, as well as computations taking too long), as they would otherwise confuse the scheduler ;
with a NIF or a linked-in driver, memory management directly impacts Erlang's virtual machine, and any crash will take the whole Erlang node down.
An external driver is a process that gets data from stdin (typically) and replies on stdout. This is very simple to design in C or C++. You could either port OpenCV's API or more complex functions depending on your needs. In this case, pointers such as IplImage* could be transferred as an opaque series of 4 or 8 bytes, or as a reference number provided you maintain a list of all IplImage* pointers Erlang has allocated. Unlike NIFs, however, there is no resource object and you will have to design your Erlang-side code to ensure memory is properly released.
You will find more information and sample code in the Interoperability Tutorial User's Guide.
See also this question: OpenCV on Erlang

Saving image with libpng - const object

I have a class which manages a grayscale image. I want to save it with libpng. To do that I want to use a const member function like this:
void GrayscaleImage::SavePNG(std::string filename) const
{
// ...
png_bytep* row_pointers = new png_bytep[m_height];
for (int i = 0; i < height_; i++) {
row_pointers[i] = const_cast<png_bytep>(m_data.data()) + i * m_width * sizeof(uint8_t);
}
png_set_rows(png_ptr, info_ptr, row_pointers);
// ...
}
The problem is that the third argument of png_set_rows is non-const, so I have to use const_cast at some point, if I want the member function GrayscaleImage::SavePNG to be const. I'm wondering, is it safe to do this?
libpng provides an API to cause it to free the row_pointers and the stuff they point to; png_data_freer. That's the default on read (where png_set_rows can currently be called but the call gets ignored).
What you did is safe, so long as you don't call png_data_freer. None of the write APIs modify the input data.
The problem exists in png_write_image, the API png_write_png calls, as well, and it exists in png_write_rows. It used to exist in png_write_row which is the lowest level API but that was fixed in libpng 1.5; it's a quiet API change there because it doesn't change the type compatibility of the argument. Changing it any higher would cause existing applications to fail to compile because of type errors.
You're not likely to see changes soon; changing the API in ways that require applications to rewrite existing code is unlikely to happen until libpng 2.0 in my opinion.
It's not safe. Without the third parameter of png_set_rows() declared const, you have no guarantee that it will not modify the input data.
You will always have to deal with libraries that don't declare parameters const even if they could. That is why const_cast exists. You should use it with extreme caution. But judging from the description, it's unlikely that png_set_rows() will modify your data.
EDIT: here is the source code. You can see it doesn't modify row_pointers. (But it definitely modifies the other two arguments!)
void PNGAPI
png_set_rows(png_structp png_ptr, png_infop info_ptr, png_bytepp row_pointers)
{
png_debug1(1, "in %s storage function", "rows");
if (png_ptr == NULL || info_ptr == NULL)
return;
if (info_ptr->row_pointers && (info_ptr->row_pointers != row_pointers))
png_free_data(png_ptr, info_ptr, PNG_FREE_ROWS, 0);
info_ptr->row_pointers = row_pointers;
if (row_pointers)
info_ptr->valid |= PNG_INFO_IDAT;
}
The const in your function definition just says that your instance shouldn't change. Saving to a file shouldn't change your instance so it's alright.
Of course the third parameter of png_set_rows isn't const because it gets set.
It doesn't matter if you create, destroy or change things in a const function as long as they don't belong to your class. Your code doesn't change any instance of GrayscaleImage.

COM interop: how to use ICustomMarshaler to call 3rd party component

I want to call a method in a COM component from C# using COM interop. This is the methods signature:
long GetPrecursorInfoFromScanNum(long nScanNumber,
LPVARIANT pvarPrecursorInfos,
LPLONG pnArraySize)
and this is sample code (which I checked is really working) to call it in C++:
struct PrecursorInfo
{
double dIsolationMass;
double dMonoIsoMass;
long nChargeState;
long nScanNumber;
};
void CTestOCXDlg::OnOpenParentScansOcx()
{
VARIANT vPrecursorInfos;
VariantInit(&vPrecursorInfos);
long nPrecursorInfos = 0;
m_Rawfile.GetPrecursorInfoFromScanNum(m_nScanNumber,
&vPrecursorInfos,
&nPrecursorInfos);
// Access the safearray buffer
BYTE* pData;
SafeArrayAccessData(vPrecursorInfos.parray, (void**)&pData);
for (int i=0; i < nPrecursorInfos; ++i)
{
// Copy the scan information from the safearray buffer
PrecursorInfo info;
memcpy(&info,
pData + i * sizeof(MS_PrecursorInfo),
sizeof(PrecursorInfo));
}
SafeArrayUnaccessData(vPrecursorInfos.parray);
}
And here's the corresponding C# signature after importing the typelib of the COM component:
void GetPrecursorInfoFromScanNum(int nScanNumber, ref object pvarPrecursorInfos, ref int pnArraySize);
If I'm not mistaken, I need to pass in null for pvarPrecursorInfos to make COM interop marshal it as the expected VT_EMPTY variant. When I'm doing it, I get a SafeArrayTypeMismatchException - not really surprising, looking at how the result is expected to be handled in the sample. So I was trying to use a custom marshaler. Since a cannot alter the component itself, I tried to introduce it this way:
[Guid("06F53853-E43C-4F30-9E5F-D1B3668F0C3C")]
[TypeLibType(4160)]
[ComImport]
public interface IInterfaceNew : IInterfaceOrig
{
[DispId(130)]
int GetPrecursorInfoFromScanNum(int nScanNumber, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(MyMarshaler))] ref object pvarPrecursorInfos, ref int pnArraySize);
}
The TypeLibType and DispID attribute are the same as in the original version. This works as far as that the MyMarshaller.GetInstance() method is called, but I do not get a callback in MyMarshaller.NativeToManaged. Instead, an access violation is reported. So is this a reliable approach? If yes - how can I make it work? If no: are there any alternatives?
(Just a footnote: in theory I could try to use managed C++ to call the component natively. However, there are lots of other methods in it that work fine with COM interop, so I would very much like to stick with C# if there is any way.)
Since someone asked for it, here's my solution in Managed C++.
array<PrecursorInfo^>^ MSFileReaderExt::GetPrecursorInfo(int scanNumber)
{
VARIANT vPrecursorInfos;
VariantInit(&vPrecursorInfos);
long nPrecursorInfos = -1;
//call the COM component
long rc = pRawFile->GetPrecursorInfoFromScanNum(scanNumber, &vPrecursorInfos, &nPrecursorInfos);
//read the result
//vPrecursorInfos.parray points to a byte sequence
//that can be seen as array of MS_PrecursorInfo instances
//(MS_PrecursorInfo is a struct defined within the COM component)
MS_PrecursorInfo* pPrecursors;
SafeArrayAccessData(vPrecursorInfos.parray, (void**)&pPrecursors);
//now transform into a .NET object
array<PrecursorInfo^>^ infos = gcnew array<PrecursorInfo^>(nPrecursorInfos);
MS_PrecursorInfo currentPrecursor;
for (int i=0; i < nPrecursorInfos; ++i)
{
currentPrecursor = pPrecursors[i];
infos[i] = safe_cast<PrecursorInfo^>(Marshal::PtrToStructure(IntPtr(&currentPrecursor), PrecursorInfo::typeid));
}
SafeArrayUnaccessData(vPrecursorInfos.parray);
return infos;
}
I look at the github code mzLib, which I believe is related to this topic. The code looks good, where it calls
pin_ptr<const wchar_t> wch = PtrToStringChars(path);
I think it may cause some problem, better use
pin_ptr<const wchar_t> pathChar = static_cast<wchar_t*>(System::Runtime::InteropServices::Marshal::StringToHGlobalUni(path).ToPointer());
The code then seems to be worked just fine when compiles. However, it might run in problem when imported as dll. I worked on that by adding a constructor,such as
public ref class ThermoDLLClass
{
public:
ThermoDLLClass();
PrecursorInfo GetPrecursorInfo(int scanNum, String^ path);
};
Then, it seems to get precursorInfo and parameters appropriately.