New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Non-portable use of va_args #196
Comments
Or perhaps we could have a "strict" mode:
That way you could remove all the compile-time branching from the individual functions, too. |
Invoking C99 makes ioquake3 and forks impossible to compile with MSVC < 2015. |
I understand, that would be a deal breaker. Are you still interested in a conditionally-compiled version (like with |
I would be mildly surprised if you needed 2015 for VA_ARGS. In any case, we don't actually even officially support VS so that shouldn't really be a gate, and requiring 2015 is no bad thing anyway since it's the first compiler they've come up with since the mid 90s that is actually quite good. |
@timangus: No, sorry, to be clear here, the crucial feature from C99 is the compound literal:
The |
Yeah, github seems to have stripped my leading and trailing underscores. Not very helpful. |
TEST_COMMENT "TEST_COMMENT" |
Well that's stupid. |
@timangus: That's markdown, baby :-) |
D'oh. |
By the way, there's a "preview" tab when you write a comment, so you can check before submitting what it will look like. And you can also edit comments if you discover a problem only after submission. :-) |
Yeah, but none of the subsequent comments would make any sense if I edited it now ;). Annnyway, if |
VS2015 community works? that's fine. |
So... would you be interested in a patch along those lines? The key features would be:
We can also keep other code branches around that use the two existing versions of va_arg abuse, both as an alternative for non-C99 compilers and in case someone derives a genuine performance advantage from that. |
Opened the debugger- I observe that every invocations (in Tremulous at least) Also, don't forget about |
Another interesting tidbit: Every instance of |
Here is a tentative change: tkoeppe@9719411 This is just a rough skeleton; it has issues:
|
@tkoeppe I've never seen Let me know if I'm reading this correctly, Assuming this is true have you verified with |
@wtfbbqhax: ish. The compound literal is an lvalue, initialized from the given initializer (which means that array elements that aren't mentioned are zero-intialized. We then take the address of that array. Yes, I do want to take the address of the array rather than decay the array so as to retain a semblance of type safety here; that way we can at least check that the number of array elements is the same everywhere. |
I named |
@zturtleman: OK, sure, my main issue with those macros in the light of this change is that you can't tie the macro value to the function signature easily. That is, I can't generate |
Yeah, it requires additional code changes to actually get more args to (DLL) vmMain now as well. This isn't really much different. |
I updated the commit, it's now: tkoeppe@614848a This one includes changes to the three |
Can you please make the VM_Call require an actual call number i.e., #define VM_Call( VM, CALL, ... ) VM_Call_Impl( VM, CALL, &(int[12]){__VA_ARGS__})
intptr_t QDECL VM_Call_Impl( vm_t *vm, int callnum, int (*arg)[12] ) |
Doesn't that break compatibility with existing DLLs? |
Hm, only if the name mangling includes the function signature. This isn't the case on Linux, but I don't know about Windows. I doubt it, though, because you don't include the signature in |
Sorry, I should of been more specific. I meant when calling |
@wtfbbqhax: Unfortunately no, because you cannot portably have zero variadic arguments in a variadic macro. |
@zturtleman: Yes, you're right. Previously compiled DLLs will pass the arguments as if to an ellipsis, but new client code would treat it as a pointer to the first element of an array, and that would break. So this change would require recompiling DLLs. |
Rocket Arena 3 uses a game DLL with no source release so it can't be recompiled. It seems like a bad idea to change the DLL-VM API in general. |
OK, so we should leave the DLLs alone then. Are you still interested in the change to |
(Note that DeepMind Lab uses the C99 compound literal: https://github.com/deepmind/lab/blob/master/engine/code/qcommon/qcommon.h#L369) |
Presumably they're using MSVC 2015/17 rather than mingw/make or extremely old msvc |
No, neither, we're using Clang and GCC only -- I just wanted to show how the proposed change looks in a real fork. |
Any progress on this? QuakeJS -s SAFE_HEAP=1 errors out on this kind of stuff. I don't mind only supporting mods with source/reverse engineering just to recompile if someone can point me towards a good implementation like Daemon or or one of the other off-shoots? |
The
VM_Call
function invm.c
currently uses variable arguments in a very awkward fashion in order to fake "default arguments" for function parameters:va_arg(ap, int)
is called 12 times unconditionally, independent of how the function was actually called.This has undefined behaviour and is not portable. It will typically read outside the stack frame and throw off memory analysers.
I'm not sure how to solve this in C89, but if you are willing to require C99, this could be solved with a compound literal:
What do you think of such a change?
The text was updated successfully, but these errors were encountered: