Passing values to an function - c

I am missing a fundamental point on passing values.
In my code, I wrote this prototype/function:
void drawFont (char A[],unsigned char length, char x1, char y1, uint16 FGcolor);
I call the function using a call like this:
drawFont ("William",7,15,25,YEL,0);
or
drawFont ("W",1,15,25,YEL,0);
Both of these work fine in the code. If I examine A[0] in the function, I will see a value of '57' representing an ASCII 'W'. All fine and good.
My question/problem is: When I attempt to replicate the 'W' using the ASCII value instead of the string representation, my code fails Example:
drawFont (57,1,15,25,YEL,0);
The value of A[0] in the code is: 0, but the address of A is 57. So somehow the compiler assumes that I want to pass a pointer? I'm confused, why did it pass the string fine, but not the value?
Thanks in advance from a novice C programmer.

If you pass
drawFont (57,1,15,25,YEL,0);
you will be doming the same as
drawFont ('W',1,15,25,YEL,0);
which is just one character. The function requires an array of characters, that's why it's not correct.

The prototype for your function declares that the first parameter is a pointer to a character:
void drawFont (char A[],...);
If you pass an integer, you are breaking the rules. The compiler should warn about it. Mine gives a warning about the following code on the line with func(57):
void func(char a[])
{
}
char arr[] = {87,84,70};
int main()
{
func(57);
func("W");
func(arr);
}
x.c(9) : warning C4047: 'function' : 'char *' differs in levels of indirection from 'int'
x.c(9) : warning C4024: 'func' : different types for formal and actual parameter 1
If you look at the assembly output from the compiler, you can see the problem more clearly (I cut out the uninteresting parts):
PUBLIC _arr
_DATA SEGMENT
_arr DB 057H ;Here's the char array at an address in memory.
DB 054H
DB 046H
ORG $+1
$SG1297 DB 'W', 00H ;Here's the "W" at an address in memory (nul-terminated)
_DATA ENDS
; 9 : func(57);
00003 6a 39 push 57 ; Push 57 as the address, WRONG!
00005 e8 00 00 00 00 call _func
0000a 83 c4 04 add esp, 4
; 10 : func("W");
0000d 68 00 00 00 00 push OFFSET $SG1297 ; Push the address of the string.
00012 e8 00 00 00 00 call _func
00017 83 c4 04 add esp, 4
; 11 : func(arr);
0001a 68 00 00 00 00 push OFFSET _arr ; Push the address of the array.
0001f e8 00 00 00 00 call _func
00024 83 c4 04 add esp, 4
The code is expecting to go to an address to read characters. Who knows what is in address 57.

