Handmade Network»Forums»Work-in-Progress
Simon Anciaux
1302 posts
RSS and Atom feed reader
Edited by Simon Anciaux on Reason: Version 0.2


For quite sometime now I've been working on a feed reader. It isn't anything special, but suits my needs. Here is a small demo video and here is a link to a test version ( 0.1 ). I've used it for more than a year now and don't plan to change much in the future. It's a test version because I changed/fixed/cleaned lots of things in the past few weeks and I'd like some testing before calling it "finished".

Any feedback would be appreciated.

I also have a question: I'm still using Windows 7, and when I tested the application on Windows 10, I was greeted by a message telling me that the application contains a trojan and wasn't able to launch the application. After a little search, it appears that it's common for Windows Defender AI/Cloud thing to mark every application as such and that the way around this is to submit the application to Microsoft on this page. Is that really the thing to do ? Is there another way around that ?

Edit: version 0.2

10 posts
RSS and Atom feed reader
Hey I work in security, so regarding your last question I think yes you might have just gotten unlucky with Windows Defender. It's a simple application and using a combination of APIs which is maybe found in some malicious executables, so the machine learning or whatever probably triggered.
Looking at it myself, out of context it seems to be doing file deletion, input and clipboard collection, system enumeration etc., in combination with Internet access. And if you compiled it in an unusual way or whatever the 'algorithm' may hold that against you.
Simon Anciaux
1302 posts
RSS and Atom feed reader
Thanks for the reply.

And if you compiled it in an unusual way...

What do you mean by compiling in an unusual way ? I'm compiling from the command line with the following commands:

rc -nologo Y:\rss_reader\cbuild.rc
cl Y:\rss_reader\main.c Y:\rss_reader\cbuild.res -Fefeed.exe -nologo -GR- -EHa- -Oi -fp:fast -WX -W4 -wd4100 -wd4189 -wd4201 -wd4204 -wd4505 -wd4996 -wd4307 -FC -Fm -Zi -diagnostics:caret -diagnostics:column -Od -MTd -DCOMPILER_CL -DDEBUG -D_ASSERT -DWINDOWS -DTARGET_x64 -DLOG -link -INCREMENTAL:NO -opt:ref -subsystem:windows -entry:mainCRTStartup wininet.lib shell32.lib user32.lib OpenGL32.lib GDI32.lib Dwmapi.lib Shlwapi.lib Comdlg32.lib Ole32.lib

Is that considered unusual ?

When I looked into the issue there were people claiming that an empty main function could be marked as trojan, although I think they were talking about another anti-virus (if I remember correctly). I didn't check that (as I'm not often using Windows 10).

...file deletion, input and clipboard collection, system enumeration etc., in combination with Internet access...

I'm doing all of that, using only Windows APIs. I sort of understand the idea that it looks bad without context, but... I'm just using the operating system. The worst thing was that Windows Defender didn't leave me the choice to run the application. Most of the time trying to launch it resulted in nothing happening, and on another computer it deleted the file directly.

Is the only solution to submit the program for review ? I assume the microsoft page will only take care of Windows Defender, so do I need to submit to other anti-virus vendors ?
10 posts
RSS and Atom feed reader
Edited by Halarious on
By unusual I meant for example stripping the CRT, or it may indeed have to do with not having main; anything which is not that commonly done. But these are all guesses and don't really mean anything, just something which may contribute to some AI false labeling it as malware.

Also, your load config table seems to be invalid which may be "suspicious", but I don't know why that would be of the top of my head since you seem to be compiling it quite normally. Some info on it from the MSDN page:

Maybe also enabling /guard:cf and /SDL would somehow lend more legitimacy (both are currently disabled).

Other than that, I'm not sure you can do much which isn't playing the algorithm (e.g. dynamically loading some of the imports to trip machine learning models up). Packing it with something like UPX might be a hack which works, but better solutions usually unpack these so it might not have any impact, but who knows.

