gcc : undefined reference error

A very common compiler error when we try to compile a C++ program using gcc on Linux.

$ gcc new.cc 
/tmp/cccP8Jve.o: In function `main':
new.cc:(.text+0xe): undefined reference to `operator new[](unsigned long)'
new.cc:(.text+0x1c): undefined reference to `std::cout'
...

Fix :

(a) Use g++ : g++ new.cc

(b) gcc -lstdc++ new.cc

Simulating disk-full scenario

Unix-like operating systems provide a number of device files in order to simulate different behaviors. In this article we will focus on simulating a “disk-full” scenario using a special file named /dev/full. Its a special file which always returns an error when an attempt is made to write to this file. Lets try to simulate this through a program :

/* disk-full.c */

#include 
#include 
#include 

int main()
{
  int fd;
  ssize_t rc;
  char *buf= "hello world!";

  // Open /dev/full for writing.
  fd= open("/dev/full", "w");

  if (fd == -1)
    printf("Error! Couldn't open the file. %d : %s\n",
           errno, strerror(errno));

  /* Now, lets try to write into this file. */
  rc= write(fd, buf, 1);

  if (rc == -1)
    printf("Error! Couldn't write to the file. %d : %s\n",
           errno, strerror(errno));

  close(fd);
  return 0;
}

Output :

./a.out 
Error! Couldn't write to the file. 28 : No space left on device

Besides /dev/full, there are other interesting device files available under /dev, which can help in a multitude of ways.

> hexdump -Cn80 /dev/urandom 
00000000  ee 32 7c 62 97 17 79 33  71 20 d5 2e 82 32 cd 32  |.2|b..y3q ...2.2|
00000010  26 02 b4 75 4e 90 5d 2f  fb 7f 58 d8 9b ba 50 34  |&..uN.]/..X...P4|
00000020  f5 30 2a e0 b1 95 ea a4  0c 92 ef 57 99 0e b1 ec  |.0*........W....|
00000030  a5 78 df 45 39 df 17 02  12 c1 0b dd cc d0 e0 ad  |.x.E9...........|
00000040  fd 65 c8 71 25 e7 1d 71  c9 77 1d 2a 57 78 be 1f  |.e.q%..q.w.*Wx..|

Using Valgrind with GDB

Valgrind is a very powerful tool for detecting & diagnosing memory related issues in a C/C++ program. Sometimes, the task of locating the actual problematic area becomes increasingly tedious if the code base is huge and complex.

Let us now try to debug a small program running under Valgrind using GDB.

/* leaky.c */
#include
#include

int main()
{
  char *ptr= malloc(100);
  printf("I am a leaky program!\n");
  return 0;
}

Before we move further, one point to note here is that a process running under Valgrind is actually running on a synthetic CPU provided by Valgrind and hence it cannot be debugged directly using GDB [source]. So, in order to overcome this limitation, Valgrind-3.7.0 introduced ‘gdbserver’, an implementation of GDB remote debugging protocol, using which the process can be debugged.

Step 1 : Start the process under Valgrind with –vgdb=yes & –vgdb-error=0 options

> gcc -g leaky.c

> valgrind --vgdb=yes --vgdb-error=0 ./a.out 
==6148== Memcheck, a memory error detector
==6148== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al.
==6148== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info
==6148== Command: ./a.out
==6148== 
==6148== (action at startup) vgdb me ... 
==6148== 
==6148== TO DEBUG THIS PROCESS USING GDB: start GDB like this
==6148==   /path/to/gdb ./a.out
==6148== and then give GDB the following command
==6148==   target remote | /usr/lib64/valgrind/../../bin/vgdb --pid=6148
==6148== --pid is optional if only one valgrind process is running
==6148==

Step 2 : In a different terminal start GDB

> gdb a.out 
GNU gdb Red Hat Linux (6.5-25.el5rh)
Copyright (C) 2006 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu"...Using host libthread_db library "/lib64/libthread_db.so.1".

Step 3 : In the same gdb session,

(gdb) target remote | /usr/lib64/valgrind/../../bin/vgdb
Remote debugging using | /usr/lib64/valgrind/../../bin/vgdb
relaying data between gdb and process 6148
[New thread 6148]
[Switching to thread 6148]
0x0000003f10000a60 in ?? ()
(gdb) b main
Breakpoint 1 at 0x4004e0: file leaky.c, line 7.
(gdb) c
Continuing.

Breakpoint 1, main () at leaky.c:7
7	  char *ptr= malloc(100);
(gdb)

And step through the code further..

Let’s go

Its been quite some time that I have been using Go, a power-packed programming language with a lot of unconventional constructs. Off the top of my head, I think of the following :

1. The magic behind swap a, b = b, a

func main() {
  a := 1
  b := 2
  c := 3
  d := 4

  d, c, b, a = a, b, c, d
  fmt.Println(a, b, c, d)
}

2. Returning multiple values

func main() {
  a, b, c, d := fn()
  fmt.Println(a, b, c, d)
}

func fn() (a int, b int, c int, d int) {
  return 1, 2, 3, 4
}

3. And, how about this..

func main() {
  串 := "世界您好!"
  fmt.Println(串)
}

Explore more here.