The value of A[] is actually a pointer, such as &A[0] (you could rewrite the function using char *A instead of char A[]
That is the address of the first slot, not what is stored in it. In the memory location pointed to by the pointer, there exists a value 57. When you write a function with a char array or char pointer parameter, you tell the compiler: I will pass you a memory address. Go to that address and start reading each char (number) until you arrive at the null byte, then stop.
But when you pass literal integer 57 as the argument, that is not a valid pointer to an array of characters. You are missing the level of indirection.
So lets assume your char A[] resides at 0xfeaa0011
In RAM at 0xfeaa0011 -> "William" (or 52, ...)
The correct call to drawFont() actually looks like drawFont(0xfeaa0011, 1, 15, 25, YEL, 0)
So you see replacing the pointer with 57 isn't the same thing.

Your function requires a string ( char[] ) as an argument.
When you pass "William" it is interpreted as a string, that's normal.
When you pass "W" it is also interpreted as a string:
string[2] = { 'W' + 0 } //notice the null byte following your char
That's because you used double-quotes " instead of single-quotes '.
Therefore passing 57 or 'W' is viewed as a single char and not a char[]/string which then gives you an error since your function is expecting a char[] and you gave it a char.

Related

Reading data pointed to by an address

working on my reversing skillset here and I came upon something I thought i understood but I managed to confuse myself.
Working in C mainly
My function returns me an address for the information I want to access.
LRESULT ret = SendMessage(hComboBox, CB_GETITEMDATA, (WPARAM)0 , (LPARAM) 0);
// the exact function doesn't really matter here.
printf("Address: %p\n", ret); // Output is 09437DF8
A dump of this address results in
09437DF8 A0 55 E8 12
This is the address (note endianness) of the data I really want to read.
12e855A0
12 E8 55 A0 - 30 00 3A 00 30 00 33 00 3A 00 32 00 32 00 00 00 - UNICODE "0:03:22"
Now I'm fairly certain this is just basic pointers/referencing/de-referencing but i cant wrap my head what I have to do to read this value pragmatically.
wprintf(L"%s\n", <value at address pointed to by ret>);
// Yes its a null terminated string
// Im working via injected dll, so no access violations
// string is unicode
Perhaps something like this?
#include <stdio.h>
#include <wchar.h>
int main()
{
wchar_t *name = L"UNICODE String";
void **ret = (void **)&name;
wprintf(L"%ls \n", *(wchar_t **)ret);
return 0;
}

UBSan: Store to misaligned address; what is the problem, and should I care

I've been running some code under UBSan, and found an error which I've never seen before:
/usr/include/c++/7/bits/stl_algobase.h:324:8: runtime error: store to misaligned address 0x611000001383 for type 'struct complex', which requires 4 byte alignment
0x611000001383: note: pointer points here
66 46 40 02 00 00 00 00 00 00 00 00 04 01 18 00 08 00 00 00 00 00 00 00 08 00 00 00 00 00 00 00
^
(g++-7.3.0, Ubuntu 18.04, flags -fsanitize=address -fsanitize=undefined)
What does this error mean? Is it truly an error (it is in the standard library, so it can't be too bad, right?), and should I care about it?
You probably use a pointer cast which casts a block of raw memory to a complex*.
Example:
void* raw = getBuffer(); // Made up function which returns a buffer
auto size = *static_cast<uint16_t>*(raw); // Maybe your format says that you got a 2 Byte size in front
auto* array = static_cast<complex*>(raw+sizeof(uint16_t)); // ... and complex numbers after
std::transform(array, array+size, ...); // Pass this into STL
Boom! You got UB.
Why?
The behavior is undefined in the following circumstances: [...]
Conversion between two pointer types produces a result that is incorrectly aligned
[...]
If the resulting pointer is not correctly aligned [68] for the referenced type, the behavior is undefined.
See https://stackoverflow.com/a/46790815/1930508 (where I got these from)
What does it mean?
Every pointer must be aligned to the type it is pointing to. For complex this means an alignment of 4. In short this means that array (from above) must be evenly divisible by 4 (aka array % 4 == 0) Assuming that raw is aligned to 4 bytes you can easily see that array cannot as (raw + 2) % 4 == 2 (because of raw % 4 == 2)
If the size would be a 4-Byte value, then array would have been aligned if (and only if) raw was aligned. Whether this is guaranteed depends on where it comes from.
So yes this is truly an error and may lead to a real bug although not always (depending on moon phase etc. as it is always with UB, see the answer above for details)
And no it is NOT in the STL, it just happens to be detected there because UBSAN watches memory dereferences. So while the actual UB is the static_cast<complex*> it is only detected when reading from that pointer.
You can use export UBSAN_OPTIONS=print_stacktrace=1 prior to executing the program to get a stacktrace and find out where your wrong cast is.
Tip: You only need to check casts. Any struct/type allocated via new is always aligned (and every member inside), unless tricks like "packed structs" are used.

Getting error "The capture file appears to be damaged or corrupt. (pcap: File has 1847605831-byte packet, bigger than maximum of 65535)"

I am getting error when i am trying to dump a packet in pcap file.
{
unsigned char *ofilename = "packet.pcap";
pcap_t *fp;
pcap_dumper_t *dumpfile;
const struct pcap_pkthdr *header;
fp = pcap_open_dead(DLT_RAW,256);
if(fp != NULL)
{
dumpfile = pcap_dump_open(fp, ofilename);
if(dumpfile == NULL)
{
printf("\nError opening output file\n");
return;
}
pcap_dump((u_char *)dumpfile,header,data);
pcap_close(fp);
pcap_dump_close(dumpfile);
}
}
HERE data is a u8 data[256].. its 256 byte data.. which has the packet bytes like this
FF FF FF FF FF FF 00 50 56 A8 11 39 81 00 0F FC 81 00 1F FC 08 06 00 01 08 00 06 04 00 01 00 50 56 A8 11 39 65 2B 01 0A 00 00 00 00 00 00 65 2B
But when i open packet.pcap i am getting "The capture file appears to be damaged or corrupt. (pcap: File has 1847605831-byte packet, bigger than maximum of 65535)"
Could someone pls help me on this whats going wrong
Kindly install "pcapfix" on Linux and run it on the corrupt file as follows
$ pcapfix -d 'file / file path here'
This will fix it.
Try something such as
{
unsigned char *ofilename = "packet.pcap";
pcap_t *fp;
pcap_dumper_t *dumpfile;
struct pcap_pkthdr header;
fp = pcap_open_dead(DLT_RAW,256);
if(fp != NULL)
{
dumpfile = pcap_dump_open(fp, ofilename);
if(dumpfile == NULL)
{
printf("\nError opening output file\n");
return;
}
header.caplen = 256; /* or however many bytes actually contain packet data */
header.len = 256; /* or however many bytes actually contain packet data */
gettimefoday(&header.ts); /* I'm assuming this is on some flavor of UN*X */
pcap_dump((u_char *)dumpfile,&header,data);
pcap_close(fp);
pcap_dump_close(dumpfile);
}
}
For one thing, just because a function takes an argument of type "{something} *", that doesn't mean you should pass to it a variable of type "{something} *". You must pass it a value of type "{something} *", but it must be a valid value, i.e. it must point to something.
An uninitialized variable of type "{something} ``*", which is what you have in your code, doesn't point to anywhere valid.
However, if you declare a variable of type "{something}", rather than "{something} *", you can use the & operator on that variable to get a value of type "{something} *" that points to the variable.
Then, as indicated, you have to give that variable a value if you're passing it to pcap_dump(). You have to set the len and caplen members of a struct pcap_pkthdr; the caplen member must be equal to the actual number bytes of packet data (which might be less than the size of the array if the packet isn't, in your case, exactly 256 bytes long), and the len member must be at least that value; len would only be bigger than caplen if the packet came from a capture done with a "snapshot length" value that discarded everything in the packet past a certain point, which isn't the case here, so len should be equal to caplen.
You probably also want to set the time stamp of the packet; I'm assuming you're running on some form of UN*X here, so you can use gettimeofday() to get the current time. If this is Windows with WinPcap, you'll probably have to do something else.
(header must not be const here, as you have to set it. It doesn't have to be const; it's const in the declaration of pcap_dump(), but that just means that pcap_dump() won't change it, so you can pass it a pointer to something that's const; you don't have to pass it something that'sconst`.)

c get data from BMP

I find myself writing a simple program to extract data from a bmp file. I just got started and I am at one of those WTF moments.
When I run the program and supply this image: http://www.hack4fun.org/h4f/sites/default/files/bindump/lena.bmp
I get the output:
type: 19778
size: 12
res1: 0
res2: 54
offset: 2621440
The actual image size is 786,486 bytes. Why is my code reporting 12 bytes?
The header format specified in,
http://en.wikipedia.org/wiki/BMP_file_format matches my BMP_FILE_HEADER structure. So why is it getting filled with wrong information?
The image file doesn't appear to be corrupt and other images are giving equally wrong outputs. What am I missing?
#include <stdio.h>
#include <stdlib.h>
typedef struct {
unsigned short type;
unsigned int size;
unsigned short res1;
unsigned short res2;
unsigned int offset;
} BMP_FILE_HEADER;
int main (int args, char ** argv) {
char *file_name = argv[1];
FILE *fp = fopen(file_name, "rb");
BMP_FILE_HEADER file_header;
fread(&file_header, sizeof(BMP_FILE_HEADER), 1, fp);
if (file_header.type != 'MB') {
printf("ERROR: not a .bmp");
return 1;
}
printf("type: %i\nsize: %i\nres1: %i\nres2: %i\noffset: %i\n", file_header.type, file_header.size, file_header.res1, file_header.res2, file_header.offset);
fclose(fp);
return 0;
}
Here the header in hex:
0000000 42 4d 36 00 0c 00 00 00 00 00 36 00 00 00 28 00
0000020 00 00 00 02 00 00 00 02 00 00 01 00 18 00 00 00
The length field is the bytes 36 00 0c 00`, which is in intel order; handled as a 32-bit value, it is 0x000c0036 or decimal 786,486 (which matches the saved file size).
Probably your C compiler is aligning each field to a 32-bit boundary. Enable a pack structure option, pragma, or directive.
There are two mistakes I could find in your code.
First mistake: You have to pack the structure to 1, so every type size is exactly the size its meant to be, so the compiler doesn't align it for example in 4 bytes alignment. So in your code, short, instead of being 2 bytes, it was 4 bytes. The trick for this, is using a compiler directive for packing the nearest struct:
#pragma pack(1)
typedef struct {
unsigned short type;
unsigned int size;
unsigned short res1;
unsigned short res2;
unsigned int offset;
} BMP_FILE_HEADER;
Now it should be aligned properly.
The other mistake is in here:
if (file_header.type != 'MB')
You are trying to check a short type, which is 2 bytes, with a char type (using ''), which is 1 byte. Probably the compiler is giving you a warning about that, it's canonical that single quotes contain just 1 character with 1-byte size.
To get this around, you can divide this 2 bytes into 2 1-byte characters, which are known (M and B), and put them together into a word. For example:
if (file_header.type != (('M' << 8) | 'B'))
If you see this expression, this will happen:
'M' (which is 0x4D in ASCII) shifted 8 bits to the left, will result in 0x4D00, now you can just add or or the next character to the right zeroes: 0x4D00 | 0x42 = 0x4D42 (where 0x42 is 'B' in ASCII). Thinking like this, you could just write:
if (file_header.type != 0x4D42)
Then your code should work.

Passing a 256-bit wire to a C function through the Verilog VPI

I have a 256-bit value in Verilog:
reg [255:0] val;
I want to define a system task $foo that calls out to external C using the VPI, so I can call $foo like this:
$foo(val);
Now, in the C definition for the function 'foo', I cannot simply read the argument as an integer (PLI_INT32), because I have too many bits to fit in one of those. But, I can read the argument as a string, which is the same thing as an array of bytes. Here is what I wrote:
static int foo(char *userdata) {
vpiHandle systfref, args_iter, argh;
struct t_vpi_value argval;
PLI_BYTE8 *value;
systfref = vpi_handle(vpiSysTfCall, NULL);
args_iter = vpi_iterate(vpiArgument, systfref);
argval.format = vpiStringVal;
argh = vpi_scan(args_iter);
vpi_get_value(argh, &argval);
value = argval.value.str;
int i;
for (i = 0; i < 32; i++) {
vpi_printf("%.2x ", value[i]);
}
vpi_printf("\n");
vpi_free_object(args_iter);
return 0;
}
As you can see, this code reads the argument as a string and then prints out each character (aka byte) in the string. This works almost perfectly. However, the byte 00 always gets read as 20. For example, if I assign the Verilog reg as follows:
val = 256'h000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f;
And call it using $foo(val), then the C function prints this at simulation time:
VPI: 20 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f
I have tested this with many different values and have found that the byte 00 always gets mapped to 20, no matter where or how many times it appears in val.
Also, note that if I read the value in as a vpiHexStrVal, and print the string, it looks fine.
So, two questions:
Is there a better way to read in my 256-bit value from the Verilog?
What's going on with the 20? Is this a bug? Am I missing something?
Note: I am using Aldec for simulation.
vpiStringVal is used when the value is expected to be ASCII text, in order to get the value as a pointer to a C string. This is useful if you want to use it with C functions that expect a C string, such as printf() with the %s format, fopen(), etc. However, C strings cannot contain the null character (since null is used to terminate C strings), and also cannot represent x or z bits, so this is not a format that should be used if you need to distinguish any possible vector value. It looks like the simulator you are using formats the null character as a space (0x20); other simulators just skip them, but that doesn't help you either. To distinguish any possible vector value use either vpiVectorVal (the most compact representation) or vpiBinStrVal (a binary string with one 0/1/x/z character for each bit).

Resources