I have a function:
auto func = v8::FunctionTemplate::New(context,
[](const v8::FunctionCallbackInfo<v8::Value>& args) {
auto isolate = args.GetIsolate();
if (args.IsConstructCall()) { ... }
...
}).ToLocalChecked();
and I exposed this function as following.
global->Set(isolate, "func", func);
I used the function both as a normal function and a constructor,
func();
new func();
and V8 crushed when IsConstructCall is called. I found that IsConstructCall uses QuickIsUndefined to check whether NewTarget is undefined or not. The problem occurs inside ReadRawField, which is called by GetInstanceType, and QuickIsUndefined calls GetInstanceType.
Since T=unsigned short, I added reinterpret_cast<unsigned short*>(addr) to the watch and the result was like this, and it was different from what the exception says.
What makes me more confusing is that sometimes my program runs well without crushing. Instead of IsContructCall, I used v8::Undefined and Value::Equals, and it runs well.
!args.NewTarget()->Equals(isolate->GetCurrentContext(), v8::Undefined(isolate)).ToChecked()
It seems like QuickIsUndefined has some problem, but I can't identify the problem. What may help in this situation? I compiled V8 with MSVC in monolith mode.
I had the same issue:
try to compile your code with -DV8_COMPRESS_POINTERS. V8 has compressed pointers as default now.
v8-internal.h "ReadRawField" can help you to understand the background
Related
I'm working on a project in C++, but at some point in the application it fails and generates a core dump. The application uses a couple of classes, which for the purposes here I'm concentrating on one of the classes, which I'm calling A, and is instantiated as object a. This has a large number of member functions, of which at the moment only a few are being used, but one of these generates a log to produce diagnostics to be used for debugging. I want to use this to find out why the application is failing.
The project is to put together code that invokes the various member functions, and although I have access to the source code and some limited documentation, none of the code can be changed, with all changes being in the code that makes use of the classes and invokes the member functions. The member function in question is:
void enable_log (log_callback callback, void * user_data = nullptr)
where the 1st argument callback contains the message and 2nd argument is optional. For now it can be set to nullptr, so would be invoked as:
a.enable_log(callback, nullptr);
From this documentation it's not at all clear what exactly callback is. However, in looking at the source code this is:
using log_callback = void (*)(const std::string& message, void* user_data);
in a header file, where log_callback is an alias for const std::string& if I understand this correctly.
I already have dummy classes on a platform using Visual Studio 2019 with some test member functions to simulate invoking the member functions on a remote Linux server, but I'm unable to find a way of making use of the member function above. I added the test member function to the dummy class as follows:
void enable_log(const std::string& callback, void* user_data = nullptr) {
callback = "ABCD";
}
which is supposed to generate a test string which is returned, such that in the real application this string will have diagnostic information that will be written to a file. However, the "=" is an error.
The idea is that in the main function an empty string will be declared, then enable_log() should populate this string, which can be printed out.
I've spent some time looking at various resources, including Stackoverflow, but I cannot find a way of returning a string with the information that can be printed out. I need a simple way to simulate this, and as I said above, I must not change the source code of the real member function, so the simulated member function has to produce a string in the same way. How is this done? Some advice would be appreciated.
Callback, in simple words, is some function that will be called later at some point. Example:
void callback_fn(int a);
using callback_t = (void)(*)(int a);
void some_func(callback_t);
You can use some_func() like so:
some_func(callback_fn);
Full example here: https://godbolt.org/z/ET3GhfYrv
For your usecase the parameters of the callback are slightly different. Here's how to read the syntax:
using log_callback = // this just creates an alias for whatever is on the right handside
void // the return type of the "callable" should be void
(*) // this tells us that it is a function pointer
(const std::string& message, void* user_data) // These are the arguments the callable takes. It is a "std::string" and a "void *"
To use this, just create a free function with the same signature:
void callable(const std::string &msg, void *userData = nullptr)
{
// msg is the data sent by the function. use it in whatever way
// you want.
std::cout << msg << '\n';
}
// Pass it to the enable_log
enable_log(callable);
I'm using /NODEFAULTLIB to disable CRT(C Runtime), however my constructor is not called, which ends up causing an error in std::map (Access violation) because it is not initialized properly, since std::map constructor it's not called.
Code compiled with LLVM 8.0.0, compiled in mode debug x86
class c_test
{
public:
c_test( int a ) // Constructor not called
{
printf( "Test: %i\n", a ); // Doesn't appear and breakpoint is not reached
}
void add( const std::string& key, const std::string& val )
{
_data[ key ] = val;
}
private:
std::map< std::string, std::string > _data;
};
c_test test{ 1337 };
int main()
{
test.add( "qwrqrqr", "23142421" );
test.add( "awrqw", "12asa1faf" );
return 1;
}
I've implemented my own functions new(HeapAlloc), delete(HeapFree), printf, memcpy, memmove, etc, and all are working perfectly, I have no idea why this happening.
Disabling the CRT is madness.
This performs crucial functions, such as static initialisation. Lack of static initialisation is why your map is in a crippled state. I would also wholly expect various parts of the standard library to just stop working; you're really creating a massive problem for yourself.
Don't reinvent little pieces of critical machinery — turn the CRT back on and use the code the experts wrote. There is really nothing of relative value to gain by turning it off.
I discovered the problem and solved, one guy from another forum said that I needed manually call constructors that are stored in pointers in .CRT section, I just did it and it worked perfectly
I just called _GLOBAL__sub_I_main_cpp function that calls my constructor and solved all my problems, thanks for the answers.
I mean a scenario like this: There is some class (I call it victim) with a private data member and another class (named attacker) with some method, which, of course, normally does not have access to private members of other classes and does not even hold a reference to an instance of victim:
extern "C" {
#include <pigpiod_if2.h>
}
class victim {
private:
static bool is_ready;
static bool is_on;
public:
static void init ()
{
is_ready = true;
is_on = true;
}
/* Some other public methods go here. */
}
class attacker {
private:
static int last_read_pin;
public:
static void run ()
{
while (true) {
/* Some sensible code goes here. */
last_read_pin = -1;
time_sleep (0.01); // Using nanosleep () does not change behavior.
}
}
}
This is just a code snippet to illustrate the following question: Is it possible, not just in theory, but also practically, that attacker::run () can modify the values of the two private static vars of victim unintentionally, without addressing any public member of victim, maybe due to undefined behavior or even a compiler bug? Thank you.
UPDATE: After a hint from another user, I did rebuild the complete app using make clean and make. Also, I added the endless loop into my example. The change in is_ready occurs during the sixth run of the loop. Changing the sleep interval does not change behavior, though.
UPDATE #2: I ran my code through gdb with a watch on the is_ready variable, and I got an alert when last_read_pin was set to –1:
Hardware watchpoint 1: is_ready
Old value = true
New value = false
attacker::Run ()
last_read_pin = -1;
UPDATE #3: Moving last_read_pin into the Run () method itself, thereby making it an internal variable, does not help either.
UPDATE #4: After simply commenting out the line of code, which makes so much trouble, the issue still persisten, apparently being caused by one line above, which reads like this:
keypad::last_levels [h] [k] = 0;
I had to comment out this line, too, to get rid of the problem with is_ready being changed.
Could the use of pigpiod cause this issue? I an earlier version, I was using pigpio directly and did not encounter this problem.
Compiled with gcc 4.9.2.
After floating around the code line in question, I found out that the blunder was lying in the line before, which reads as follows:
last_levels [h] [l] = 0;
Unfortunately, h can be < 0. In this case, some kinda exception (array index out of bounds) should be thrown, but unfortunately, it isn't (Does anybody know why?). The gdb gave me the wrong information of the overwrite of is_ready to happen in the following line (Is this maybe a bug?), and I believed this without any criticism. As if this wasn't enough, this error made no problems until I changed my code in a completely different place!
This blunder has cost me quite much time, but now, at last, I know what its cause was, and I corrected it successfully. Thank you anyway for your hints and comments!
I have several configuration flags that I am implementing as structs. I create an object. I call a method of the object with a flag, which eventually triggers a comparison between two flags. However, by this time, one of the flags has been overwritten somehow.
To clarify, here's a VERY simplified version of the code that should illustrate what I'm seeing:
class flag_type { unsigned int flag; /*more stuff*/ };
flag_type FLAG1
flag_type FLAG2
class MyObject {
public:
void method1(const flag_type& flag_arg) {
//conditionals, and then:
const flag_type flag_args[2] = {flag_arg,flag_arg};
method2(flag_args);
}
void method2(const flag_type flag_args[2]) {
//conditionals, and then:
method3(flag_args[0]);
}
void method3(const flag_type& flag_arg) { //Actually in a superclass
//stuff
if (flag_arg==FLAG1) { /*stuff*/ }
//stuff
}
};
int main(int argc, const char* argv[]) {
//In some functions called by main:
MyObject* obj = new MyObject();
//Later in some other functions:
obj->method1(FLAG1);
}
With a debugger and print statements, I can confirm that both FLAG1 and flag_arg/flag_args are fine in both "method1" and "method2". However, when I get to method3, "FLAG1.flag" has been corrupted, so the comparison fails.
Now, although I'm usually stellar about not doing it, and it passes MSVC's static code analysis on strictest settings, this to me looks like the behavior of a buffer overrun.
I haven't found any such error by looking, but of course one usually doesn't. My question isA: Am I screwing up somewhere else? I realize I'm not sharing any real code, but am I missing something already? This scheme worked before before I rewrote a large portion of the code.
B: Is there an easier way than picking through the code more carefully until I find it? The code is cross-platform, so I'm already setting it up to check with Valgrind on an Ubuntu box.
Thanks to those who tried to help. Though, it should be noted that the code was for clarification purposes only; I typed it from scratch to show generally was was happening; not to compile. In retrospect, I realize it wasn't fair to ask people to solve it on so little information--though my actual question "Is there an easier way than picking through the code more carefully" didn't really concern actually solving the problem--just how to approach it.
As to this question, on Ubuntu Linux, I got "stack smashing" which told me more or less where the problem occurred. Interestingly, the traceback for stack smashing was the most helpful. Long story short, it was an embarrassingly basic error; strcpy was overflowing (in the operators for ~, | and &, the flags have a debug string set this way). At least it wasn't me who wrote that code. Always use strncpy, people :P
Question is in bold below :
This works fine:
void process_batch(
string_vector & v
)
{
training_entry te;
entry_vector sv;
assert(sv.size() == 0);
...
}
However, this causes the assert to fail :
void process_batch(
string_vector & v
)
{
entry_vector sv;
training_entry te;
assert(sv.size() == 0);
...
}
Now I know this issue isn't shrink wrapped, so I'll restrict my question to this: what conditions could cause such a problem ? Specifically: variable initialization getting damaged dependant on appearance order in the stack frame. There are no malloc's or free's in my code, and no unsafe functions like strcpy, memcpy etc... it's modern c++. Compilers used: gcc and clang.
For brevity here are the type's
struct line_string
{
boost::uint32_t line_no;
std::string line;
};
typedef std::vector<boost::uint32_t> line_vector;
typedef std::vector<line_vector> entry_vector;
typedef std::vector<line_string> string_vector;
struct training_body
{
boost::uint32_t url_id;
bool relevant;
};
struct training_entry
{
boost::uint32_t session_id;
boost::uint32_t region_id;
std::vector< training_body> urls;
};
p.s., I am in no way saying that there is a issue in the compiler, it's probably my code. But since I am templatizing some code I wrote a long time ago, the issue has me completely stumped, I don't know where to look to find the problem.
edit
followed nim's suggestion and went through the following loop
shrink wrap the code to what I have shown here, compile and test, no problem.
#if 0 #endif to shrink wrap the main program.
remove headers till it compiles in shrink wrapped form.
remove library links till compiles in shrink wrapped form.
Solution: removing link to protocol buffers gets rid of the problem
The C++ standard guarantees that the following assertion will succeed:
std::vector<anything> Default;
//in your case anything is line_vector and Default is sv
assert(Default.size() == 0);
So, either you're not telling the whole story or you have a broken STL implementation.
OR: You have undefined behavior in your code. The C++ standard gives no guarantees about the behavior of a program which has a construct leading to UB, even prior to reaching that construct.
The usual case for this when one of the created objects writes beyond
its end in the constructor. And the most frequent reason this happens
in code I've seen is that object files have been compiled with different
versions of the header; e.g. at some point in time, you added (or
removed) a data member of one of the classes, and didn't recompile all
of the files which use it.
What might cause the sort of problem you see is a user-defined type with a misbehaving constructor;
class BrokenType {
public:
int i;
BrokenType() { this[1].i = 9999; } // Bug!
};
void process_batch(
string_vector & v
)
{
training_entry te;
BrokenType b; // bug in BrokenType shows up as assert fail in std::vector
entry_vector sv;
assert(sv.size() < 100);
...
}
Do you have the right version of the Boost libaries suited for your platform? (64 bit/32 bit)? I'm asking since the entry_vector object seems to be have a couple of member variables of type boost::uint32_t. I'm not sure what could be the behaviour if your executable is built for one platform and the boost library loaded is of another platform.