0

Recently I've been recoding my own printf function, and with that, unit tests with the Criterion C library.

When I tried testing the %p flag (printing the address of the pointer), I was just stuck there trying to figure out how to predict the memory address I was going to have.

I wasn't sure if I could "extract" it before criterion started the tests and send it in the assert but it seems that there is nothing about pointers, memory addresses or anything related in the docs.

For a nil pointer, I could just predict the result ("nil" string) such as :

Test(my_printf, nil_pointer, .init=cr_redirect_stdout)
{
    char *string = NULL;

    my_printf("This is a nil %p.", string);
    cr_assert_stdout_eq_str("This is a nil (nil).");
}

but for an unknown future memory address, I was just stuck with :

Test(my_printf, pointer_address_1, .init=cr_redirect_stdout)
{
    char *string = "hello world";

    my_printf("valid pointer: %p.", string);
    cr_assert_stdout_eq_str("valid pointer: 0x???????");
}

I would like to know if there is a way to predict / send the address of my pointer into my assert during the test, instead of the question marks.

I don't know if I was very clear, if not please let me know so I can help you understand my issue.

Laurel
  • 5,965
  • 14
  • 31
  • 57
pironc
  • 51
  • 1
  • 9

1 Answers1

0

Why do you want a "real" pointer for this? You can very well craft your own fake pointer, after all, a pointer is just a value. If your implementation is reasonable, your print function really doesn't need to know if the pointer is valid in order to print its value.

Test(my_printf, pointer_address_1, .init=cr_redirect_stdout)
{
    my_printf("pointer: %p", (void *)0x12345678);
    cr_assert_stdout_eq_str("pointer: 0x12345678");
}

If you really want to test with a valid pointer, then you can try using mmap to request a page at a specific address, but this is Linux specific and totally unneeded:

Test(my_printf, pointer_address_1, .init=cr_redirect_stdout)
{
    unsigned char *ptr = mmap(0x12345000, 0x1000, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    if (ptr == MAP_FAILED) {
        // Fail test
    }

    ptr += 0x678;
    my_printf("pointer: %p", ptr);
    cr_assert_stdout_eq_str("pointer: 0x12345678");
}

Note that mmap only takes your requested address as an hint and also only maps whole pages so the last 3 hex digits of the address will always be 000.

Marco Bonelli
  • 63,369
  • 21
  • 118
  • 128
  • Thanks a lot for answering my question. The thing is I'm not very familiar with memory addresses, how it really looks like, the length of it, etc... I just saw that the `%p` flag of `printf` was just printing the string in hexadecimal and that's what I did in my own version, just by using my own `%x` flag and printing `0x` in the beginning, but I was not 100% sure if it was going to be like that every time. I'll play with the `mmap` function more in depth to see how it works, and the same thing for pointers and their memory addresses. – pironc Nov 04 '20 at 11:37
  • @pironc as I said, you **do not** need `mmap`. The real printf of course does not use it, it's kind of insane to use it really. You can just cast the value of the pointer to an integer type (like uintmax_t and then print it in hexadecimal like you would for any other integer). No need to test with valid pointers. – Marco Bonelli Nov 04 '20 at 13:08