C++ memset / memcpy / strcpy implementation - check for buffer overflows - c++

I have made basic memset / memcpy / strcpy implementations in C++, which work fine. However, is there a way of detecting buffer overflows if I was to do something like this:
Example:
int main()
{
char *buf = (char *)calloc(10, sizeof(char));
__strcpy(buf, "Hello World");
// buffer size: 10, copy size: 12 (including '\0') - overflow
}
Implementations (typedef unsigned int UINT):
void *__memset(void *_Dst, int _Val, UINT _Size)
{
UINT *buf = (UINT *)_Dst;
while (_Size--)
{
*buf++ = (UINT)_Val;
}
return _Dst;
}
void *__memcpy(void *_Dst, const void *_Src, UINT _Size)
{
UINT *buf = (UINT *)_Dst;
UINT *src = (UINT *)_Src;
while (_Size--)
{
*buf++ = *src++;
}
return _Dst;
}
char *__strcpy(char *_Dst, const char *_Src)
{
while ((*_Dst++ = *_Src++) != '\0');
return _Dst;
}

Buffer overflows are not detectable in your program. The operating system is detecting them. You only can check for potential pitfalls in the code (if/else,asserts,exceptions). Or you use profiling tools like valgrind.

You can detect overflows, but only if you also implement your own memory-management routines. We used to do this when we wrote embedded software that ran on devices without a "real" operating system, before there were very many good debugging tools.
The idea is to build your own wrapper around malloc() (and calloc(), in your case), that will allocate a few more bytes than the caller requests. Then set up a few "guard bytes" before and after the memory that was requested and initialize the entire buffer with recognizable data. Also build a wrapper around free() that checks for the guard bytes before releasing the memory and generates an error if they've changed.
#define GUARD_LEN = 4 // Arbitrary number of guard bytes.
#define GUARD_BYTE = 0xA5 // Arbitrary but recognizable: 10100101b
#define UNUSED_BYTE = 0x96 // Arbitrary but recognizable: 10010110b
#define FREED_BYTE = 0xC3 // Arbitrary but recognizable: 11000011b
#define MAX_ALLOCS = 1024 // Max # of malloc'ed buffers.
struct {
void *addr; // Address of malloc'ed buffer
size_t len; // Number of requested bytes
} Allocs[MAX_ALLOCS];
// Allocates and initializes memory.
void *chk_malloc(size_t length) {
// Allocate memory for buffer + guard bytes.
void *mem = malloc(length + 2*GUARD_LEN);
if (mem == NULL) {
return NULL;
}
// Initialize: [GUARD][UNUSED_BUFFER][GUARD]
// Caller's usable memory starts after GUARD.
void *buffer = mem + GUARD_LEN;
memset(mem, GUARD_BYTE, GUARD_LEN);
memset(buffer, UNUSED_BYTE, length);
memset(buffer + length, GUARD_BYTE, GUARD_LEN);
// Remember the address and length.
// Simplified for demonstration; you may want this to be smarter.
for (int i = 0; i < MAX_ALLOCS; ++i) {
if (Allocs[i].addr == NULL) {
Allocs[i].addr = buffer;
Allocs[i].len = length;
return buffer;
}
return NULL; // Should also indicate MAX_ALLOCS is too small.
}
// Checks that buffer is filled with val.
bool chk_filled(void *buffer, char val, size_t len) {
for (int i = 0; i < len; ++i) {
if (buffer[i] != val) {
return false;
}
}
return true;
}
// Checks for over/underrun and releases memory.
void chk_free(void *buffer) {
// Find the buffer in the array of alloc'ed buffers.
for (int i = 0; i < MAX_ALLOCS; ++i) {
if (Allocs[i].addr == buffer) {
void *guard = buffer - GUARD_LEN; // Initial guard bytes.
if (!chk_filled(guard, GUARD_BYTE, GUARD_LEN)) {
// Underrun
}
end_guard = buffer + Allocs[i].len; // Terminal guard bytes.
if (!chk_filled(end_guard, GUARD_BYTE, GUARD_LEN)) {
// Overrun
}
// Mark the buffer as free and release it.
memset(guard, FREED_BYTE, Allocs[i].len + 2*GUARD_LEN);
Allocs[i].addr = -Allocs[i].addr; // See text below.
free(guard);
return;
}
}
// Error: attempt to free unalloc'ed memory.
}
In reality you'd probably want this to be smarter in several ways:
You might not want to have a limit of MAX_ALLOCS.
Check for allocated memory that isn't freed when the program exits.
Print Allocs[] on exit.
Print more information and/or exit immediately when an error is detected.

The safer way to detect buffer overflows is by providing your own implementation of calloc instead. Provide a few bytes padding before and after the returned block, set them to a known value (NOT 0 or 255), and when calling free check that they're untouched. Also, after calling free you should overwrite the whole block (including the padding on both sides) to check for double free calls.

You may need the size of buffer you are owing, which can be used to iterate that many locations to copy checking buffer overflow if any as shown below,
char *__strcpy(char *_Dst, const char *_Src, int size)
{
while ((*_Dst++ = *_Src++) != '\0' && size--); //Iterate/copy to allocated Bytes
return _Dst;
}
int main()
{
int size;
char *buf = (char *)calloc(size, sizeof(char)); // Here you know the size of buf
__strcpy(buf, "Hello World", size); // Send size as parameter
// buffer size: 10, copy size: 12 (including '\0') - overflow
}

All your mem* functions are invalid. They copy (or set) objects of type unsigned int while they have to copy (or set) objects of type unsigned char. Take into account that __Size can be an odd number.
These functions theirself are unable to check buffer overflow without changing their declarations.
Also even the third function is invalid
char *__strcpy(char *_Dst, const char *_Src)
{
while ((*_Dst++ = *_Src++) != '\0');
return _Dst;
}
inside the function pointer _Dst was changed and points to the terminating zero. This address you return from the function while you have to return the address of the first character of the string pointed by _Dst.
The same is valid for the first two functions.

There can be a real C++ implementation, if you use arrays instead of pointers to char. You could define your functions as template and make the array size a template argument.
template < std::size_t D >
char* strcpy( char ( &dest )[ D ], const char* source )
{
assert( D > std::strlen( source ) );
...
}
As you really just need the destination size, I've left the source size out.
int main()
{
char buf[ 10 ];
// would assert, if assertions are enabled.
strcpy( buf, "Hello World" );
}

Related

any wrong I done for using Openssl for calculating HMAC_SHA1 hash value?

int computeHMACSHA1Hash(const char * unhashedcstr, char * hashedcstr, const char * key, int returncode)
{
string hashed;
size_t unhashlength = strlen(unhashedcstr);
char * nonconstunhashcstr = new char[unhashlength];
strcpy_s(nonconstunhashcstr, unhashlength + 1, unhashedcstr);
unsigned char* pixels = reinterpret_cast<unsigned char*>(nonconstunhashcstr);
returncode = 0;
HMAC_CTX* context = HMAC_CTX_new();
size_t unhashedstrlength = sizeof(unhashedcstr);
if (context != NULL)
{
if (HMAC_Init_ex(context, key, strlen(key), EVP_sha1(), NULL))
{
if (HMAC_Update(context, pixels, unhashedstrlength))
{
unsigned char hash[EVP_MAX_MD_SIZE];
unsigned int lengthOfHash = 0;
if (HMAC_Final(context, hash, &lengthOfHash))
{
std::stringstream ss;
for (unsigned int i = 0; i < lengthOfHash; ++i)
{
ss << std::hex << std::setw(2) << std::setfill('0') << (int)hash[i];
}
hashed = ss.str();
size_t outputSize = hashed.length() + 1; // +1 for null terminator
strcpy_s(hashedcstr, outputSize, hashed.c_str());
returncode = 0;
}
else
{
returncode = 7;
}
}
else
{
returncode = 6;
}
}
else
{
returncode = 5;
}
HMAC_CTX_free(context);
}
else
{
returncode = 4;
}
return returncode;
}
int main()
{
const char * unhashedcstr = "a=services&l=v1&p=open&k=SD58292829&i=20200918125249803&n=2124&t=1600404769&f={\"invoiceCode\": \"11111\",\"invoiceNo\": \"2222\",\"inTaxAmount\": \"\",\"exTaxAmount\": \"\"}";
char * hashedcstr = new char[100];
int returncode = 0;
const char * key = "SD886A11B0EE428F";
int result = computeHMACSHA1Hash(unhashedcstr, hashedcstr, key, returncode);
return 0;
}
I tried the code above to calculating the HMAC SHA1 hash value for a content, but compared the results on https://www.freeformatter.com/hmac-generator.html#before-output
it looks like I didn't do it right. I'm not sure what I have done wrong though. Any help would be appreciated.
It turned out the result was "d916b4c2d277319bbf18076c158f0cbcf6c3bc57", while on the website https://www.freeformatter.com/hmac-generator.html#before-output, the result was "71482b292f2b2a47b3eca6dad5e7350566d60963". Even when I tried using the string "a=services&l=v1&p=open&k=SD58292829&i=20200918125249803&n=2124&t=1600404769&f={"invoiceCode": "11111","invoiceNo": "2222","inTaxAmount": "","exTaxAmount": ""}" which removed the escape characters, the result was "09be98b6129c149e685ed57a1d19651a602cda0d". It didn't match the correct one.
Is there anything wrong with my code?
Your hash is calculated over the bytes a=se, which are the first four bytes of the whole input string. Thus, you get d916b4c2d277319bbf18076c158f0cbcf6c3bc57 instead of the 09be98b6129c149e685ed57a1d19651a602cda0d that would correspond to the whole string.
The reason is this:
size_t unhashedstrlength = sizeof(unhashedcstr);
Here, sizeof(unhashedcstr) is the size of the unhashedcstr pointer itself (which is of type const char*), not the size of the null-terminated C-style string this unhashedcstr pointer is pointing to. You are compiling a 32-bit program, so the size of a pointer is 4 bytes. Thus, unhashedstrlength is 4.
To get the length of the C-style string, you can do this instead:
size_t unhashedstrlength = strlen(unhashedcstr);
But just as a comment, in modern C++, you should avoid using raw pointers (such as const char*, char*, unsigned char*), C functions (like strlen(), strcpy_s()) and manual memory management (new / delete and new[] / delete[]). You should prefer to use std::string and/or std::vector<unsigned char> instead, wherever possible. When you need to pass a buffer's address to an API function, you can use std::string::data(), std::vector::data(), or more generally, std::data().
By the way, you currently leak memory: you dynamically allocate buffers using new[], but you never deallocate those (using delete[]). So that memory is released by the OS only after the program exits. This is called a memory leak.

C++ custom-written strncpy without padding all characters to null is it safe?

#include <iostream>
using namespace std;
struct Packet {
int a;
char b[17];
int c;
};
// char* dest has form char dest[n], src has length <= n and is null-terminated
// After the function, dest should satisfy:
// - If strlen(src)==n, dest is not null terminated
// - If strlen(src) < n, dest[n-1] = dest[strlen(src)] = '\0'
static void strncpy_faster(char* dest, const char* src, size_t n) {
size_t i;
for (i = 0; i < n; i++) {
dest[i] = src[i];
if (src[i] == '\0')
break;
}
//while (i < n) {dest[i] = '\0'; i++;} // C standard strncpy do this
if (i < n)
dest[n - 1] = '\0';
}
string charArrayToString(const char* a, size_t n) {
size_t len = 0;
while (len < n && a[len]!='\0') len++;
return std::string(a, a+len);
}
int main()
{
string s = "12341234123412345";
Packet packet;
strncpy_faster(packet.b, s.c_str(), 17);
cout << charArrayToString(packet.b, sizeof(packet.b)) << "\n";
s = "12345";
strncpy_faster(packet.b, s.c_str(), 17);
cout << charArrayToString(packet.b, sizeof(packet.b));
return 0;
}
I'm dealing with struct that have fixed-size char arrays. Let's say I really, really want to keep struct size small (or I need to send them over network), so std::string is not used in my struct (it cost 32 bytes, while I have multiple small char arrays with size 4-20). I have 2 problems with strncpy:
strncpy 2 char array with same length will emit warning about "potentially not having null-terminated character", which is intended, but I don't need that warning.
strncpy pad ALL leftover characters (from dest[strlen(src) -> n-1]) with '\0'. This is a waste of processing in my program.
So, my strncpy_faster only assign up to 2 positions to '\0': the last element of the array, and the position of strlen(src). Since std::string() requires a null-terminated char array (NTCA), I use charArrayToString() to convert non-NTCA to string.
Is this version of strncpy safe? Are there any C/C++ functions that requires strncpy to fill all leftover bytes with '\0', or do they only need a null terminator? I don't know why the standard requires strncpy to zero-out remaining bytes.
Is this version of strncpy safe?
Yes.
It's as safe as strncpy is. So.... not safe.
Are there any C/C++ functions that requires strncpy to fill all leftover bytes with '\0', or do they only need a null terminator?
No function require it.
Notes from Linux man-pages man strcpy:
NOTES
Some programmers consider strncpy() to be inefficient and error
prone. If the programmer knows (i.e., includes code to test!) that
the size of dest is greater than the length of src, then strcpy() can
be used.
One valid (and intended) use of strncpy() is to copy a C string to
a fixed-length buffer while ensuring both that the buffer is not
overflowed and that unused bytes in the destination buffer are zeroed
out (perhaps to prevent information leaks if the buffer is to be
written to media or transmitted to another process via an interprocess
communication technique).
Consider using (and/or implementing) strlcpy. Remember about first rule of optimization.

How to convert the template from C++ to C

I am trying to convert some C++ code to C for my compiler that can't run with C++ code. I'd like to create the template below to C. This template converts the decimal integer to hexadecimal, and adds 0 in front of value if the size of the hexadecimal string is smaller than (sizeof(T)*2). Data type T can be unsigned char, char, short, unsigned short, int, unsigned int, long long, and unsigned long long.
template< typename T > std::string hexify(T i)
{
std::stringbuf buf;
std::ostream os(&buf);
os << std::setfill('0') << std::setw(sizeof(T) * 2)
<< std::hex << i;
std::cout<<"sizeof(T) * 2 = "<<sizeof(T) * 2<<" buf.str() = "<<buf.str()<<" buf.str.c_str() = "<<buf.str().c_str()<<std::endl;
return buf.str().c_str();
}
Thank you for tour help.
Edit 1: I have tried to use the declaration
char * hexify (void data, size_t data_size)
but when I call with the int value int_value:
char * result = hexify(int_value, sizeof(int))
it doesn't work because of:
noncompetitive type (void and int).
So in this case, do I have to use a macro? I haven't tried with macro because it's complicated.
C does not have templates. One solution is to pass the maximum width integer supported (uintmax_t, in Value below) and the size of the original integer (in Size). One routine can use the size to determine the number of digits to print. Another complication is C does not provide C++’s std::string with is automatic memory management. A typical way to handle this in C is for the called function to allocate a buffer and return it to the caller, who is responsible for freeing it when done.
The code below shows a hexify function that does this, and it also shows a Hexify macro that takes a single parameter and passes both its size and its value to the hexify function.
Note that, in C, character constants such as 'A' have type int, not char, so some care is needed in providing the desired size. The code below includes an example for that.
#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
char *hexify(size_t Size, uintmax_t Value)
{
// Allocate space for "0x", 2*Size digits, and a null character.
size_t BufferSize = 2 + 2*Size + 1;
char *Buffer = malloc(BufferSize);
// Ensure a buffer was allocated.
if (!Buffer)
{
fprintf(stderr,
"Error, unable to allocate buffer of %zu bytes in %s.\n",
BufferSize, __func__);
exit(EXIT_FAILURE);
}
// Format the value as "0x" followed by 2*Size hexadecimal digits.
snprintf(Buffer, BufferSize, "0x%0*" PRIxMAX, (int) (2*Size), Value);
return Buffer;
}
/* Provide a macro that passes both the size and the value of its parameter
to the hexify function.
*/
#define Hexify(x) (hexify(sizeof (x), (x)))
int main(void)
{
char *Buffer;
/* Show two examples of using the hexify function with different integer
types. (The examples assume ASCII.)
*/
char x = 'A';
Buffer = hexify(sizeof x, x);
printf("Character '%c' = %s.\n", x, Buffer); // Prints "0x41".
free(Buffer);
int i = 123;
Buffer = hexify(sizeof i, i);
printf("Integer %d = %s.\n", i, Buffer); // Prints "0x00007b".
free(Buffer);
/* Show examples of using the Hexify macro, demonstrating that 'A' is an
int value, not a char value, so it would need to be cast if a char is
desired.
*/
Buffer = Hexify('A');
printf("Character '%c' = %s.\n", 'A', Buffer); // Prints "0x00000041".
free(Buffer);
Buffer = Hexify((char) 'A');
printf("Character '%c' = %s.\n", 'A', Buffer); // Prints "0x41".
free(Buffer);
}
You don't need templates if you step down to raw bits and bytes.
If performance is important, it is also best to roll out the conversion routine by hand, since the string handling functions in C and C++ come with lots of slow overhead. The somewhat well-optimized version would look something like this:
char* hexify_data (char*restrict dst, const char*restrict src, size_t size)
{
const char NIBBLE_LOOKUP[0xF+1] = "0123456789ABCDEF";
char* d = dst;
for(size_t i=0; i<size; i++)
{
size_t byte = size - i - 1; // assuming little endian
*d = NIBBLE_LOOKUP[ (src[byte]&0xF0u)>>4 ];
d++;
*d = NIBBLE_LOOKUP[ (src[byte]&0x0Fu)>>0 ];
d++;
}
*d = '\0';
return dst;
}
This breaks down any passed type byte-by-byte, using a character type. Which is fine, when using character types specifically. It also uses caller allocation for maximum performance. (It can also be made endianess-independent with an extra check per loop.)
We can make the call a bit more convenient with a wrapper macro:
#define hexify(buf, var) hexify_data(buf, (char*)&var, sizeof(var))
Full example:
#include <string.h>
#include <stdint.h>
#include <stdio.h>
#define hexify(buf, var) hexify_data(buf, (char*)&var, sizeof(var))
char* hexify_data (char*restrict dst, const char*restrict src, size_t size)
{
const char NIBBLE_LOOKUP[0xF+1] = "0123456789ABCDEF";
char* d = dst;
for(size_t i=0; i<size; i++)
{
size_t byte = size - i - 1; // assuming little endian
*d = NIBBLE_LOOKUP[ (src[byte]&0xF0u)>>4 ];
d++;
*d = NIBBLE_LOOKUP[ (src[byte]&0x0Fu)>>0 ];
d++;
}
*d = '\0';
return dst;
}
int main (void)
{
char buf[50];
int32_t i32a = 0xABCD;
puts(hexify(buf, i32a));
int32_t i32b = 0xAAAABBBB;
puts(hexify(buf, i32b));
char c = 5;
puts(hexify(buf, c));
uint8_t u8 = 100;
puts(hexify(buf, u8));
}
Output:
0000ABCD
AAAABBBB
05
64
an optional solution is to use format string like printf
note that you can't return pointer to local variable, but you can get the buffer as argument, (here it is without boundaries check).
char* hexify(char* result, const char* format, void* arg)
{
int size = 0;
if(0 == strcmp(format,"%d") || 0 == strcmp(format,"%u"))
{
size=4;
sprintf(result,"%08x",arg);
}
else if(0 == strcmp(format,"%hd") || 0 == strcmp(format,"%hu"))
{
size=2;
sprintf(result,"%04x",arg);
}
else if(0 == strcmp(format,"%hhd")|| 0 == strcmp(format,"%hhu"))
{
size=1;
sprintf(result,"%02x",arg);
}
else if(0 == strcmp(format,"%lld") || 0 == strcmp(format,"%llu") )
{
size=8;
sprintf(result,"%016x",arg);
}
//printf("size=%d", size);
return result;
}
int main()
{
char result[256];
printf("%s", hexify(result,"%hhu", 1));
return 0;
}

Array of bytes into a string of comma separated int

I have an Arduino that controls timers. The settings for timers are stored in byte arrays. I need to convert the arrays to strings to SET a string on an external Redis server.
So, I have many arrays of bytes of different lengths that I need to convert to strings to pass as arguments to a function expecting char[]. I need the values to be separated by commas and terminated with '\0'.
byte timer[4] {1,5,23,120};
byte timer2[6] {0,0,0,0,0,0}
I have succeeded to do it manually for each array using sprintf() like this
char buf[30];
for (int i=0;i<5;i++){ buf[i] = (int) timer[i]; }
sprintf(buf, "%d,%d,%d,%d,%d",timer[0],timer[1],timer[2],timer[3],timer[4]);
That gives me an output string buf: 1,5,23,120
But I have to use a fixed number of 'placeholders' in sprintf().
I would like to come up with a function to which I could pass the name of the array (e.g. timer[]) and that would build a string, probably using a for loop of 'variable lengths' (depending of the particular array to to 'process') and many strcat() functions. I have tried a few ways to do this, none of them making sense to the compiler, nor to me!
Which way should I go looking?
Here is the low tech way you could do it in normal C.
char* toString(byte* bytes, int nbytes)
{
// Has to be static so it doesn't go out of scope at the end of the call.
// You could dynamically allocate memory based on nbytes.
// Size of 128 is arbitrary - pick something you know is big enough.
static char buffer[128];
char* bp = buffer;
*bp = 0; // means return will be valid even if nbytes is 0.
for(int i = 0; i < nbytes; i++)
{
if (i > 0) {
*bp = ','; bp++;
}
// sprintf can have errors, so probably want to check for a +ve
// result.
bp += sprintf(bp, "%d", bytes[i])
}
return buffer;
}
an implementation, assuming that timer is an array (else, size would have to be passed as a parameter) with the special handling of the comma.
Basically, print the integer in a temp buffer, then concatenate to the final buffer. Pepper with commas where needed.
The size of the output buffer isn't tested, mind.
#include <stdio.h>
#include <strings.h>
typedef unsigned char byte;
int main()
{
byte timer[4] = {1,5,23,120};
int i;
char buf[30] = "";
int first_item = 1;
for (i=0;i<sizeof(timer)/sizeof(timer[0]);i++)
{
char t[10];
if (!first_item)
{
strcat(buf,",");
}
first_item = 0;
sprintf(t,"%d",timer[i]);
strcat(buf,t);
}
printf(buf);
}

How to initialize char * in c++ class? (sizeof() always gives 8)

I'm facing some troubles with code for my school. The problem is that I have a char pointer named "contenido" like this:
class Archivo {
public:
Archivo(const char *filename, int banderas);
Archivo(const char *filename, int banderas, mode_t modo);
~Archivo();
size_t lee(size_t nbytes);
size_t escribe(const void *buffer, size_t nbytes);
char *get_contenido();
void cerrar();
protected:
string nombreArchivo;
int fd;
//Problematic char pointer
char *contenido;
};
The code is supposed to be a class implementation of the c functions read(), write() and open(), the specific method where i need to set a new size for my char pointer is size_t lee(size_t nbytes); that i implemented like this:
size_t Archivo::lee(size_t nbytes) {
contenido = new char[nbytes];
cout << "contenido: " << sizeof(contenido) << endl;
nbytes = read(fd, contenido, sizeof(contenido));
return nbytes;
}
In this method, I should receive a new size for "contenido" that in this case, it works as my buffer for the read() function but unfortunately, it doesn't matter which value I use it always returns "8" in the call of sizeof(contenido). I have tried using malloc() in the constructor, using malloc() and then realloc() and as you may see using new char[size_t] but in every single case I receive the same result of "8". I researched about this and in most cases the suggestion was to use std::vector but in this specific case it's necessary to use char * due to the request of my professor. I hope you can help me and thanks in advance.
sizeof(contenido) evaluates to the size of a pointer, which is 8 on your platform.
To restore the contents of a string, you need to use the length of the string as argument to read.
size_t Archivo::lee(size_t nbytes) {
contenido = new char[nbytes];
cout << "contenido: " << sizeof(contenido) << endl;
nbytes = read(fd, contenido, nbytes);
return nbytes;
}
If contenido is supposed to be a null terminated string, you probably need to allocate one more byte for it and make sure to add the terminating null character.
size_t Archivo::lee(size_t nbytes) {
contenido = new char[nbytes+1];
cout << "contenido: " << sizeof(contenido) << endl;
nbytes = read(fd, contenido, nbytpes);
contenido[nbytes] = '\0';
return nbytes;
}
You are calling the sizeof() operator on a pointer, therefore you get the size of the pointer and not the size of content it's pointing to. Pointer in memory is usually like another regular variable (int for example) except it contains an address instead of an actual value. You always get the number 8 probably because your machine is 64 bit, so a pointer should be able to hold any address in the 64 bit space. (8 bytes = 64 bit)
If you want to get the size in bytes of the content (the memory you allocated), you should take the size of char (the type the content is made of) using sizeof() and then multiply that by the number of chars allocated, like so:
sizeof(char)*nbytes