For a small chat server thingie I'm making, I decided to use D; finding myself
with a very neat example from listener.d to get a kick start I decided to
pretty much take the example over! However, I'm stuck on a bug I can't truly
wrap my finger around. Most likely it's my own fault and I'm doing something
wrong, but considering I took the code pretty much from the example I am more
inclined to believe the example is broken.
I'll explain what happens:
List item
I start up my server (nothing wrong, it's running as it should and listening)
I telnet to it. My server accepts the connection.
I use telnet to send some information. Server handles the information
properly, again, no issue.
I quit telnet by using ^] and then writing quit. Breaking the connection
rather ungracefully.
The server properly recognises this isn't a clean disconnect and executes
the code to remove the socket.
I then get a range violation.
This is the main process and it's loop:
https://github.com/JGBrands/BlaatServer/blob/master/source/bserver.d
This is the server class, the code where it deletes the socket is at the
complete bottom in the function void destroySocket(int index);
https://github.com/JGBrands/BlaatServer/blob/master/source/server.d
Actually let me copy paste that. :-)
void destroySocket(int index) {
this.reads[index].close(); /* release resources. */
/* Remove the socket now. We don't want this around! It'll crash us! */
if (index != this.reads.length -1)
this.reads[index] = this.reads[this.reads.length -1];
this.reads = this.reads[0 .. this.reads.length -1];
writeln("Total connections: " ~ to!string(this.reads.length));
}
The code is primarily taken over from the listener.d example like I said, the
error I get is this:
core.exception.RangeError#server(61): Range violation
----------------
----------------
I'm lead to believe the function is deleting something it shouldn't, for those
interested, this is line 61 in server.d:
if (this.sset.isSet(this.reads[i])) {
Hopefully you guys can help me make more sense about this, am I missing something really obvious here?
As ratchet points out:
if (index != this.reads.length -1)
This does not verify that index is within range. It only validates that index is not the last element. This is fine as long as index has already been verified to be within range.
void destroySocket(int index)
in {
assert(index > -1);
assert(index < this.reads.length);
} body {
{
Related
I'm using Chrome's performance tab to study the performance of a page, and I occasionally get a warning like:
DevTools: CPU profile parser is fixing 4 missing samples.
Does anyone know what this means? Googling for this warning has returned no results so far...
As coming across with and having this situation, possible helpful things to consider are as below.
As Chrome 58 is released in 2017, some changes are done related to the analyzing performance. For example:
Timeline panel is renamed as Performance panel.
Profiles panel is renamed as Memory panel.
Record Javascript CPU Profile menu is moved into Dev Tools → Three dots at right → More tools → Javascript Profiler. (Old version of Javascript Profiler)
In addition of these, the warning message that is seen (DevTools: CPU profile parser is fixing N missing samples.) is being written to the console window when there is single (program) sample between two call stacks sharing the same bottom node. Also, the samples count should be greater than or equal to 3 according to the source code.
Comments written above _fixMissingSamples method in the CPUProfileDataModel.js file explains this situtation as below;
// Sometimes sampler is not able to parse the JS stack and returns
// a (program) sample instead. The issue leads to call frames belong
// to the same function invocation being split apart.
// Here's a workaround for that. When there's a single (program) sample
// between two call stacks sharing the same bottom node, it is replaced
// with the preceeding sample.
In the light of these information, we can trace the code and examine the behavior.
CPUProfileDataModel.js
let prevNodeId = samples[0];
let nodeId = samples[1];
let count = 0;
for (let sampleIndex = 1; sampleIndex < samplesCount - 1; sampleIndex++) {
const nextNodeId = samples[sampleIndex + 1];
if (nodeId === programNodeId && !isSystemNode(prevNodeId) && !isSystemNode(nextNodeId) &&
bottomNode(idToNode.get(prevNodeId)) === bottomNode(idToNode.get(nextNodeId)) {
++count;
samples[sampleIndex] = prevNodeId;
}
prevNodeId = nodeId;
nodeId = nextNodeId;
}
if (count) {
Common.console.warn(ls`DevTools: CPU profile parser is fixing ${count} missing samples.`);
}
It seems that, it simply compares previous and next node related to current node as if they has the same bottom node (actually comparing parent nodes). Also previous and next node shouldn't be a system (program/gc/idle function) node and current node should be the 'program' node. If it is the case, then the current node in samples array is set to previous node.
idle: Waiting to do process
program: Native code execution
garbage collector: Accounts for Garbage Collection
Also, disabling Javascript samples from Performance → Capture Settings result fewer details & call stacks because of omitting all the call stacks. The warning message shouldn't appear in this case.
But, since this warning is about the sampler that says cannot parse the JS stack and call frames being split apart, it doesn't seem very important thing to consider.
Resources:
https://github.com/ChromeDevTools/devtools-frontend/tree/master/front_end/sdk
https://github.com/ChromeDevTools/devtools-frontend/blob/master/front_end/sdk/CPUProfileDataModel.js
https://chromium.googlesource.com/chromium/blink/+/master/Source/devtools/front_end/sdk/
https://developers.google.com/web/tools/chrome-devtools/evaluate-performance
https://developers.google.com/web/updates/2016/12/devtools-javascript-cpu-profile-migration
The Reference Source page for stringbuilder.cs has this comment in the ToString method:
if (chunk.m_ChunkLength > 0)
{
// Copy these into local variables so that they
// are stable even in the presence of ----s (hackers might do this)
char[] sourceArray = chunk.m_ChunkChars;
int chunkOffset = chunk.m_ChunkOffset;
int chunkLength = chunk.m_ChunkLength;
What does this mean? Is ----s something a malicious user might insert into a string to be formatted?
The source code for the published Reference Source is pushed through a filter that removes objectionable content from the source. Verboten words are one, Microsoft programmers use profanity in their comments. So are the names of devs, Microsoft wants to hide their identity. Such a word or name is substituted by dashes.
In this case you can tell what used to be there from the CoreCLR, the open-sourced version of the .NET Framework. It is a verboten word:
// Copy these into local variables so that they are stable even in the presence of race conditions
Which was hand-edited from the original that you looked at before being submitted to Github, Microsoft also doesn't want to accuse their customers of being hackers, it originally said races, thus turning into ----s :)
In the CoreCLR repository you have a fuller quote:
Copy these into local variables so that they are stable even in the presence of race conditions
Github
Basically: it's a threading consideration.
In addition to the great answer by #Jeroen, this is more than just a threading consideration. It's to prevent someone from intentionally creating a race condition and causing a buffer overflow in that manner. Later in the code, the length of that local variable is checked. If the code were to check the length of the accessible variable instead, it could have changed on a different thread between the time length was checked and wstrcpy was called:
// Check that we will not overrun our boundaries.
if ((uint)(chunkLength + chunkOffset) <= ret.Length && (uint)chunkLength <= (uint)sourceArray.Length)
{
///
/// imagine that another thread has changed the chunk.m_ChunkChars array here!
/// we're now in big trouble, our attempt to prevent a buffer overflow has been thawrted!
/// oh wait, we're ok, because we're using a local variable that the other thread can't access anyway.
fixed (char* sourcePtr = sourceArray)
string.wstrcpy(destinationPtr + chunkOffset, sourcePtr, chunkLength);
}
else
{
throw new ArgumentOutOfRangeException("chunkLength", Environment.GetResourceString("ArgumentOutOfRange_Index"));
}
}
chunk = chunk.m_ChunkPrevious;
} while (chunk != null);
Really interesting question though.
Don't think that this is the case - the code in question copies to local variables to prevent bad things happening if the string builder instance is mutated on another thread.
I think the ---- may relate to a four letter swear word...
I have just started a new version of my Crysis Wars Server Side Modification called InfinityX. For better management, I have put the functions inside tables as it looks neater and I can group functions together (like Core.PlayerHandle:GetIp(player)), but I have ran into a problem.
The problem is that the specified method to get the players' name, player:GetName() is being seen as an invalid method, when the method actually is completely valid.
I would like to know if using the below structure is causing a problem and if so, how to fix it. This is the first time I've used this structure for functions, but it is already proving easier than the old method I was using.
The Code:
Event =
{
PlayerConnect = function(player)
Msg.All:CenteredConsole("$4Event$8 (Connect)$9: $3"..player:GetName().." on channel "..player.actor:GetChannel());
System.LogAlways(Default.Tag.."Incoming Connect on Channel "..player.actor:GetChannel());
Event:Log("Connect", player);
end;
};
The below code works when I bypass the function and put the code directly where it's needed:
Msg.All:CenteredConsole("$4Event$8 (Connect)$9: $3"..player:GetName().." on channel "..player.actor:GetChannel());
System.LogAlways(Default.Tag.."Incoming Connect on Channel "..player.actor:GetChannel());
The Error:
[Warning] [Lua Error] infinityx/main/core.events.lua:23: attempt to call method 'GetName' (a nil value)
PlayerConnect, (infinityx/main/core.events.lua: 23)
ConnectScript, (infinityx/main/core.main.lua: 52)
OnClientEnteredGame, (scripts/gamerules/instantaction.lua: 511)
(null) (scripts/gamerules/teaminstantaction.lua: 520)
Any clarification would be appreciated.
Thanks :)
Well, as PlayerConnect is inside the table Event, and you are calling with a ":", add self as first arg in the function, like:
PlayerConnect = function(self, player)
Clearly, player in the first block of code is not the same as player in the second block of code. The problem must be that the caller of Event.PlayerConnect is not passing the same value.
To test that your Event.PlayerConnect function works, try this in the same place as your second block of code:
Event.PlayerConnect(player)
That should work as you expect.
So, the problem comes down to how Event.PlayerConnect is called without the second block of code. I'm not familiar with that game engine so I don't know how it is done. Perhaps reviewing the documentation and/or debugging that area would help. If you print(player) or call the equivalent log function in both cases, you should see they are different. If you can't run in a debugger, you can still get a stack trace with print(debug.traceback("Accessing player, who's value is: "..player)). If there is indeed some kind of table-based player object in both cases, you can try comparing their fields to see how they are different. You might need to write a simple dumping function to help with that.
I got a problem,my program coredumped when i iterator a set,the code is below,when the size of the set is below 50000,it runs okay,while it'll fail when the size is bigger than 50000(almost).I did nothing in the for loops,but it still coredumped .what is the problem?
set<CRoute *>::iterator it = route_list.begin();
for(; it != route_list.end(); ++it)
{
//Nothing TODO
}
what is the problem?
It's impossible to say given the data you've provided.
There are several common causes:
You have corrupted the set earlier in the program (e.g. by accessing it from multiple threads without proper locking)
You have used a sorting predicate that violates strict weak ordering requirements of the std::set
You have left a dangling pointer in your std::set, and your sorting predicate uses the dangling data and crashes when given garbage.
To figure out what's happening, quit thinking and look e.g. by running the program in a debugger and understanding exactly where the coredump is happening.
I have a web-application written in CodeIgniter, and for the most part everything seems fairly reasonable. However, I've noticed extremely high CPU usage when a user logs out. My logout function in my auth controller is as follows:
function logout()
{
$goto = $SERVER['HTTP-REFERER'];
$this->session->sess_destroy();
if (!$goto)
$goto = "/";
header('location: '.$goto);
}
Normally, this is perfectly fine and fast. The strange thing is that when linked to from a particular sub-page this function takes about 5-6 seconds my of mysqld running at 100% cpu. How can I see what it's doing, and why?
Taking a shot in the dark (if you're sure this function is causing the slowness):
First, you could turn on MySQL's slow query log:
http://dev.mysql.com/doc/refman/5.1/en/slow-query-log.html
Then, if $sess_use_database is TRUE you might try optimizing your session table. You could have some overhead causing issues.
Apart from that, the only other thing I can think of is that there is an issue with your DB server. You might try running the MySQL Tuner to see if you can improve things a bit:
https://github.com/rackerhacker/MySQLTuner-perl
Hope that helps!
FYI
Here is the code that is run when the OP runs sess_destroy() (from v2.0.2):
/**
* Destroy the current session
*
* #access public
* #return void
*/
function sess_destroy()
{
// Kill the session DB row
if ($this->sess_use_database === TRUE AND isset($this->userdata['session_id']))
{
$this->CI->db->where('session_id', $this->userdata['session_id']);
$this->CI->db->delete($this->sess_table_name);
}
// Kill the cookie
setcookie(
$this->sess_cookie_name,
addslashes(serialize(array())),
($this->now - 31500000),
$this->cookie_path,
$this->cookie_domain,
0
);
}