For personal use, you can add "Exclusions" in Windows Defender, folders which won't be scanned for malware. It should leave everything in exclusion folders alone.
Simon Anciaux
1302 posts
RSS and Atom feed reader
Edited by Simon Anciaux on
I don't know much about PE headers, but I inspected 6 executables (with this tool, which I don't know so it might not be good) and 3 of them had a config table that was empty except for the Characteristics field, one also had the reserved field set and 2 had no config table at all. So it doesn't seem to be a problem.

Anyway, thanks for the help.
Simon Anciaux
1302 posts
RSS and Atom feed reader
Edited by Simon Anciaux on Reason: Fixed link

Version 0.2 changelog:

  • Fixed an issue with the html parser memory allocator.

Download feed 0.2

Simon Anciaux
1302 posts
RSS and Atom feed reader

Version 0.3 changelog:

  • Added support for youtube feeds.

Download feed 0.3

Simon Anciaux
1302 posts
RSS and Atom feed reader
Edited by Simon Anciaux on

I don't really have a project for the visibility jam, but today I was changing some code in the feed reader while I was looking at performance, and ended up writing some small visualization.

One of my test case is displaying a "big" html page, and I was looking at how much time was spent looking up kerning information for codepoints. Turns out there was about a lot of calls to the kerning function, about 96000 (times 2 but it doesn't matter), so I looked up if a binary search would be faster than the current linear search for that particular function.

The perfs seemed similar in the two cases, with the binary search maybe a tiny bit faster (talking about 200 micro seconds so it doesn't matter). So I then decided to check if the new version of the function was producing the same result as the old one. I wrote this simple code:

data_t output = memory_get_virtual( mebioctet( 10 ), 0 );
for ( umm i = 0; i < set.codepoint_count; i++ ) {
	s32 codepoint = set.codepoints[ i ];
	codepoint_metrics_t* cm = font_get_codepoint_metrics( collection.fonts, codepoint );
	b32 out = false;
	for ( umm j = 0; j < set.codepoint_count; j++ ) {
		s32 kerning = font_get_kerning( collection.fonts, cm, set.codepoints[ j ] );
		if ( kerning ) {
			if ( !out ) {
				string_push_u64( &output, codepoint, 0, 0, 0 );
				memory_push_copy_l( &output, ":\n" );
				out = true;
			memory_push_copy_l( &output, "    " );
			string_push_u64( &output, set.codepoints[ j ], 0, 0, 0 );
			memory_push_copy_l( &output, ", " );
			string_push_s64( &output, kerning, 0, 0, 0 );
			memory_push_copy_l( &output, "\n" );

file_write_entire( string_l( "kern_1.txt" ), output.bytes, output.used, true, &g_file_error );

Which produce this kind of result

    8217, -100
    8221, -100
    65, -100
    198, -100
    8217, -210
    8221, -210
    65, -50
    73, -30
    74, -100
    83, -20
    84, -150
    86, -50
    87, -50
    88, -80
    89, -140
    90, -30
    97, -20
    118, -40
    119, -20
    120, -50
    121, -40
    122, -40
    198, -50
    230, -20
    44, -130
    45, -160
    173, -160
    8211, -120
    8212, -120
    8217, -210
    8221, -210

And they didn't produce the same result. The new version seemed to produce wrong values: most of the original output consist of negative values that are multiples of 10 and I wasn't seeing that in the new version.

So I tried to figure what was wrong and while the process wasn't interesting, it turned out that both version were wrong, and I had been using wrong kerning information for several years !

The codepoint_metrics_t struct contained the offset to use to reach the correct part of the kerning array for that codepoint. I never filled that offset after pushing things in the array, meaning all kerning queries started on the first element of the array (only the first codepoint metrics produced the correct value) and since the number of kerning entries was correct for each codepoint metrics, the search often didn't find the requested codepoint, and when it did, it was likely not the correct value.

After fixing the issue, I took a before and after screenshot and did a difference between the two to see the change. Here is what came up (opening the images in a new tab is a good idea):

Before (wrong) kerning_incorrect.png

After (correct) kerning_correct.png

Animated kerning_anim.gif

Difference kerning_difference.png

That's all for me.