So, I finally completed the first cut of my logger, and initially it was a LOT larger than the version in the repository, but after 'test driving', I found that (sadly) all my fancy ideas were just too fancy.
So, it's a pretty small 'opus', and just proves the rule that the shorter a piece of software is, the longer it takes to write.
I found that the ability to define new logging macros, set levels and display options, cherry pick levels to show and defining an output function on the fly really is more than enough for everything that is needed.
Other fails include that my idea to use 'ts -i "%.s"' from moreutils for adhoc profiling didn't really work properly for some reason that I cannot work out why.
If I try to use it with a macro that sets a few printout markers inside a function, all I get is that the expected function printf output stops totally whilst it does it's thing, then I get the total time taken put out on the top line, and everything that I expected to arrive 'peu-a-peu' comes in one go as it's finished doing the time wasting loop test, and it looks suspiciously like it's simply measuring the time it takes for writing to stdout via printf, and that some weird blockage is happening to the stdout output.
Oh well. Looks like I just have to write something else to have that service :-D
Showing posts with label C. Show all posts
Showing posts with label C. Show all posts
Friday, 11 September 2015
Wednesday, 27 May 2015
Put some colour in your C code
I like colours.
Colours make things easier to spot, especially if you have to look at a few metres of test output bumpf --- looking for something blue or pink is much quicker.
So, I made myself a little color.h file that lives in /usr/include/ where it is available anywhere I need some colour in my code.
You will probably notice the colour names --- I took the liberty of renaming 'green' to 'moss', 'bold green' to just 'green' and 'magenta' to 'purple' and so on. It's less to type, more descriptive, and, also functions as a small cheat map to understand the weird names the fashionistas in your life use to describe colour shades.
You can find the source for color.h here, note that the test code is present in the file in a comment, ready to be copied into a *.c file.
Enjoy!
Colours make things easier to spot, especially if you have to look at a few metres of test output bumpf --- looking for something blue or pink is much quicker.
So, I made myself a little color.h file that lives in /usr/include/ where it is available anywhere I need some colour in my code.
You will probably notice the colour names --- I took the liberty of renaming 'green' to 'moss', 'bold green' to just 'green' and 'magenta' to 'purple' and so on. It's less to type, more descriptive, and, also functions as a small cheat map to understand the weird names the fashionistas in your life use to describe colour shades.
You can find the source for color.h here, note that the test code is present in the file in a comment, ready to be copied into a *.c file.
Enjoy!
Monday, 25 May 2015
A fake switch
This post is about a trick from the Dalvik VM Internals video, which was mentioned in the Coursera Android course that is currently running. (maybe the next million years will be more exciting?)
The claim was that this is the one case where goto isn't evil around minute 33:31 and that it performs better than switch. Well, does it? And if so, by how much?
This was the example:
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#define DISPATCH() \
{ goto *op_table[*((s)++) - 'a']; }
static void interp_old(const char* s)
{
static void *op_table[] = {
&&op_a, &&op_b, &&op_c, &&op_d, &&op_e };
DISPATCH();
op_a: printf("Hell"); DISPATCH();
op_b: printf("o "); DISPATCH();
op_c: printf("wo"); DISPATCH();
op_d: printf("rld!\n"); DISPATCH();
op_e: return;
}
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Switch is pretty switched on, so let's see how this compares!
The code that does the comparison can be found here. Results(on my ancient 32 bit Dell):
With gcc -g:
So, there is a small difference, but it's really not that big a deal, unless you really are pressed for time and space.
The ever useful gcc manual has an entry about fun with local labels which will tell you more.
Still, building this by hand is tedious, even if emacs is your best friend.
What if you have a huge array of a struct that maps variable A to variable B and also has an optional function pointer F? What you need is a 'fake_switch' generator, here is my version. It should be easily adjustable for your taste.
Goto it ;-)
Ps.: For extra fun, try this C to Assembler translator. I really like the hover feature they built, but another thing that would be useful is showing the size of the generated code.
The claim was that this is the one case where goto isn't evil around minute 33:31 and that it performs better than switch. Well, does it? And if so, by how much?
This was the example:
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#define DISPATCH() \
{ goto *op_table[*((s)++) - 'a']; }
static void interp_old(const char* s)
{
static void *op_table[] = {
&&op_a, &&op_b, &&op_c, &&op_d, &&op_e };
DISPATCH();
op_a: printf("Hell"); DISPATCH();
op_b: printf("o "); DISPATCH();
op_c: printf("wo"); DISPATCH();
op_d: printf("rld!\n"); DISPATCH();
op_e: return;
}
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Switch is pretty switched on, so let's see how this compares!
The code that does the comparison can be found here. Results(on my ancient 32 bit Dell):
With gcc -g:
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= Using default value of 100000. Usage: ./dispatch # Sample size = 100000 chars * 100000 iterations. Dispatch method: 0.002152 Dispatch shuffled method: 0.002144 Goto switch method: 0.002641 Goto switch method 2: 0.002351 For loop Switch method: 0.002667 For loop Switch shuffled method: 0.002660 Recursive switch method: 0.010798 Recursive shuffled Switch method: 0.006913 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
With gcc -O3:
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= Using default value of 100000. Usage: ./dispatch # Sample size = 100000 chars * 100000 iterations. Dispatch method: 0.001083 Dispatch shuffled method: 0.001108 Goto switch method: 0.001338 Goto switch method 2: 0.001381 For loop Switch method: 0.001465 For loop Switch shuffled method: 0.001385 Recursive switch method: 0.001437 Recursive shuffled Switch method: 0.001385 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
So, there is a small difference, but it's really not that big a deal, unless you really are pressed for time and space.
What if you have a huge array of a struct that maps variable A to variable B and also has an optional function pointer F? What you need is a 'fake_switch' generator, here is my version. It should be easily adjustable for your taste.
Goto it ;-)
Ps.: For extra fun, try this C to Assembler translator. I really like the hover feature they built, but another thing that would be useful is showing the size of the generated code.
Thursday, 16 April 2015
Sometimes, it's not a bug, but a workaround.
I found a few ';;' in the Corinthia source and thought -- aha, typo! So, I fixed and committed, but alas...
http://www.mail-archive.com/dev@corinthia.incubator.apache.org/msg01164.html
...it's a VC++ bug, it won't do C99 without this little hack.
http://www.mail-archive.com/dev@corinthia.incubator.apache.org/msg01164.html
...it's a VC++ bug, it won't do C99 without this little hack.
Monday, 9 March 2015
... and it was such a great idea... :(
tldr:
Lesson 1: You cannot cheat your way around strlen() by using sizeof(s)/sizeof(s[0]) because you cannot stuff a char *s into a char s[] for free.Lesson 2: Don't use the clock mechanism in the proggy below, because it's unreliable on hyper-threaded CPUs.
Lesson 3: Don't use floats.
The full story:
I am currently reading the book Modern C. In it, I came across the advice that you can compute the size of an array by doing sizeof(s)/sizeof(s[0]). Hmm, maybe I could use that instead of strlen, because surely this is much quicker!So... hackety-hack, I made this[1] and got that output:
A: Time spent: 0.045580 count = 35
B: Time spent: 0.180489 count = 34
I mailed my guru about this unsuccess for his entertainment (and that of his colleagues :-) , and the message coming back informed me that clock is considered harmful, and floats are also bad. Being curious I asked why clock is dodgy (since time.h surely should be sound), and was informed that on a hyper-threaded CPU, it's unreliable, which of course is no good if you're trying to profile anything. Apparently it's better to use this little creation.
So, how to do find out if your cpu is hyper-threaded? You do cat /proc/cpuinfo and look up the spec. (mine isn't ht but that's no excuse).
[1]
#define _GNU_SOURCE /* See feature_test_macros(7) */
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <time.h>
int main (int argc, char *argv[])
{
clock_t begin, end;
double time_spent;
// sadly I can't assign ss to s :(
// char *ss = "supercalifragilisticexpialidocious";
char s[] = "supercalifragilisticexpialidocious";
size_t max = 10000000;
int count;
begin = clock();
for (size_t i = 0; i < max; i++)
count = sizeof(s)/sizeof(s[0]);
end = clock();
time_spent = (double)(end - begin) / CLOCKS_PER_SEC;
printf("A: Time spent: \t %f count = %d\n",time_spent, count);
begin = clock();
for (size_t i = 0; i < max; i++)
count = strlen(s);
end = clock();
time_spent = (double)(end - begin) / CLOCKS_PER_SEC;
printf("B: Time spent: \t %f count = %d\n",time_spent, count);
exit(EXIT_SUCCESS);
}
Wednesday, 4 March 2015
Wednesday, 25 February 2015
Your own malloc function, the very lazy way
The problem: You want your own malloc function, and there are gazillions of them in the code base you're working on. You could automate editing this lot, but littering the place with lots of custom xmallocs does not appeal, plus, there is are 3rd party libraries and you don't really want to mess with those.
The solution: 3 different ways of solving. And: How to coax the linker into compliance for the wrap.
The solution: 3 different ways of solving. And: How to coax the linker into compliance for the wrap.
My patch, that puts it all together, using CMake.
Wednesday, 31 December 2014
The Short Tourist's Guide to Memory Allocaters
There's ancient malloc().
And then there is glibc's malloc():
General:
A very good place to start is Mr. Golick's intro: Memory Allocators 101, then there is Mr. Luu's C tutorial, or even Doug Lea's dlmalloc. But, that's only the beginning of a very good, very long story.
Strategies (the very meat of this post):
There is an interesting survey on the different ways of writing a memory allocator, it's very informative (and well-written), and useful to know in general (even though it's a little old).
More Specific:
For even more pleasing (and productive) confusion, there's TCMalloc, Lockless and a short paper that compares glibc to the former and the latter.
Also notable is jemalloc, and they have a nice video too. Here's a neat synopsis of this toy.
Profiling:
TCMalloc has profiling inbuilt (via perftools), Lockless has some hooks and jemalloc has a heap profiler. If you want to check what glibc malloc gets up to, there's malloc_count, or, you can knit your own, using malloc hooks and struct mallinfo.
The Lockless site has some neat info on how to profile without a profiler, using gcc. (their article collection is also quite a good read [with a very special recommendation for the rather nifty 'Obfuscated Rogue' proggy <3 !]).
Happy alloc()-ing!
Ps.: Stuff I idly wonder about:
None of the above seem to take performance profiles of stuff as they run and then automate the conclusions.
There is probably a very good reason for it (there always is :-) --- but, I wonder what would happen if we had a wrapper that that 'kept score' and did test runs on the inputs it knows about and then swaps in different memory allocators on the next run, depending on what profiles match that particular usage pattern the best.
In other news, here's my sure-fire way of how to beat the backgammon world champion: you roll a double-6 to run home, and with the final checker, you put their 15th checker on the bar. EASY! ;-)
Obligatory New Years' Eve video... Ms Sophie is celebrating her birthday party. The only problem is that all her guests deceased 25 years ago, and so, the butler has to stand in... (scroll forward to 2:24 to start the actual sketch, but, in full length with the German intro, it still makes a nice ambience, even if you do not speak German ;-) the rest is, as they say, without words!
And then there is glibc's malloc():
A very good place to start is Mr. Golick's intro: Memory Allocators 101, then there is Mr. Luu's C tutorial, or even Doug Lea's dlmalloc. But, that's only the beginning of a very good, very long story.
Strategies (the very meat of this post):
There is an interesting survey on the different ways of writing a memory allocator, it's very informative (and well-written), and useful to know in general (even though it's a little old).
More Specific:
For even more pleasing (and productive) confusion, there's TCMalloc, Lockless and a short paper that compares glibc to the former and the latter.
Also notable is jemalloc, and they have a nice video too. Here's a neat synopsis of this toy.
Profiling:
TCMalloc has profiling inbuilt (via perftools), Lockless has some hooks and jemalloc has a heap profiler. If you want to check what glibc malloc gets up to, there's malloc_count, or, you can knit your own, using malloc hooks and struct mallinfo.
The Lockless site has some neat info on how to profile without a profiler, using gcc. (their article collection is also quite a good read [with a very special recommendation for the rather nifty 'Obfuscated Rogue' proggy <3 !]).
Happy alloc()-ing!
Ps.: Stuff I idly wonder about:
None of the above seem to take performance profiles of stuff as they run and then automate the conclusions.
There is probably a very good reason for it (there always is :-) --- but, I wonder what would happen if we had a wrapper that that 'kept score' and did test runs on the inputs it knows about and then swaps in different memory allocators on the next run, depending on what profiles match that particular usage pattern the best.
+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+
Happy New year everyone!!!
Monday, 17 November 2014
Just another evening on IRC
I hang out on ##c on freenode.net to learn some stuff (and for some entertainment).
Apart from talking about C, it's quite the dadaist scene:
[00:29] <pentester_> in C what's the different between char a="hello" and unsigned a="hello"?
[00:29] <pentester_> unsigned char a="hello"
[00:29] <marchelzo_> one is invalid and the other is invalid
[00:29] <pentester_> bad typo
[00:29] <pentester_> a[]
[00:30] <pentester_> char a[]="hello and unsigned char a[]="hello"
[00:30] <pentester_> ^ missing " xD
[00:30] <marchelzo_> one is an array of chars and the other is an array of unsigned chars
[00:30] <pentester_> what's the purpose of the unsigned char?
[00:30] <pentester_> i mean why someone would use it ?
[00:30] * zid` thinks pentester_ tests pens for a living
[00:31] <gyaretto> pentester_: I'm using it now.
[00:31] <gyaretto> Because I need to make use of all 8 bits.
[00:31] <marchelzo_> ungined char can store larger integers than char
[00:31] <marchelzo_> unsigned*
[00:31] <zid`> and it's unsined..
[00:31] <zid`> meaning you can perform mathematical operations on it
[00:31] <zid`> that would otherwise be UB
[00:31] <Chris> Why do you ever use any unsigned types? Because you don't care about negatives.
[00:32] <gyaretto> zid`: Didn't know that. TIL.
[00:32] <pentester_> so i can use integer which is more or equal to 0x80?
[00:32] <Chris> So you use unsigned char just to deal with bytes from 0 to 255 (or greater)
[00:32] <Chris> Yes, unsigned char ranges from at least 0 to 0xFF
[00:32] <marchelzo_> what can you do with unsigned that is UB with signed?
[00:32] <zid`> shifting
[00:32] <Chris> go past the highest value.
[00:32] <zid`> in some situations
[00:32] <zid`> overflow
[00:32] <zid`> lots of stuff
[00:32] *** ChanServ gives channel operator privileges to candide.
[00:32] *** candide sets a ban on *!zid@90.219.233.100.
[00:32] <Chris> unsigned char x = UCHAR_MAX; x++; // defined to be 0
[00:33] <pentester_> what is UB?
[00:33] <Chris> signed char y = SCHAR_MAX; x++; // undefined behavior
[00:33] <Chris> pentester_: undefined behavior.
[00:33] <Chris> er.. y++ for the second example, obviously.
[00:33] <pentester_> zid`: r u hacker?
[00:33] *** candide removes the ban on *!zid@90.219.233.100.
[00:34] <zid`> pentester_: Can you recommend me a pen?
[00:34] <pentester_> zid`: no time to sell pen
[00:34] <pentester_> i can penetrate if that what you want
[00:35] <Chris> zid`: www.penisland.net
[00:35] <m0shbear> zid`: the free ones they give out at career fairs
[00:35] <pentester_> Chris: what's the value of SCHAR_MAX
[00:35] <Chris> pentester_: implementation dependent.
[00:35] <pentester_> why its UB
[00:35] <vhlfd> Lol.
[00:35] <Chris> pentester_: why is what UB?
[00:35] <marchelzo_> ,grab pentester_ penetrate
[00:35] <m0shbear> because signed overflow is undefined
[00:35] <candide> Quote grabbed: 446: <pentester_> i can penetrate if that what you want
[00:36] <Chris> pentester_: overflowing a signed integer is undefined behavior.
[00:36] <gyaretto> Haha.
[00:36] <pentester_> will that a good thing for hacker?
[00:36] <Chris> Don't know, don't care.
[00:36] <pentester_> i mean can an attacker benefit from UB
[00:36] <Chris> Ask ##scriptkiddies
[00:36] <marchelzo_> yes
[00:36] <zid`> Stick to testing pens
[00:37] <Chris> pentester_: buffer overflows are UB, surely you're familiar with them
[00:37] <vhlfd> I doubt he has any idea what he's doing, all things considered.
[00:37] <m0shbear> ^
[00:37] <pentester_> vhlfd: jelly?
[00:37] *** ChanServ takes channel operator privileges from candide.
[00:38] <pentester_> m0shbear: 0xF0ff
[00:38] <vhlfd> Wannabe hackers are excruciating.
[00:38] <Chris> Everyone has to learn at first.
[00:38] <zid`> He's learning upside down
[00:38] <Chris> But the side effects of UB are off-topic here.
[00:38] <zid`> He's going for things he's not intelligent enough to understand first, rather than last
[00:38] <Chris> That's fairly typical.
[00:40] <pentester_> what's the meaning of signed overflow?
[00:40] <pentester_> i understand simple overflow
[00:40] <vhlfd> Read a book.
[00:40] <pentester_> vhlfd: wut book
[00:40] <vhlfd> ,k&r pentester_
[00:40] <Chris> It just means overflow on signed integers.
[00:40] <candide> pentester_: k&r is The C Programming Language, 2nd edition, by Kernighan and Ritchie, http://cm.bell-labs.com/cm/cs/cbook/ - be sure to see the errata as well, at http://cm.bell-labs.com/cm/cs/cbook/2ediffs.html
[00:40] <pentester_> old book
[00:40] <m0shbear> >not reading the classics
[00:40] <gunthler> http://www.twitch.tv/handmade_hero
[00:40] <candide> Title of gunthler's link: Twitch
[00:40] <vhlfd> Indeed. It could teach you a thing or two.
[00:41] <Chris> In C, when you do an arithmetic operation that takes a signed integer out of range, it's undefined behavior.
[00:41] <Chris> When you do the same on an unsigned integer, it is well defined.
[00:41] <Chris> The end.
[00:41] <pentester_> chris you mean if the maximum is -5 and i add one and it become -6 it will result in UB
[00:41] <Chris> I don't know how the hell you add 1 to -5 to get -6
[00:41] * vhlfd wanders off.
[00:41] <pentester_> add one by using add 0xff
[00:42] <pentester_> ^ -1
[00:42] * Chris facepalms.
[00:42] <m0shbear> use of twos-complement == nonportable
[00:42] <Chris> Don't try to be clever, pentester_. Adding 255 is not the same as subtracting 1
[00:42] <pentester_> i think i'm doing it right?
[00:43] <Chris> (except in certain contexts, which we're not talking about now and that's unsigned char where CHAR_BIT is 8)
[00:43] <Chris> No, you're not.
[00:43] <Chris> Adding 255 is not the same as subtracting 1. Make up your mind what you're talking about.
[00:43] <m0shbear> >assuming a certain representation of negative values
[00:43] <Chris> Given signed char x = -5; then x += 255; is undefined behavior. (assuming SCHAR_MAX == 127)
[00:43] <m0shbear> >assuming a certain number of bits
[00:43] <pentester_> Chris: now we talking
[00:44] <pentester_> i'm waiting for the example for overflowing signed integer
[00:44] <Chris> pentester_: anything which results in an out of range result.
[00:44] <pentester_> thanks
[00:44] <pentester_> unsigned will never overflow right?
[00:44] <Chris> Now, given unsigned char y = 5; then y += 255; is _guaranteed_ to set y to 4 (for CHAR_BIT == 8)
[00:44] <Chris> Correct.
[00:45] <pentester_> unsigned wrap around signed are not?
[00:45] <Chris> Yes...
[00:45] <pentester_> clear ;)
[00:46] <pentester_> ,thanks Chris
[00:46] <candide> /say, pentester_
[00:51] <batchm> pentester please note that you are being told what the C standard says from anal pedants, and not what actually happens on platforms you are likely to use now, and in your life time. I am sure there is some obscure platform where signed numerical types don't wrap around, but I am also sure you aren't using any of them
[00:52] <vhlfd> Another insane person.
[00:53] <Chris> pentester_: batchm's well meaning (toward you, not me) but ignorant comment neglects the fact that compilers are allowed to assume undefined behavior doesn't happen and can and will optimize out such things in many instances, thus causing shit to fail if you assume such a wrap. This is why gcc supports and needs the -fwrapv compiler flag, for example.
[00:54] <batchm> more anal pedantry.. please ignore it
[00:54] <Chris> (I just gave a practical example, and it's still called pedantry, hilarious)
[00:54] <batchm> unless you want to become a language lawyer, rather than actually get things done
[00:55] <lemonade`> hey guys, anything new lately?
[00:55] <m0shbear> >getting things done by assuming implementation-dependent things that are technically UB
[00:55] <m0shbear> how fun
[00:56] <vhlfd> Is moshbear the channel mule?
[00:56] <vhlfd> batchm, I don't think you know many language lawyers.
[00:57] <vhlfd> I think people in general would be happy if IDB GNU C were the topic of this channel.
[00:58] <vhlfd> Meh.
[00:58] <m0shbear> vhlfd: eh?
[01:01] <milesrout> pentester_, signed overflow isn't 'left up to the compiler' or 'left up to the target platform' or anything like that. The standard says 'signed overflow is undefined behaviour'. That means that your compiler is allowed to assume it never ever happens.
[01:02] <milesrout> e.g. if you do for (int i = 0; i < -1; i++);, you might expect that the compiler will go from 0 up to INT_MAX then wrap around and go up to -1 from INT_MIN.
[01:03] <milesrout> that *might* happen. but the compiler is allowed to say "signed overflow is undefined, so the programmer doesn't intend it to happen. 0 is greater than -1, and you only increment i in the loop, so i only increases. therefore this is an infinite loop"
[01:03] <milesrout> and emit the equivalent of for (int i = 0; true; i++)
[01:06] <naptime> milesrout: You meant i > -1 , right?
[01:06] <naptime> in the loop?
[01:06] <milesrout> naptime, uhh... yes!
[01:06] <milesrout> yes I did.
[01:06] <naptime> Okay, that makes more sense then [=
[01:07] <milesrout> of course, the compiler is also allowed to say 'when int overflows, wipe the hard drive'
[01:07] <naptime> I would hate to develop for that implementation!
[01:08] <milesrout> if you pass -fwrapv to the compiler, it'll wrap on signed overflow and everything should be dandy. if you pass -ftrapv to the compiler, it'll *trap* on signed overflow, i.e. your program will abort when it tries to increment INT_MAX.
[01:08] <naptime> And -fwipev clears the hard disk?
[01:08] <milesrout> those aren't portable, though. -ftrapv is very useful for debugging if you think you have signed overflow somewhere and the compiler is fucking with you because of it.
[01:09] <milesrout> hahah
[01:09] <eb0t> join #ubuntu
[01:09] <vhlfd> Nearly there.
[01:10] <milesrout> I'm a little disappointed if I wrote that all out and pentester_ had already left :/
[01:11] <vhlfd> milesrout, you can messenger your loop to him I'm sure.
[01:12] <naptime> milesrout: Well I got here just before you wrote it all out so I saw it even if this pentester_ user didn't >^,^< And I thought it was very helpful!
[01:12] <milesrout> naptime, good!
[01:12] <vhlfd> >^,^<
[01:13] <PoppaVic> always assume a compiler.. and behavior. Very Good.
[01:28] <fizzie> ,cc -std=c11 -O2 void f(int i) { static int c = 0; if (c++ > 10) exit(0); printf("%d ", i); } for (int i = INT_MAX - 2; i > -1; i++) f(i); /* look at that optimizer go! */
[01:28] <candide> fizzie: 2147483645 2147483646 2147483647 2147483645 2147483646 2147483647 2147483645 2147483646 2147483647 2147483645 2147483646 Program received signal SIGSEGV, Segmentation fault in ?? () called by exit () called by f (i=<optimized out>) at statement: if (c++ > 10) exit(0); called by main () at statement: for (int i = INT_MAX - 2; i > -1; i++) f(i); <local variables: c = 12; i = 2147483647>
Srsly, who needs comic shows on TV when stuff like that is available? :-D
Apart from talking about C, it's quite the dadaist scene:
[00:29] <pentester_> in C what's the different between char a="hello" and unsigned a="hello"?
[00:29] <pentester_> unsigned char a="hello"
[00:29] <marchelzo_> one is invalid and the other is invalid
[00:29] <pentester_> bad typo
[00:29] <pentester_> a[]
[00:30] <pentester_> char a[]="hello and unsigned char a[]="hello"
[00:30] <pentester_> ^ missing " xD
[00:30] <marchelzo_> one is an array of chars and the other is an array of unsigned chars
[00:30] <pentester_> what's the purpose of the unsigned char?
[00:30] <pentester_> i mean why someone would use it ?
[00:30] * zid` thinks pentester_ tests pens for a living
[00:31] <gyaretto> pentester_: I'm using it now.
[00:31] <gyaretto> Because I need to make use of all 8 bits.
[00:31] <marchelzo_> ungined char can store larger integers than char
[00:31] <marchelzo_> unsigned*
[00:31] <zid`> and it's unsined..
[00:31] <zid`> meaning you can perform mathematical operations on it
[00:31] <zid`> that would otherwise be UB
[00:31] <Chris> Why do you ever use any unsigned types? Because you don't care about negatives.
[00:32] <gyaretto> zid`: Didn't know that. TIL.
[00:32] <pentester_> so i can use integer which is more or equal to 0x80?
[00:32] <Chris> So you use unsigned char just to deal with bytes from 0 to 255 (or greater)
[00:32] <Chris> Yes, unsigned char ranges from at least 0 to 0xFF
[00:32] <marchelzo_> what can you do with unsigned that is UB with signed?
[00:32] <zid`> shifting
[00:32] <Chris> go past the highest value.
[00:32] <zid`> in some situations
[00:32] <zid`> overflow
[00:32] <zid`> lots of stuff
[00:32] *** ChanServ gives channel operator privileges to candide.
[00:32] *** candide sets a ban on *!zid@90.219.233.100.
[00:32] <Chris> unsigned char x = UCHAR_MAX; x++; // defined to be 0
[00:33] <pentester_> what is UB?
[00:33] <Chris> signed char y = SCHAR_MAX; x++; // undefined behavior
[00:33] <Chris> pentester_: undefined behavior.
[00:33] <Chris> er.. y++ for the second example, obviously.
[00:33] <pentester_> zid`: r u hacker?
[00:33] *** candide removes the ban on *!zid@90.219.233.100.
[00:34] <zid`> pentester_: Can you recommend me a pen?
[00:34] <pentester_> zid`: no time to sell pen
[00:34] <pentester_> i can penetrate if that what you want
[00:35] <Chris> zid`: www.penisland.net
[00:35] <m0shbear> zid`: the free ones they give out at career fairs
[00:35] <pentester_> Chris: what's the value of SCHAR_MAX
[00:35] <Chris> pentester_: implementation dependent.
[00:35] <pentester_> why its UB
[00:35] <vhlfd> Lol.
[00:35] <Chris> pentester_: why is what UB?
[00:35] <marchelzo_> ,grab pentester_ penetrate
[00:35] <m0shbear> because signed overflow is undefined
[00:35] <candide> Quote grabbed: 446: <pentester_> i can penetrate if that what you want
[00:36] <Chris> pentester_: overflowing a signed integer is undefined behavior.
[00:36] <gyaretto> Haha.
[00:36] <pentester_> will that a good thing for hacker?
[00:36] <Chris> Don't know, don't care.
[00:36] <pentester_> i mean can an attacker benefit from UB
[00:36] <Chris> Ask ##scriptkiddies
[00:36] <marchelzo_> yes
[00:36] <zid`> Stick to testing pens
[00:37] <Chris> pentester_: buffer overflows are UB, surely you're familiar with them
[00:37] <vhlfd> I doubt he has any idea what he's doing, all things considered.
[00:37] <m0shbear> ^
[00:37] <pentester_> vhlfd: jelly?
[00:37] *** ChanServ takes channel operator privileges from candide.
[00:38] <pentester_> m0shbear: 0xF0ff
[00:38] <vhlfd> Wannabe hackers are excruciating.
[00:38] <Chris> Everyone has to learn at first.
[00:38] <zid`> He's learning upside down
[00:38] <Chris> But the side effects of UB are off-topic here.
[00:38] <zid`> He's going for things he's not intelligent enough to understand first, rather than last
[00:38] <Chris> That's fairly typical.
[00:40] <pentester_> what's the meaning of signed overflow?
[00:40] <pentester_> i understand simple overflow
[00:40] <vhlfd> Read a book.
[00:40] <pentester_> vhlfd: wut book
[00:40] <vhlfd> ,k&r pentester_
[00:40] <Chris> It just means overflow on signed integers.
[00:40] <candide> pentester_: k&r is The C Programming Language, 2nd edition, by Kernighan and Ritchie, http://cm.bell-labs.com/cm/cs/cbook/ - be sure to see the errata as well, at http://cm.bell-labs.com/cm/cs/cbook/2ediffs.html
[00:40] <pentester_> old book
[00:40] <m0shbear> >not reading the classics
[00:40] <gunthler> http://www.twitch.tv/handmade_hero
[00:40] <candide> Title of gunthler's link: Twitch
[00:40] <vhlfd> Indeed. It could teach you a thing or two.
[00:41] <Chris> In C, when you do an arithmetic operation that takes a signed integer out of range, it's undefined behavior.
[00:41] <Chris> When you do the same on an unsigned integer, it is well defined.
[00:41] <Chris> The end.
[00:41] <pentester_> chris you mean if the maximum is -5 and i add one and it become -6 it will result in UB
[00:41] <Chris> I don't know how the hell you add 1 to -5 to get -6
[00:41] * vhlfd wanders off.
[00:41] <pentester_> add one by using add 0xff
[00:42] <pentester_> ^ -1
[00:42] * Chris facepalms.
[00:42] <m0shbear> use of twos-complement == nonportable
[00:42] <Chris> Don't try to be clever, pentester_. Adding 255 is not the same as subtracting 1
[00:42] <pentester_> i think i'm doing it right?
[00:43] <Chris> (except in certain contexts, which we're not talking about now and that's unsigned char where CHAR_BIT is 8)
[00:43] <Chris> No, you're not.
[00:43] <Chris> Adding 255 is not the same as subtracting 1. Make up your mind what you're talking about.
[00:43] <m0shbear> >assuming a certain representation of negative values
[00:43] <Chris> Given signed char x = -5; then x += 255; is undefined behavior. (assuming SCHAR_MAX == 127)
[00:43] <m0shbear> >assuming a certain number of bits
[00:43] <pentester_> Chris: now we talking
[00:44] <pentester_> i'm waiting for the example for overflowing signed integer
[00:44] <Chris> pentester_: anything which results in an out of range result.
[00:44] <pentester_> thanks
[00:44] <pentester_> unsigned will never overflow right?
[00:44] <Chris> Now, given unsigned char y = 5; then y += 255; is _guaranteed_ to set y to 4 (for CHAR_BIT == 8)
[00:44] <Chris> Correct.
[00:45] <pentester_> unsigned wrap around signed are not?
[00:45] <Chris> Yes...
[00:45] <pentester_> clear ;)
[00:46] <pentester_> ,thanks Chris
[00:46] <candide> /say, pentester_
[00:51] <batchm> pentester please note that you are being told what the C standard says from anal pedants, and not what actually happens on platforms you are likely to use now, and in your life time. I am sure there is some obscure platform where signed numerical types don't wrap around, but I am also sure you aren't using any of them
[00:52] <vhlfd> Another insane person.
[00:53] <Chris> pentester_: batchm's well meaning (toward you, not me) but ignorant comment neglects the fact that compilers are allowed to assume undefined behavior doesn't happen and can and will optimize out such things in many instances, thus causing shit to fail if you assume such a wrap. This is why gcc supports and needs the -fwrapv compiler flag, for example.
[00:54] <batchm> more anal pedantry.. please ignore it
[00:54] <Chris> (I just gave a practical example, and it's still called pedantry, hilarious)
[00:54] <batchm> unless you want to become a language lawyer, rather than actually get things done
[00:55] <lemonade`> hey guys, anything new lately?
[00:55] <m0shbear> >getting things done by assuming implementation-dependent things that are technically UB
[00:55] <m0shbear> how fun
[00:56] <vhlfd> Is moshbear the channel mule?
[00:56] <vhlfd> batchm, I don't think you know many language lawyers.
[00:57] <vhlfd> I think people in general would be happy if IDB GNU C were the topic of this channel.
[00:58] <vhlfd> Meh.
[00:58] <m0shbear> vhlfd: eh?
[01:01] <milesrout> pentester_, signed overflow isn't 'left up to the compiler' or 'left up to the target platform' or anything like that. The standard says 'signed overflow is undefined behaviour'. That means that your compiler is allowed to assume it never ever happens.
[01:02] <milesrout> e.g. if you do for (int i = 0; i < -1; i++);, you might expect that the compiler will go from 0 up to INT_MAX then wrap around and go up to -1 from INT_MIN.
[01:03] <milesrout> that *might* happen. but the compiler is allowed to say "signed overflow is undefined, so the programmer doesn't intend it to happen. 0 is greater than -1, and you only increment i in the loop, so i only increases. therefore this is an infinite loop"
[01:03] <milesrout> and emit the equivalent of for (int i = 0; true; i++)
[01:06] <naptime> milesrout: You meant i > -1 , right?
[01:06] <naptime> in the loop?
[01:06] <milesrout> naptime, uhh... yes!
[01:06] <milesrout> yes I did.
[01:06] <naptime> Okay, that makes more sense then [=
[01:07] <milesrout> of course, the compiler is also allowed to say 'when int overflows, wipe the hard drive'
[01:07] <naptime> I would hate to develop for that implementation!
[01:08] <milesrout> if you pass -fwrapv to the compiler, it'll wrap on signed overflow and everything should be dandy. if you pass -ftrapv to the compiler, it'll *trap* on signed overflow, i.e. your program will abort when it tries to increment INT_MAX.
[01:08] <naptime> And -fwipev clears the hard disk?
[01:08] <milesrout> those aren't portable, though. -ftrapv is very useful for debugging if you think you have signed overflow somewhere and the compiler is fucking with you because of it.
[01:09] <milesrout> hahah
[01:09] <eb0t> join #ubuntu
[01:09] <vhlfd> Nearly there.
[01:10] <milesrout> I'm a little disappointed if I wrote that all out and pentester_ had already left :/
[01:11] <vhlfd> milesrout, you can messenger your loop to him I'm sure.
[01:12] <naptime> milesrout: Well I got here just before you wrote it all out so I saw it even if this pentester_ user didn't >^,^< And I thought it was very helpful!
[01:12] <milesrout> naptime, good!
[01:12] <vhlfd> >^,^<
[01:13] <PoppaVic> always assume a compiler.. and behavior. Very Good.
[01:28] <fizzie> ,cc -std=c11 -O2 void f(int i) { static int c = 0; if (c++ > 10) exit(0); printf("%d ", i); } for (int i = INT_MAX - 2; i > -1; i++) f(i); /* look at that optimizer go! */
[01:28] <candide> fizzie: 2147483645 2147483646 2147483647 2147483645 2147483646 2147483647 2147483645 2147483646 2147483647 2147483645 2147483646 Program received signal SIGSEGV, Segmentation fault in ?? () called by exit () called by f (i=<optimized out>) at statement: if (c++ > 10) exit(0); called by main () at statement: for (int i = INT_MAX - 2; i > -1; i++) f(i); <local variables: c = 12; i = 2147483647>
Srsly, who needs comic shows on TV when stuff like that is available? :-D
Monday, 20 October 2014
My Buffer Overflowesth
There I was, looking for a video on the glibc malloc implementation (more about that adventure in the next post) and whilst the most promising clip I found was unfortunately in Japanese (and, it has to be admitted, this is about as much as I currently understand about this topic :-) --- I came across a gentleman on the sidebar who posted a nifty video series about buffer overruns, and who has a good way of explaining the problem.
If you've always wondered just exactly how a buffer overrun works in real life(in a very basic way) check his video series out {some basic assembler required}:
If you've always wondered just exactly how a buffer overrun works in real life(in a very basic way) check his video series out {some basic assembler required}:
Sunday, 12 October 2014
Solving a Non-Problem
If you solve Euler Project problem 26, you will be able to see my 'solution' in the forum for that problem on page 9, as user Gabriela.
It's terrible. Taarrrribbble. First I didn't research the math, thinking: Oh, that is _easy_! Then one simple hack led to another quick hack (with a bit of faerydust sprinkled) and let's just say I got the correct solution the first time I checked, because I lucked out, not because I wrote a good algorithm.
Valgrind was happy with it. I'm not. After posting the code, I realised that *somehow* I crammed nearly 1000 chars into a string I malloc(500)'ed.
The question is: Why did it work? The next question is: would it work on another computer? And most important of all: should it have worked in the first place? Plus, other than eye balling the code and seeing the obvious problem, is there a way to check?
True, you could say that it's not a bug as such, because it does what I intended, but... the issue that I have, is if that isn't picked up with a nice helpful (and popular!) SIGSEV, what else is as dodgy and wrong?
Adding -fstack-protector-all didn't help to find a indication of an error either.
After some surfing, I found that dmesg (and readelf -s) is my friend, and, lo and behold:
(...)
[12556151.546186] project2-exe[18950]: segfault at 7fff5a18ae00 ip 00007fd452916744 sp 00007fffaddf9338 error 4 in libc-2.19.so[7fd45288d000+1bb000]
[12564217.667780] traps: project2-exe[19250] general protection ip:7f94a50ad7cd sp:7fff01927b90 error:0 in libc-2.19.so[7f94a5072000+1bb000]
(...)
Luckily I knew where the problem was, or so I thought. But, alas, this was a previous SIGSEV which I had fixed[1] and there was nothing that readelf had to tell me. After some more coffee, I finally had the bright idea that perhaps those allocations were just not used, and I checked the man pages for strndup() and strstr() and... yep, that was the non-problem.
[1] One good reason to use the emacs shell instead of M-x compile: search upwards is trivial and you find out some things that otherwise would have confuzzled you for yonks.
It's terrible. Taarrrribbble. First I didn't research the math, thinking: Oh, that is _easy_! Then one simple hack led to another quick hack (with a bit of faerydust sprinkled) and let's just say I got the correct solution the first time I checked, because I lucked out, not because I wrote a good algorithm.
Valgrind was happy with it. I'm not. After posting the code, I realised that *somehow* I crammed nearly 1000 chars into a string I malloc(500)'ed.
The question is: Why did it work? The next question is: would it work on another computer? And most important of all: should it have worked in the first place? Plus, other than eye balling the code and seeing the obvious problem, is there a way to check?
True, you could say that it's not a bug as such, because it does what I intended, but... the issue that I have, is if that isn't picked up with a nice helpful (and popular!) SIGSEV, what else is as dodgy and wrong?
Adding -fstack-protector-all didn't help to find a indication of an error either.
After some surfing, I found that dmesg (and readelf -s) is my friend, and, lo and behold:
(...)
[12556151.546186] project2-exe[18950]: segfault at 7fff5a18ae00 ip 00007fd452916744 sp 00007fffaddf9338 error 4 in libc-2.19.so[7fd45288d000+1bb000]
[12564217.667780] traps: project2-exe[19250] general protection ip:7f94a50ad7cd sp:7fff01927b90 error:0 in libc-2.19.so[7f94a5072000+1bb000]
(...)
Luckily I knew where the problem was, or so I thought. But, alas, this was a previous SIGSEV which I had fixed[1] and there was nothing that readelf had to tell me. After some more coffee, I finally had the bright idea that perhaps those allocations were just not used, and I checked the man pages for strndup() and strstr() and... yep, that was the non-problem.
[1] One good reason to use the emacs shell instead of M-x compile: search upwards is trivial and you find out some things that otherwise would have confuzzled you for yonks.
Wednesday, 13 August 2014
Sometimes, to fake is better than to make
#! /bin/bash
# Compile a test file without those noisy -Wunused* flags, but
# everything else that may be useful.
#
# Usage: compileCTest <name of your file without the '.c'>
# give the executable an easy to spot and mass-delete friendly name
executable="$1-exe"
# remove the old executable if it exists
if [ -e $executable ]
then
rm $executable;
fi
echo ""
echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
echo ""
# all flags from -Wall and -Wextra minus the -Wunused flags
runGCC='gcc -g -std=c99 -Waddress -Warray-bounds -Wchar-subscripts -Wenum-compare -Wimplicit-int -Wimplicit-function-declaration -Wformat -Wmain -Wmaybe-uninitialized -Wmissing-braces -Wnonnull -Wparentheses -Wpointer-sign -Wreturn-type -Wsequence-point -Wsign-compare -Wstrict-aliasing -Wstrict-overflow=1 -Wswitch -Wtrigraphs -Wuninitialized -Wunknown-pragmas -Wvolatile-register-var -Wclobbered -Wempty-body -Wignored-qualifiers -Wmissing-field-initializers -Wmissing-parameter-type -Wold-style-declaration -Woverride-init -Wsign-compare -Wtype-limits -Wuninitialized $1.c -o $1-exe -lm -lgmp'
eval $runGCC
# check that compile resulted in executable and if so, run it
if [ -e $executable ]
then
# add a couple of dividing lines to make this easier to read
echo "=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=";
./$executable;
echo "=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=";
fi
# Compile a test file without those noisy -Wunused* flags, but
# everything else that may be useful.
#
# Usage: compileCTest <name of your file without the '.c'>
# give the executable an easy to spot and mass-delete friendly name
executable="$1-exe"
# remove the old executable if it exists
if [ -e $executable ]
then
rm $executable;
fi
echo ""
echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
echo ""
# all flags from -Wall and -Wextra minus the -Wunused flags
runGCC='gcc -g -std=c99 -Waddress -Warray-bounds -Wchar-subscripts -Wenum-compare -Wimplicit-int -Wimplicit-function-declaration -Wformat -Wmain -Wmaybe-uninitialized -Wmissing-braces -Wnonnull -Wparentheses -Wpointer-sign -Wreturn-type -Wsequence-point -Wsign-compare -Wstrict-aliasing -Wstrict-overflow=1 -Wswitch -Wtrigraphs -Wuninitialized -Wunknown-pragmas -Wvolatile-register-var -Wclobbered -Wempty-body -Wignored-qualifiers -Wmissing-field-initializers -Wmissing-parameter-type -Wold-style-declaration -Woverride-init -Wsign-compare -Wtype-limits -Wuninitialized $1.c -o $1-exe -lm -lgmp'
eval $runGCC
# check that compile resulted in executable and if so, run it
if [ -e $executable ]
then
# add a couple of dividing lines to make this easier to read
echo "=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=";
./$executable;
echo "=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=";
fi
Sunday, 3 August 2014
Remedial Reading for the 'C'onfused.
Programming from the Ground up is an easy going, fun read, and goes a long way towards explaining all those inconvenient miracles that occur when you first try to use pointers in C.
... and, for some reason, Holger Czukays' short video of 'Ode To Perfume' nicely matches the topic (and it's pretty good hacking music). The longer version of that song is here
(and if this reminds you of Stockhausen's work, well, there's a reason for that)
Update: This here is also a useful read about C's peculiarities.
Friday, 25 July 2014
char* is not a synonym for char[]
... was the subject of a mail I wrote to friend, who replied:
... no, it's not a synonym. One of the ways in which they differ is in
declarators, as you see.
> int main(int argc, char *argv[])
>
> {
> char ok[] = "abcd";
This means 'ok[] is an array, as large as necessary, in writeable
storage, containing the string "abcd\0"'.
> char *broken = "abcd";
This means 'broken is a pointer to a character, pointing to the literal
string, in unmodified program text, "abcd". (Technically, this should be
'const char *': in C++, this is mandatory.)
Another difference: sizeof(ok) is the size of the array, in bytes;
sizeof(broken) is the size of a pointer to char on this platform.
In *parameter lists*, char *foo and char foo[] are synonyms, because
arrays decay to pointers *when passed to functions*. Otherwise, they are
not. (In this case sizeof() both will give the same answer.)
> /* this is ok */
>
> ok[0]= 'Z';
Yep. That's modifiable storage.
> printf("ok = %s\n", ok);
>
> /* this segfaults */
>
> broken[0] = 'Z';
Can't modify program text, this is not FORTRAN where you could pass in
the number 3 to a function and then modify it to change the value of 3
throughout the universe, uh, I mean your program. :P
> TIL C is short for 'Confusion'.
The general rule is that in declarators, you're declaring exactly what
it looks like: foo *bar is a *pointer*, not a buffer of anything, so
assigning to it will assign to *some other buffer somewhere else*. foo[]
bar is a convenience notation for making an array on the stack, as long
as necessary, and then initializing it as with memcpy() with an
appropriate size. (Not strcpy() -- you can do this:
char containsnulls[] = "foo\0bar"
which will make an eight-byte array containing "foo\0bar\0". strcpy()
would only fill in the first four bytes of that.)
This general distinction is crucial to get the hang of, because very
often you want to declare things *not* on the stack -- that outlive
their containing function -- and then you genrally have to declare them
as a foo * and allocate and free them by hand. So remembering where your
things live (that char foo[] lives on the stack, while char foo * merely
puts the pointer on the stack while the data lives elsewhere) is
essential.
... no, it's not a synonym. One of the ways in which they differ is in
declarators, as you see.
> int main(int argc, char *argv[])
>
> {
> char ok[] = "abcd";
storage, containing the string "abcd\0"'.
> char *broken = "abcd";
This means 'broken is a pointer to a character, pointing to the literal
string, in unmodified program text, "abcd". (Technically, this should be
'const char *': in C++, this is mandatory.)
Another difference: sizeof(ok) is the size of the array, in bytes;
sizeof(broken) is the size of a pointer to char on this platform.
In *parameter lists*, char *foo and char foo[] are synonyms, because
arrays decay to pointers *when passed to functions*. Otherwise, they are
not. (In this case sizeof() both will give the same answer.)
> /* this is ok */
>
> ok[0]= 'Z';
> printf("ok = %s\n", ok);
>
> /* this segfaults */
>
> broken[0] = 'Z';
the number 3 to a function and then modify it to change the value of 3
throughout the universe, uh, I mean your program. :P
> TIL C is short for 'Confusion'.
it looks like: foo *bar is a *pointer*, not a buffer of anything, so
assigning to it will assign to *some other buffer somewhere else*. foo[]
bar is a convenience notation for making an array on the stack, as long
as necessary, and then initializing it as with memcpy() with an
appropriate size. (Not strcpy() -- you can do this:
char containsnulls[] = "foo\0bar"
which will make an eight-byte array containing "foo\0bar\0". strcpy()
would only fill in the first four bytes of that.)
This general distinction is crucial to get the hang of, because very
often you want to declare things *not* on the stack -- that outlive
their containing function -- and then you genrally have to declare them
as a foo * and allocate and free them by hand. So remembering where your
things live (that char foo[] lives on the stack, while char foo * merely
puts the pointer on the stack while the data lives elsewhere) is
essential.
Thursday, 26 September 2013
The handrolled version of *_create_custom_diff_cmd
This may or may not be a good idea, but if you enjoy this sort of thing, my latest effort at code comedy is here.
This is probably not the final version because copying Mel the Programmer's strategies is almost never a good idea, but, it just had to be done at least once ;-)
Update 30mins later: Hah, already busted. I take away any special end characters but if what I'm handling is not a delimiter, then I end up stealing user's chars. Added a new test for this, now I have to fix it =)
(and why is it that every time, no matter how long I stare at my effort beforehand, the moment I commit code, I find a whopping show stopper a few minutes later? :-D )
Update on update: Fixed. And I should have coded that in the first place, the repetition should have made me suspicious, and I did think about it at the time, but thought that it can't be done differently for some reason. Next time, I'll lay off the catnip before I commit.
This is probably not the final version because copying Mel the Programmer's strategies is almost never a good idea, but, it just had to be done at least once ;-)
Update 30mins later: Hah, already busted. I take away any special end characters but if what I'm handling is not a delimiter, then I end up stealing user's chars. Added a new test for this, now I have to fix it =)
(and why is it that every time, no matter how long I stare at my effort beforehand, the moment I commit code, I find a whopping show stopper a few minutes later? :-D )
Update on update: Fixed. And I should have coded that in the first place, the repetition should have made me suspicious, and I did think about it at the time, but thought that it can't be done differently for some reason. Next time, I'll lay off the catnip before I commit.
Friday, 30 August 2013
Another failed patch
Whilst doing the long overdue merge of trunk into my invoke-diff-cmd branch, I spotted a deprecation warning that looked like a minor oversight, and so, I fixed it, svn compiled, the tests passed and ... the patch turned out to be a no-can-do, because APR_ARRAY_PUSH doesn't care what type you stuff in there.
I thought it did, because of this:
#define APR_ARRAY_PUSH(ary,type) (*((type *)apr_array_push(ary)))
which *looks* like it's type-safe at least if you don't know what you're really looking at (and if you haven't bothered to check the underlying code to see what it actually does). It of course does no such thing -- so, what does this trick that does seemingly nothing actually do?
Ask on #svn-dev and ye shall receive:
[19:32] <breser> gbb: The reason it takes a type is to avoid warnings. The apr_array_push() function returns a void *. Technically there's no issue with putting any pointer in a void pointer, however some compilers will warn you about that since you may not be doing it intentionally.
[19:33] <breser> gbb: The array code doesn't care what the pointer is to, it's up to the user of APR Arrays to keep their types straight.
[19:34] <breser> gbb: In this case the fact that the array code is taking a type (and casting) is hiding the errors/warnings you would have otherwise seen.
[20:30] <Bert> breser, gbb: Apr arrays can be of different kinds than just pointers. In some cases we have arrays of specific struct kinds (e.g. for property changes in the diff handling)
Thank you Ben and Bert, it certainly did clear things up, and made me look up the 'long answer' --- the very short answer of course is that C isn't C++, and so doesn't have type-safe templates. Caveat coder!
I thought it did, because of this:
#define APR_ARRAY_PUSH(ary,type) (*((type *)apr_array_push(ary)))
which *looks* like it's type-safe at least if you don't know what you're really looking at (and if you haven't bothered to check the underlying code to see what it actually does). It of course does no such thing -- so, what does this trick that does seemingly nothing actually do?
Ask on #svn-dev and ye shall receive:
[19:32] <breser> gbb: The reason it takes a type is to avoid warnings. The apr_array_push() function returns a void *. Technically there's no issue with putting any pointer in a void pointer, however some compilers will warn you about that since you may not be doing it intentionally.
[19:33] <breser> gbb: The array code doesn't care what the pointer is to, it's up to the user of APR Arrays to keep their types straight.
[19:34] <breser> gbb: In this case the fact that the array code is taking a type (and casting) is hiding the errors/warnings you would have otherwise seen.
[20:30] <Bert> breser, gbb: Apr arrays can be of different kinds than just pointers. In some cases we have arrays of specific struct kinds (e.g. for property changes in the diff handling)
Thank you Ben and Bert, it certainly did clear things up, and made me look up the 'long answer' --- the very short answer of course is that C isn't C++, and so doesn't have type-safe templates. Caveat coder!
Thursday, 21 March 2013
Diff is difficult.
After much staring, stepping and grepping, I finally produced a solution for the partial problem defined in (Issue 2074, "--extensions '' doesn't work.) which is part of (Issue 2044, Fully customizable external diff invocations).
It's not bad(it works for very small values of functional), but also not very good, since it is rather agricultural and I'm not sure how to handle deprecation, but, it's a start.
However it only deals with one part of the problem and not with the issue of giving the user a wormhole to call any diff function they want to use, however they want to.
To be continued... ;-)
It's not bad(it works for very small values of functional), but also not very good, since it is rather agricultural and I'm not sure how to handle deprecation, but, it's a start.
However it only deals with one part of the problem and not with the issue of giving the user a wormhole to call any diff function they want to use, however they want to.
To be continued... ;-)
Wednesday, 16 January 2013
Outlambda'd !
So, I decide to mail a MUD friend with my OPW success to brag a little about my 'Supersize Me' coding experiment and he shows me his 'Superconcise Me' project!
John Tromp scooped "Most Functional" in the 2012 International Obfuscated C contest!
I don't know the name of the program(this is the obfuscated C contest after all...), but I think it's the Lambda beast.
And suddenly the Subversion octopus does not look quite as scary anymore, relatively speaking (however, no easier at all!) If the 'Lamda beast' was a song, I think it would sound like this:
Gratz John, and thank you for a lovely coding perl!
John Tromp scooped "Most Functional" in the 2012 International Obfuscated C contest!
Int L[A],m,b,*D=A,
*c,*a=L,C,*U=L,u;s
(_){u--&&s(a=*a);}
char*B,I,O;S(){b=b
--?b:m|read(0,&I,1
)-1;return~I>>b&1;
}k(l,u){for(;l<=u;
U-L<A?*U++=46^l++[
"-,&,,/.--/,:-,'/"
".-,-,,/.-,*,//..,"
]:exit(5));}p(Int*m){
return!*U?*m=S()?U++,!S
()?m[1]=p(++U),2:3:1,p(U)
:S()?U+=2:p(U[1]++),U-m;}x(
c){k(7*!b,9);*U++=b&&S();c&&x
(b);}d(Int*l){--l[1]||d(l[d(*l),
*l=B,B=l,2]);}main(e){for(k(10,33
),a[4]-=m=e-2&7,a[23]=p(U),b=0;;e-2
?e?e-3?s(D=a),C=a [3],++1[a=a[2]],d(
D):c?D=c,c=*D,*D= a,a=D:exit(L[C+1])
:C--<23?C=u+m&1?O =O+O|C&1,9:write(m
||(O=C+28),&O,1)+ 1:(S(),x(0<b++?k(0,
6),U[-5]=96:0)):( D=B?B:calloc(4,X))
?B=*D,*D=c,c=D,D[ 2]=a,a[++D[1]]++,D
[3]=++C+u:exit(6) )e=L[C++],u=L[C];}
I don't know the name of the program(this is the obfuscated C contest after all...), but I think it's the Lambda beast.
And suddenly the Subversion octopus does not look quite as scary anymore, relatively speaking (however, no easier at all!) If the 'Lamda beast' was a song, I think it would sound like this:
Gratz John, and thank you for a lovely coding perl!
Subscribe to:
Posts (Atom)