Skip to content
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

Switch int and uint to intptr_t and uintptr_t respectively, or define cintptr_t/cuintptr_t types #24613

Open
arnetheduck opened this issue Jan 11, 2025 · 8 comments

Comments

@arnetheduck
Copy link
Contributor

Summary

Make these stdint types available to nim programs for importc / exportc needs

Description

In the current implementation, which integer type Nim uses depends on many things, but above all, it is not guaranteed to match the type used in intptr_t even if their definitions broadly aim to achieve the same thing in both nim and c.

This causes problems when trying to interop/importc with code that uses intptr_t* and similar pointers, since this may cause a type-based aliasing violation - on some platforms, intptr_t will be typedefed to C int, long or long long depending on the memory model, and even if int* and long* are of the same size, it is not valid to access the same memory location via them - when there's a mismatch, platform-dependent violations happen.

There are a few ways this can be addressed:

  • use intptr_t and uintptr_t for Nim int and uint and document this in the manual - this can be conditioned on the use of a C99+ compiler and revert back to the currenty method for older c standards
  • expose cintptr_t and uintptr_t as new integer types similar to cint - at that point, preferably all stdint.h types would be exposed like this
  • both :)

Alternatives

No response

Examples

No response

Backwards Compatibility

No response

Links

No response

@Araq
Copy link
Member

Araq commented Jan 14, 2025

Well but currently we are compatible with the C types that are more widely used than intptr_t and uintptr_t. The type based aliasing causes troubles either way but there is no evidence we wouldn't introduce even more of this problem with intptr_t. size_t is much more common than uintptr_t too.

@arnetheduck
Copy link
Contributor Author

arnetheduck commented Jan 15, 2025

no evidence we wouldn't introduce even more of this problem

uh, the aim here is to ensure that nim code uses the same type as C that it's interacting with, so as to avoid avoidable type aliasing problems - that's broadly done using the same types in nim and C so I don't understand this comment really. You don't introduce problems by using the same type, you introduce them by trying to use the existing nim types which are lacking in this regard.

When a C api uses intptr_t, or intptr_t* in its API today, it is not possible to import it into Nim using the standard nim types offered by the language - intptr_t, uintptr_t (and ptrdiff_t for that matter which has been around even longer) are all part of the C standard since time immemorial - since nim arbitrarily chooses to expose some of these standard C types, I don't see why the support should not be made complete? Of course, libraries that need them can do it themselves but this is a clear and obvious omission from nim's otherwise solid C interop story.

The only question is how, really, and one option is to simply make nim int/uint interoperable by default - I'm not entirely convinced it's the right option, but I can't formulate any strong arguments against it either - there's a nuance in the C definition of these types where it in theory allows a larger type to be used - this nuance would be one reason to go with cintptr_t instead.

@Araq
Copy link
Member

Araq commented Jan 15, 2025

Well let me repeat it more clearly. I have no idea if mapping int to intptr_t is better or worse than mapping it to ssize_t likewise for the unsigned variants (where it is an even bigger question since size_t is much more common than uintptr_t).

@arnetheduck
Copy link
Contributor Author

size_t is defined as the type for array indexing, ie it can be smaller than a type for pointers on machines with segmented memory because it only needs to cover the needs of a single object in memory - it used to be the same with 16-bit array segments vs "full" 32-bit pointers where size_t would be 16 bits while intptr_t would be 32 bits.

If nim is to maintain the sizeof(pointer) == sizeof(int) guarantee on all such systems, intptr_t would be the type for it.

@Araq
Copy link
Member

Araq commented Jan 15, 2025

Even in C's spec size_t is used 429 times whereas uintptr_t is used 11 times: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3220.pdf

Also looking at this document size_t and the like are defined to be type aliases, they are not additional core types. This makes the aliasing rules between e.g long int and ptrdiff_t impossible to determine reliably in C.

@arnetheduck
Copy link
Contributor Author

arnetheduck commented Jan 15, 2025

uintptr_t is used 11 times

well, it's not a vote - it's either "it can be done" or "it cannot be done" - the lack of intptr_t makes it impossible to correctly import libraries that use types from the the C spec with full coverage - that's what this issue is about: the lack of tools to correctly import libraries that use intptr_t.

Also: the correct thing to do here is probably both: use intptr_t for Nim int as a "practical and portable implementation option" and add cintptr_t et al to the std lib dedicated to the purpose of importing C things. This allows C imports to be correct and provides spec freedom for Nim.

@Araq
Copy link
Member

Araq commented Jan 15, 2025

Alright.

@arnetheduck
Copy link
Contributor Author

(as a side note, sizeof(int) == 16 is gonna be insanely expensive when such systems hit mainstream 😱)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants