<story><title>Kirc – A tiny IRC client written in POSIX C99</title><url>https://github.com/mcpcpc/kirc</url></story><parent_chain><item><author>stingraycharles</author><text>&amp;gt; malloc() return isn&amp;#x27;t checked&lt;p&gt;small digression, but I thought that at least on Linux, malloc() never returns an error because the actual allocation happens lazily, when the memory is first used?</text></item><item><author>knorker</author><text>A little sloppy with the error handling, but pretty neat.&lt;p&gt;E.g. log_append() doesn&amp;#x27;t check fopen return value, malloc() return isn&amp;#x27;t checked, and a write() can return a partial write, thus needs a loop. fcntl().&lt;p&gt;Also write() should check for EINTR&amp;amp;EAGAIN.&lt;p&gt;And also there&amp;#x27;s no handling for nonblocking write.&lt;p&gt;If the user types too much while the network glitches it seems that this could cause the client to exit().&lt;p&gt;Probably the correct way is to not read from stdin unless poll() returns that writing to the socket is safe, and vice versa.&lt;p&gt;connect() errors should print where they failed to connect.&lt;p&gt;And:
   $ .&amp;#x2F;kirc 
   Nick not specified: Success&lt;p&gt;And in my first test I got:
   Write to socket: Resource temporarily unavailable&lt;p&gt;And I see a lot of NULL pointers being printed when I connect to e.g. freenode.&lt;p&gt;And so on, and so on…&lt;p&gt;For these things I recommend re-reading the manpage for every libc and syscall you call, and check how they can fail, and consider how you can handle that failure.&lt;p&gt;307 lines of pure C is a pretty neat minimal actually usable client, so I&amp;#x27;m not saying it&amp;#x27;s not well done. But that thing about &amp;quot;… and do it well&amp;quot; (from the readme) means doing all of the above.&lt;p&gt;The problem, of course, is that fixing these problems &lt;i&gt;well&lt;/i&gt; is &amp;quot;the other 90% of the work&amp;quot;, especially when coding in C.&lt;p&gt;And this is the main reason I avoid C when I can. You can&amp;#x27;t just call &amp;quot;write()&amp;quot;. You have to write a 5-10 line wrapper function, and then all callers need a few lines of error handling. And so it goes for everything, until your program is no longer the nice 300 line neat thing you can almost write from memory.&lt;p&gt;So it&amp;#x27;s a good start. But it&amp;#x27;s pretty fragile in its current form.</text></item></parent_chain><comment><author>fulafel</author><text>Cases where memory allocations fail on linux include: hitting memory resource limits (ulimit), overcommit behaviour is set to stricter than the default via sysctl, kernel heuristics with the default overcommit settings end up failing allocation, container &amp;#x2F; cgroups limits, 32-bit virtual address space is exhausted - i&amp;#x27;m sure there are more.&lt;p&gt;The default overcommit-within-reason algorithm is designed to deny allocations that are obviously unrealistic I think.&lt;p&gt;Using semi conservative ulimit settings is pretty common in interactive use to catch runaway &amp;#x2F; swapped to death situations.</text></comment>
<story><title>Kirc – A tiny IRC client written in POSIX C99</title><url>https://github.com/mcpcpc/kirc</url></story><parent_chain><item><author>stingraycharles</author><text>&amp;gt; malloc() return isn&amp;#x27;t checked&lt;p&gt;small digression, but I thought that at least on Linux, malloc() never returns an error because the actual allocation happens lazily, when the memory is first used?</text></item><item><author>knorker</author><text>A little sloppy with the error handling, but pretty neat.&lt;p&gt;E.g. log_append() doesn&amp;#x27;t check fopen return value, malloc() return isn&amp;#x27;t checked, and a write() can return a partial write, thus needs a loop. fcntl().&lt;p&gt;Also write() should check for EINTR&amp;amp;EAGAIN.&lt;p&gt;And also there&amp;#x27;s no handling for nonblocking write.&lt;p&gt;If the user types too much while the network glitches it seems that this could cause the client to exit().&lt;p&gt;Probably the correct way is to not read from stdin unless poll() returns that writing to the socket is safe, and vice versa.&lt;p&gt;connect() errors should print where they failed to connect.&lt;p&gt;And:
   $ .&amp;#x2F;kirc 
   Nick not specified: Success&lt;p&gt;And in my first test I got:
   Write to socket: Resource temporarily unavailable&lt;p&gt;And I see a lot of NULL pointers being printed when I connect to e.g. freenode.&lt;p&gt;And so on, and so on…&lt;p&gt;For these things I recommend re-reading the manpage for every libc and syscall you call, and check how they can fail, and consider how you can handle that failure.&lt;p&gt;307 lines of pure C is a pretty neat minimal actually usable client, so I&amp;#x27;m not saying it&amp;#x27;s not well done. But that thing about &amp;quot;… and do it well&amp;quot; (from the readme) means doing all of the above.&lt;p&gt;The problem, of course, is that fixing these problems &lt;i&gt;well&lt;/i&gt; is &amp;quot;the other 90% of the work&amp;quot;, especially when coding in C.&lt;p&gt;And this is the main reason I avoid C when I can. You can&amp;#x27;t just call &amp;quot;write()&amp;quot;. You have to write a 5-10 line wrapper function, and then all callers need a few lines of error handling. And so it goes for everything, until your program is no longer the nice 300 line neat thing you can almost write from memory.&lt;p&gt;So it&amp;#x27;s a good start. But it&amp;#x27;s pretty fragile in its current form.</text></item></parent_chain><comment><author>simias</author><text>It&amp;#x27;s sloppy coding and not portable. If you really don&amp;#x27;t want to check for malloc() return value because you consider that it shouldn&amp;#x27;t fail (or that you won&amp;#x27;t be able to recover from it anyway) just implement an xmalloc() that just aborts on failure and do that. At least it&amp;#x27;ll crash &amp;quot;cleanly&amp;quot; this way.</text></comment>