Problem calling DX12 functions in a program compiled with clang in c11 - c

For the sake of learning, I am trying to correctly call the DirectX12 APIs using clang in pure c11. I managed to get everything to compile, but sometimes the vtable pointers seem to get corrupted and change where they point when they shouldn't be.
ID3D12DeviceVtbl* tbl; //tracking the vtable pointer for debugging purposes
D3D_FEATURE_LEVEL featureLevel = D3D_FEATURE_LEVEL_11_0;
if (D3D12CreateDevice(NULL, featureLevel, &IID_ID3D12Device, (void**)&g_pd3dDevice) != S_OK)
{
return false;
}
{
tbl = g_pd3dDevice->lpVtbl;
D3D12_DESCRIPTOR_HEAP_DESC desc ;
desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
desc.NumDescriptors = NUM_BACK_BUFFERS;
desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
desc.NodeMask = 1;
// works fine
if (g_pd3dDevice->lpVtbl->CreateDescriptorHeap(g_pd3dDevice,&desc, &IID_ID3D12DescriptorHeap, (void**)&g_pd3dRtvDescHeap) != S_OK)
return false;
// works fine
SIZE_T rtvDescriptorSize = g_pd3dDevice->lpVtbl->GetDescriptorHandleIncrementSize(g_pd3dDevice,D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
// works fine
D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = g_pd3dRtvDescHeap->lpVtbl->GetCPUDescriptorHandleForHeapStart(g_pd3dRtvDescHeap);
// after the line above executes, g_pd3dDevice->lpVtbl now points to somewhere new and invalid
}
{
D3D12_DESCRIPTOR_HEAP_DESC desc ;
desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
desc.NumDescriptors = 1;
desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
// g_pd3dDevice->lpVtbl can't find CreateDescriptorHeap
if (g_pd3dDevice->lpVtbl->CreateDescriptorHeap(g_pd3dDevice,&desc, &IID_ID3D12DescriptorHeap, (void**)&g_pd3dSrvDescHeap) != S_OK)
{
return false;
}
// tbl->CreateDescriptorHeap is still a valid pointer however.
}
As explaining in the comments, after the line D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = g_pd3dRtvDescHeap->lpVtbl->GetCPUDescriptorHandleForHeapStart(g_pd3dRtvDescHeap); the g_pd3dDevice->lpVtbl pointer changes and points somewhere invalid and I don't understand why.
I am compiling with the following options:
clang.exe -std=c11 -pedantic-errors -g -D CINTERFACE .\main.c

You are hitting a known bug in the C-bindings... See this thread which explains there's a bug with GetCPUDescriptorHandleForHeapStart.
There were similar issues with the C-bindings with Direct3D9Ex. The basic issue is that almost all users use C++ for DirectX since it naturally maps to COM. The C bindings are mostly automatically generated; they are not well tested or maintained.

Related

Issues using realloc (old size)

I'm trying to use realloc function in C, to dynamically operate on a char array of strings (char**).
I usually get a realloc():invalid old size error after 41st cicle of the for loop and I really can't understand why.
So, thanks to everyone who will help me ^-^
[EDIT] I'm trying to make the post more clear and following your advices, as a "new active member" of this community, so thank you all!
typedef struct _WordsOfInterest { // this is in an header file containing just
char **saved; // the struct and libraries
int index;
} wordsOfInterest;
int main() {
char *token1, *token2, *save1 = NULL, file[LEN], *temp, *word, **tokenArr;
int n=0, ch,ch2, flag=0, size, init=0,position,currEdit,init2=0,tempEdit,size_arr=LEN,
oldIndex=0,totalIndex=0,*editArr,counterTok=0;
wordsOfInterest toPrint;
char **final;
toPrint.index = 0;
toPrint.saved = malloc(sizeof(char*)*LEN);
editArr = malloc(sizeof(int)*LEN);
tokenArr = malloc(sizeof(char*)*LEN);
final = malloc(sizeof(char*)*1);
// external for loop
for(...) {
tokenArr[counterTok] = token1;
// internal while loop
while(...) {
// some code here surely not involved in the issue
} else {
if(init2 == 0) {
currEdit = config(token1,token2);
toPrint.saved[toPrint.index] = token2;
toPrint.index++;
init2 = 1;
} else {
if((abs((int)strlen(token1)-(int)strlen(token2)))<=currEdit) {
if((tempEdit = config(token1,token2)) == currEdit) {
toPrint.saved[toPrint.index] = token2;
toPrint.index++;
if(toPrint.index == size_arr-1) {
size_arr = size_arr*2;
toPrint.saved = realloc(toPrint.saved, size_arr);
}
} else if((tempEdit = config(token1,token2))<currEdit) {
freeArr(toPrint, size_arr);
toPrint.saved[toPrint.index] = token2;
toPrint.index++;
currEdit = tempEdit;
}
}
}
flag = 0;
word = NULL;
temp = NULL;
freeArr(toPrint, size_arr);
}
}
editArr[counterTok] = currEdit;
init2 = 0;
totalIndex = totalIndex + toPrint.index + 1;
final = realloc(final, (sizeof(char*)*totalIndex));
uniteArr(toPrint, final, oldIndex);
oldIndex = toPrint.index;
freeArr(toPrint,size_arr);
fseek(fp2,0,SEEK_SET);
counterTok++;
}
You start with final uninitialized.
char **final;
change it to:
char **final = NULL;
Even if you are starting with no allocation, it needs a valid value (e.g. NULL) because if you don't initialize a local variable to NULL, it gets garbage, and realloc() will think it is reallocating a valid chunk of memory and will fail into Undefined Behaviour. This is probably your problem, but as you have eliminated a lot of code in between the declaration and the first usage of realloc, whe cannot guess what is happening here.
Anyway, if you have indeed initialized it, I cannot say, as you have hidden part of the code, unlistening the recommendation of How to create a Minimal, Reproducible Example
.
There are several reasons (mostly explained there) to provide a full but m inimal, out of the box, failing code. This allows us to test that code without having to provide (and probably solving, all or part) the neccesary code to make it run. If you only post a concept, you cannot expect from us complete, full running, and tested code, degrading strongly the quality of SO answers.
This means you have work to do before posting, not just eliminating what you think is not worth mentioning.
You need to build a sample that, with minimum code, shows the actual behaviour you see (a nonworking complete program) This means eliminating everything that is not related to the problem.
You need (and this is by far more important) to, before sending the code, to test it at your site, and see that it behaves as you see at home. There are many examples that, when eliminated the unrelated code, don't show the commented behaviour.
...and then, without touching anymore the code, send it as is. Many times we see code that has been touched before sending, and the problem dissapeared.
If we need to build a program, we will probably do it with many other mistakes, but not yours, and this desvirtuates the purpose of this forum.
Finally, sorry for the flame.... but it is necessary to make people read the rules.

Pass array to Julia binary code in a similar way as in C/C++

(I am editing my initial post to add some more information)
I have recently moved to Julia because of its nice ability to create a binary out of the code.
While I followed this documentation I managed to create a binary.
Now, my intention is to pass an array to this binary. As it is mentioned in the documentation, one can pass arguments by using the global variable ARGS.
I am not sure how this could help in getting/returning an array.
To be more specific, I would like to:
write my algorithm in Julia (which gets an array, it does some calculations and returns a new array)
do the precompile
create the sysimage
create the shared library
and then call it in a similar way as in the documentation
EDIT: While the above seemed to be quite tricky, I thought I could follow the example here but simply creating my own module. That didn't work.
Here is what I tried:
I created the "my_test.jl"
module my_test
export real_main
export julia_main
function real_main(x::Float64, y::Float64)
println("from main " , x, " " , y)
end
Base.#ccallable function julia_main(x::Float64, y::Float64)::Cint
try
real_main(x,y)
return 0
catch
Base.invokelatest(Base.display_error, Base.catch_stack())
return 1
end
return 0
end
if abspath(PROGRAM_FILE) == #__FILE__
julia_main(3.,4.)
end
end
then I precompiled it, by using:
julia --startup-file=no --trace-compile=app_precompile.jl my_test.jl
Once the pre-compilation was successful, I created the create_sysimage.jl:
Base.init_depot_path()
Base.init_load_path()
#eval Module() begin
Base.include(#__MODULE__, "my_test.jl")
for (pkgid, mod) in Base.loaded_modules
if !(pkgid.name in ("Main", "Core", "Base"))
eval(#__MODULE__, :(const $(Symbol(mod)) = $mod))
end
end
for statement in readlines("app_precompile.jl")
try
Base.include_string(#__MODULE__, statement)
catch
# See julia issue #28808
Core.println("failed to compile statement: ", statement)
end
end
end # module
empty!(LOAD_PATH)
empty!(DEPOT_PATH)
Then, I built the shared library based on that image, in 2 steps:
julia --startup-file=no -J"$JULIA_DIR/lib/julia/sys.so" --output-o sys.o create_sysimage.jl
gcc -g -shared -o libsys.so -Wl,--whole-archive sys.o -Wl,--no-whole-archive -L"$JULIA_DIR/lib" -ljulia
Once this succeeds, I created the cpp file to use the library above. Therefore, my_test.cpp:
#include <julia.h>
JULIA_DEFINE_FAST_TLS()
int main()
{
libsupport_init();
jl_options.use_compiled_modules = JL_OPTIONS_USE_COMPILED_MODULES_YES;
jl_options.image_file = JULIAC_PROGRAM_LIBNAME;
jl_options.image_file_specified = 1;
jl_init_with_image(NULL,JULIAC_PROGRAM_LIBNAME);
//Enabling the below gives a better explanation of te failure
/*
jl_eval_string("using Main.my_test.jl");
if (jl_exception_occurred()) {
jl_call2(jl_get_function(jl_base_module, "showerror"),
jl_stderr_obj(),
jl_exception_occurred());
jl_printf(jl_stderr_stream(), "\n");
jl_atexit_hook(2);
exit(2);
}
jl_module_t* LA = (jl_module_t *)jl_eval_string("Main.my_test");
if (jl_exception_occurred()) {
jl_call2(jl_get_function(jl_base_module, "showerror"),
jl_stderr_obj(),
jl_exception_occurred());
jl_printf(jl_stderr_stream(), "\n");
jl_atexit_hook(3);
exit(3);
}
*/
jl_function_t *func1 = jl_get_function(jl_main_module, "julia_main");
if (jl_exception_occurred()) {
jl_call2(jl_get_function(jl_base_module, "showerror"),
jl_stderr_obj(),
jl_exception_occurred());
jl_printf(jl_stderr_stream(), "\n");
jl_atexit_hook(4);
exit(4);
}
jl_value_t* in1 = jl_box_float64(12.);
jl_value_t* in2 = jl_box_float64(24.);
jl_value_t* ret = NULL;
JL_GC_PUSH3(&in1,&in2,&ret);
ret = jl_call2(func1, in1, in2);
JL_GC_POP();
jl_atexit_hook(0);
}
And then compile it, as:
g++ -o pass_2_arrays_to_my_test_by_eval -fPIC -I$JULIA_DIR/include/julia -L$JULIA_DIR/lib -ljulia -L$CURRENT_FOLDER -lsys pass_2_arrays_to_my_test_by_eval.cpp $JULIA_DIR/lib/julia/libstdc++.so.6
The JULIA_DIR points to the Julia's installation directory and CURRENT_FOLDER points to the current working dir.
Calling the pass_2_arrays_to_my_test_by_eval fails with Segmentation Fault message.
To my understanding, it fails because it cannot load the module (you can see that if un-comment some lines in the cpp code).
Could someone give some help on that?
Some people in the past seem to do that without any issue (as here).
Thanks a lot in advance!

Warning 'return' with no value, in function returning non-void - What should it return?

How do I solve the following throwing the warning in the title?
struct Nodes* InsertNode(unsigned int IP, unsigned short Port)
{
if (!IP)
return;
if (!Port)
return;
// Above is what chucks the warnings
{
// do stuff & conditionally
return &List[x];
}
// Different conditions & stuff
{
return &List[Other];
}
}
In other words, in the case of giving up through missing data, what should it return? Or do I need to trawl through the entire body of code and have checks every time to see if it should be called or not? The program functions as intended just returning at that point, if I'm to continue using it (or upgrade the OS it's running on), fixing compiler warnings seems like a good idea, they tend to turn into errors when compiler versions get bumped.
There's a clue in this answer which answers someone asking about the same warning, the answer doesn't give me quite enough info to proceed though, nor do the other's I've read.
Extra information: The check on the values of IP & Port are there to sanitize the content of &List, such cases indicate datagrams from misconfigured clients or traffic from persons with malicious intent, sad but it happens. It's invalid data we don't care about at all, logging it seems pointless, it shouldn't delay processing the next one, and absolutely not halt the program. Until the switch from gcc 4.9 to 6.3 I didn't see a warning. The current return; appears to simply black-hole it, but I only understand bits of the code's intent.
in the case of giving up through missing data, what should it return?
As often it depends.
There are several scenarios
The function is not designed to return NULL as a valid value.
Replace
if (!IP)
return;
if (!Port)
return;
by
if (!IP || !Port)
{
errno = EINVAL; /* Setting errno, allows the caller to log
the failure using the perror() function. */
return NULL;
}
Use it like this:
struct Nodes * p = InsertNode (...);
if (NULL == p)
{
perror("InsertNode() failed");
/* exit or error logging/handling */
}
IP and Port will never be 0 under normal operation. So if they were it would be a programming mistake.
In those cases you probably no don't return but end the program.
So instead of
if (!IP)
return;
if (!Port)
return;
use
assert((IP) && (Port));
No specific usage necessary here as the program would simply end if the assertion isn't met.
Please note that this approach requires extensive testing as the test will typically be removed in a production/release build!
The function may return NULL as valid value and IP and/or Port may be 0 under normal operation.
Redesign the function to in one way or the other return a separate error status.
This can generally be done in two ways:
Use the function's return value and pass back the result via a pointer being passed as parameter
int InsertNode(unsigned int IP, unsigned short Port, struct Nodes** ppresult)
{
int error_state = 0;
if (!IP || !Port || !ppresult)
{
errno = EINVAL; /* Setting errno, allows the caller to log
the failure using the perror() function. */
error_state = -1;
}
else
{
if (...)
{
*ppresult = &List[x];
}
...
}
return error_state;
}
Use it like this:
struct Nodes * p;
if (-1 == InsertNode (..., &p))
{
perror("InsertNode() failed");
/* exit or error logging/handling */
}
Pass back the error state result via a pointer being passed as parameter
struct Nodes * InsertNode(unsigned int IP, unsigned short Port, int * perror_state)
{
int error_state = 0;
if (!IP || !Port || !perror_state)
{
errno = EINVAL; /* Setting errno, allows the caller to log
the failure using the perror() function. */
error_state = -1;
}
else
{
if (...)
{
*ppresult = &List[x];
}
...
}
*perror_state = error_state;
return NULL;
}
Use it like this:
int result;
struct Nodes * p = InsertNode (..., &result))
if (-1 == result)
{
perror("InsertNode() failed");
/* exit or error logging/handling */
}
TLDR
"Until the switch from gcc 4.9 to 6.3 I didn't see a warning." Try compiling with gcc -std=gnu90 to compile under similar conditions to those that worked before, when you were using gcc 4.9.
OK, I'm Listening
The reason that you see compiler warnings after changing compilers from gcc 4.9 to gcc 6.3 is that gcc 4.9 defaulted to C90 (really the gnu90 dialect of C90), but by gcc 5.5 the default was C11 (really gnu11).
The C90 Standard says in the Constraints section about the return statement that (C90 §6.6.6.4):
A return statement with an expression shall not appear in a function whose return type is void.
But the same Constraints section from the C11 Standard saysC11 §6.8.6.4:
A return statement with an expression shall not appear in a function whose return type is void. A return statement without an expression shall only appear in a function whose return type is void.
Now, the compiler must produce a diagnostic message for any constraint violation (§5.1.1.3). No constraint was violated when your code was compiled under C90, but the change to a more recent compiler means that the code now compiles under C11, where there is a constraint violation, hence the warning.
One option would be to simply compile with gcc -std=gnu90, allowing the code to be compiled using the same dialect of C you used before, even on the more recent compilers.
But, also note that the original code may have had undefined behavior, since (C90 §6.6.6.4):
If a return statement with an expression is executed, and the value of the function call is used by the caller, the behavior is undefined.
If the value returned by InsertNode() is used by the caller, and the return; statement is encountered in the function call, you have undefined behavior. The best choice would be to look at all of the calls to InsertNode() to see how they handle the return values. It is possible that return; is a typo, and that the code already handles returned null pointers, in which case changing to return NULL; would be all that is needed to fix the code. If the code does not already handle null pointers, #alk has provided several options for fixing the code.

nrf51 timer driver code bugs

I'm currently trying to make an application using the nrf51 development kit & I'm trying to use the timer driver, when I induled the C & H files of the driver I got some error :
static const nrf_drv_timer_config_t m_default_config[] = {// here it told me there is error #1
#if (TIMER0_ENABLED == 1)
NRF_DRV_TIMER_DEFAULT_CONFIG(0),
#endif
#if (TIMER1_ENABLED == 1)
NRF_DRV_TIMER_DEFAULT_CONFIG(1),
#endif
#if (TIMER2_ENABLED == 1)
NRF_DRV_TIMER_DEFAULT_CONFIG(2)
#endif
};
// here it told me there is error #2
ret_code_t nrf_drv_timer_init(nrf_drv_timer_t const * const p_instance,
nrf_drv_timer_config_t const * p_config,
nrf_timer_event_handler_t timer_event_handler)
{
ASSERT((p_instance->instance_id) < TIMER_INSTANCE_NUMBER);
ASSERT(TIMER_IS_BIT_WIDTH_VALID(p_instance->instance_id, p_config->bit_width));
if (m_cb[p_instance->instance_id].state != NRF_DRV_STATE_UNINITIALIZED)
{
return NRF_ERROR_INVALID_STATE; // timer already initialized
}
if (p_config == NULL)
{
p_config = &m_default_config[p_instance->instance_id];
}
#ifdef SOFTDEVICE_PRESENT
if (p_instance->p_reg == NRF_TIMER0)
{
return NRF_ERROR_INVALID_PARAM;
}
#endif
nrf_drv_common_irq_enable(p_instance->irq, p_config->interrupt_priority);
mp_contexts[p_instance->instance_id] = p_config->p_context;
if (timer_event_handler != NULL)
{
m_timer_event_handlers[p_instance->instance_id] = timer_event_handler;
}
else
{
return NRF_ERROR_INVALID_PARAM;
}
nrf_timer_mode_set(p_instance->p_reg, p_config->mode);
nrf_timer_bit_width_set(p_instance->p_reg, p_config->bit_width);
nrf_timer_frequency_set(p_instance->p_reg, p_config->frequency);
m_cb[p_instance->instance_id].state = NRF_DRV_STATE_INITIALIZED;
return NRF_SUCCESS;
}
the error #1 says that "an empty initializer is invalid for an array with unspecified bound"
the error #2 says that it expected an expression
I till now didn't use any of these functions in the main.c code, I'm just added the header files that will be used further.
Error 1: Apparently neither of TIMERx_ENABLED is 1, so the array will be empty. As it is const, there is no chance to initialize it later. That would also result in an array of zero elements, which is not allowed. Easiest might be to have an #else clause with a single null entry. However, I suspect you have to configure the stuff for your system first. Read the documentation.
Error 2: might be a follow up error, or one of the custom types are not defined - hard to say without more info, or the location the error is reported is simply not that of the actual error, or ... . Best is to fix the first error, then try again for error 2.
If you are using examples from nordic then the defines are either in nrf_drv_config.h or in the sdk_config.h for new versions of the nordic sdk.
You have to enable the timers by changing the TIMER_ENABLED define to 1. Then do the same for the timers you want to use.
You could make these defines yourself as other people have suggested.

Where is the implementation of dm_task_create in cryptsetup?

Where is the implementation of the function dm_task_create in cryptsetup (and other dm_task_ related functions)? Grepping for this function in the source for cryptsetup I come up with nothing. I see it is used in lib/libdevmapper.c and that it has a function prototype in libdevmapper.h. However where is the implementation? As a side note, cryptsetup compiles fine and executes.
Just to check, I grepped through the kernel source as well but it doesn't appear to be implemented in the kernel either.
From the following link http://www.saout.de/pipermail/dm-crypt/2009-December/000464.html it appears that at least in the past it was implemented in libdevmapper.c.
It's implemented in libdm-common.c, which is part of libdm (lib device-mapper). It is not implemented as part of cryptsetup itself.
This code is maintained alongside LVM2, as documented on this page:
The userspace code (dmsetup and libdevmapper) is now maintained
alongside the LVM2 source available from
http://sources.redhat.com/lvm2/. To build / install it without LVM2
use 'make device-mapper' / 'make device-mapper_install'.
Here's the implementation:
struct dm_task *dm_task_create(int type)
{
struct dm_task *dmt = dm_zalloc(sizeof(*dmt));
if (!dmt) {
log_error("dm_task_create: malloc(%" PRIsize_t ") failed",
sizeof(*dmt));
return NULL;
}
if (!dm_check_version()) {
dm_free(dmt);
return_NULL;
}
dmt->type = type;
dmt->minor = -1;
dmt->major = -1;
dmt->allow_default_major_fallback = 1;
dmt->uid = DM_DEVICE_UID;
dmt->gid = DM_DEVICE_GID;
dmt->mode = DM_DEVICE_MODE;
dmt->no_open_count = 0;
dmt->read_ahead = DM_READ_AHEAD_AUTO;
dmt->read_ahead_flags = 0;
dmt->event_nr = 0;
dmt->cookie_set = 0;
dmt->query_inactive_table = 0;
dmt->new_uuid = 0;
dmt->secure_data = 0;
return dmt;
}

Resources