2011年7月28日 星期四

[C++] NULL reference and NULL pointer deference

通常如果function是在接受reference的參數, 不像是pointer 需要去檢查是不是NULL,但是下面這種情況卻會造成segmentation fault.
原因是因為deference NULL pointer (ex: *p) 本身就是未定義行為, 而NULL reference只可能出現在未定義行為的地方.


#include < stdio.h >
struct obj
{
int t;
};

void foo(obj &a)
{
std::cout << a.t;
}

int main()
{
obj *p = NULL;

foo(*p);
return 0;

}

以下的程式就算我把foo裡面的std::cout comment掉, 並且用-O0, 他就不會造成crash, 造理來說*p應該就要crash,
這邊可以看一下輸出的assembly, 就可以理解其實底層實做reference 也是用到pointer, 所以只要沒有真的access NULL pointer, 是不會造成crash


#include <stdio.h>

struct obj
{
int t;
};

void foo(obj &a)
{
}

int main()
{
obj *p = NULL;

foo(*p);
return 0;
}

可以看到main裡面assembly, 他其實也只是把pointer當參數傳進去~


movq $0, -8(%rbp)
movq -8(%rbp), %rax
movq %rax, %rdi
call _Z3fooR3obj

雖然可以透過下面的方式去檢查, 但是我覺得這樣寫很奇怪, 畢竟問題不是在foo function.


#include <stdio.h>

struct obj
{
int t;
};

void foo(obj &a)
{
if( &a == NULL) {
std::cout << "null\n";
return;
}
std::cout << a.t;
}

int main()
{
obj *p = NULL;

foo(*p);
return 0;
}

所以只有caller需要自己去檢查傳進去的pointer是不是NULL

Reference: 
http://stackoverflow.com/questions/4364536/c-null-reference
http://www.nicollet.net/2009/11/can-references-be-null/
http://discuss.fogcreek.com/joelonsoftware/default.asp?cmd=show&ixPost=17154 

2011年7月27日 星期三

[C++] Diffie-Hellman Key Exchange (Client API)

DHKeyCrypt.h


#if !defined(dhkeycrypt_include)

#define dhkeycrypt_include

#include
#include
#include

/*
* Example:
*
* // initial steps
* const char *p, *g, *public_key;
* char *buf;
* int buf_size;
* DHKeyCrypt *key = new DHKeyCrypt(256); // mean generate 256 bits prime
*
* // p, g, public_key will point to the hex representation string
* key->GenerateKey(&p, &g, &public_key);
*
* // use the 3rd party public key to compute session key
* key->ComputeKey(other_pubkey);
*
* // usage
* key->Encode(buf, buf_size); // encode buf
*
*/
class DHKeyCrypt
{
private:
char *m_g[2];
DH *m_dh;
char *m_p;
char *m_pubkey;
unsigned char *m_session_key;

int m_key_len;
int m_gindex;

public:
DHKeyCrypt(int size);
void GenerateKey(const char **p, const char **g, const char **public_key);
int ComputeKey(const char *pubkey_3rd);
void Encode(char *buf, int buf_len);
~DHKeyCrypt();
};

#endif

DHKeyCrypt.cpp


#include "DHKeyCrypt.h"
#include
#include

/*
* generate size bits prime
*/
DHKeyCrypt::DHKeyCrypt(int size) : m_session_key(NULL)
{
m_g[0] = strdup("2");
m_g[1] = strdup("5");
m_gindex = time(NULL) & 1;
m_dh = DH_generate_parameters(size, m_g[m_gindex][0] - '0', NULL, NULL);
DH_generate_key(m_dh);
m_p = BN_bn2hex(m_dh->p);
m_pubkey = BN_bn2hex(m_dh->pub_key);
}

void DHKeyCrypt::GenerateKey(const char **p, const char **g, const char **public_key)
{
*p = m_p;
*g = m_g[m_gindex];
*public_key = m_pubkey;
}

int DHKeyCrypt::ComputeKey(const char *pubkey_3rd)
{
BIGNUM *bn = NULL;

if(!BN_hex2bn(&bn, pubkey_3rd))
return -1;
m_session_key = new (std::nothrow) unsigned char [DH_size(m_dh)];
if(!m_session_key) return -1;
m_key_len = DH_compute_key(m_session_key, bn, m_dh);
if(m_key_len == -1) return -1;
/*
printf("SessionKey: ");
for(int i=0; i < m_key_len; i++)
printf("%02X", m_session_key[i]);
printf("\n");
*/
return 0;
}

void DHKeyCrypt::Encode(char *buf, int buf_len)
{
for(int i=0; i < buf_len; i++)
buf[i] = buf[i] ^ m_session_key[i % m_key_len];
}

DHKeyCrypt::~DHKeyCrypt()
{
OPENSSL_free(m_p);
OPENSSL_free(m_pubkey);
free(m_g[0]);
free(m_g[1]);
delete [] m_session_key;
DH_free(m_dh);
}