Skip to content

Commit

Permalink
Switch to allowedNames and blockedNames using regular expressions (
Browse files Browse the repository at this point in the history
…#43)

* Explicitly allowed names use regex

* Use `allowedNames` and `blockedNames` and combine logic

* Update README.md
  • Loading branch information
lithiumtoast authored Jan 20, 2025
1 parent 37c7d31 commit 0b8ec5a
Show file tree
Hide file tree
Showing 27 changed files with 229 additions and 245 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ Note that the internals of the C library is irrelevant and to which this list do
||Function-like macros <sup>5</sup>|
||Object-like macros <sup>2, 6, 7</sup>|

<sup>1</sup>: When declaring your external functions or variables, do set the default visibility explictly. This is necessary because `c2ffi` is configured to have the visibiity set to hidden when using `libclang` via the flag `-fvisibility=hidden` so that only the strict subset of functions and variables intended for FFI are extracted. Most C libraries will have an `API_DECL` macro object defined which can be redefined to also set the visibility. See [ffi_helper.h](src/c/production/ffi_helper/include/ffi_helper.h) for an example in C. You can also use the config `.json` file to define tyour `API_DECL` macro object.
<sup>1</sup>: When declaring your external functions or variables, do set the default visibility explictly. This is necessary because `c2ffi` is configured to have the visibiity set to hidden when using `libclang` via the flag `-fvisibility=hidden` so that only the strict subset of functions and variables intended for FFI are extracted. Most C libraries will have an `API_DECL` macro object defined which can be redefined to also set the visibility. See [ffi_helper.h](src/c/production/ffi_helper/include/ffi_helper.h) for an example in C. You can also use the config `.json` file to define your `API_DECL` macro object.

Bad
```c
Expand Down Expand Up @@ -294,7 +294,7 @@ Acceptable
#define BUFFER_SIZE 1024 // Type is int16_t
```

<sup>7</sup>: Types must be explicitly transtive to a function extern, variable extern, or macro-object so that they can be included as part of the FFI. If this is not the case, then the type is not used in the FFI and will not be extracted.
<sup>7</sup>: Types other than enums must be explicitly transtive to a function extern, variable extern, or macro-object so that they can be included as part of the FFI. If this is not the case, then the type is not used in the FFI and will not be extracted.

### Platforms

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
"ignoredIncludeFiles": [
"../../../production/ffi_helper/include/ffi_helper.h"
],
"includedNames": [
"enum_implicit"
"allowedNames": [
"enum_dangling"
],
"targetPlatforms": {
"windows": {
Expand Down
8 changes: 8 additions & 0 deletions src/c/tests/enums/enum_dangling/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#include <stdio.h>
#include "ffi_helper.h"

// NOTE: This enum is not found in any function, variable, or macro object; it's dangling.
enum enum_dangling {
ENUM_IMPLICIT_VALUE0 = 0,
ENUM_IMPLICIT_VALUE1 = 255
} enum_dangling;
2 changes: 1 addition & 1 deletion src/c/tests/enums/enum_week_day/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ typedef enum enum_week_day {
_ENUM_WEEK_DAY_MAX = 6
} enum_week_day;

FFI_API_DECL enum_week_day enum_week_day;
FFI_API_DECL enum_week_day variable_1;
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
"ignoredIncludeFiles": [
"../../../production/ffi_helper/include/ffi_helper.h"
],
"ignoredNames": [
"blockedNames": [
"function_not_allowed",
"function_ignored*"
"function_blocked_.*"
],
"targetPlatforms": {
"windows": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ FFI_API_DECL void function_not_allowed()
{
}

FFI_API_DECL void function_ignored1()
FFI_API_DECL void function_blocked_1()
{
}

FFI_API_DECL void function_ignored2()
FFI_API_DECL void function_blocked_2()
{
}
12 changes: 0 additions & 12 deletions src/c/tests/functions/function_implicit_enum/main.c

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
"ignoredIncludeFiles": [
"../../../production/ffi_helper/include/ffi_helper.h"
],
"ignoredNames": [
"blockedNames": [
"MACRO_OBJECT_NOT_ALLOWED",
"MACRO_OBJECT_IGNORED*"
"MACRO_OBJECT_BLOCKED_.*"
],
"targetPlatforms": {
"windows": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
"ignoredIncludeFiles": [
"../../../production/ffi_helper/include/ffi_helper.h"
],
"ignoredNames": [
"blockedNames": [
"variable_not_allowed",
"variable_ignored*"
"variable_blocked_.*"
],
"targetPlatforms": {
"windows": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@
FFI_API_DECL int variable_allowed;
FFI_API_DECL int variable_not_allowed;

FFI_API_DECL int variable_ignored_1;
FFI_API_DECL int variable_ignored_2;
FFI_API_DECL int variable_blocked_1;
FFI_API_DECL int variable_blocked_2;
41 changes: 20 additions & 21 deletions src/cs/production/c2ffi.Tool/Extract/Explore/ExploreContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -131,22 +131,6 @@ public NodeInfo CreateNodeInfoVariable(clang.CXCursor clangCursor)
return nodeInfo;
}

public NodeInfo CreateNodeInfoExplicitlyIncluded(CNodeKind nodeKind, clang.CXCursor clangCursor)
{
var clangCursorName = clangCursor.Spelling();
var clangCursorType = clang.clang_getCursorType(clangCursor);
var clangTypeInfo = ClangTypeInfoProvider.GetTypeInfo(clangCursorType);

var nodeInfo = CreateNodeInfo(
nodeKind,
clangCursorName,
clangTypeInfo.Name,
clangCursor,
clangTypeInfo.ClangType,
null);
return nodeInfo;
}

public NodeInfo CreateNodeInfoRecordNested(
CNodeKind nodeKind,
string typeName,
Expand All @@ -166,6 +150,23 @@ public NodeInfo CreateNodeInfoRecordNested(
return nodeInfo;
}

public NodeInfo CreateNodeInfo(clang.CXCursor clangCursor)
{
var clangCursorName = clangCursor.Spelling();

var clangCursorType = clang.clang_getCursorType(clangCursor);
var clangTypeInfo = ClangTypeInfoProvider.GetTypeInfo(clangCursorType);

var nodeInfo = CreateNodeInfo(
clangTypeInfo.NodeKind,
clangCursorName,
clangTypeInfo.Name,
clangCursor,
clangTypeInfo.ClangType,
null);
return nodeInfo;
}

public void Dispose()
{
ParseContext.Dispose();
Expand Down Expand Up @@ -304,12 +305,10 @@ private CType VisitTypeInternal(
return type;
}

foreach (var regex in ParseContext.InputSanitized.IgnoreNameRegexes)
var isBlocked = !ParseContext.InputSanitized.IsNameAllowed(typeName);
if (isBlocked)
{
if (regex.IsMatch(typeName))
{
return type;
}
return type;
}

var info = CreateNodeInfo(type.NodeKind, type.Name, type.Name, clangCursor, clangType, parentInfo);
Expand Down
38 changes: 12 additions & 26 deletions src/cs/production/c2ffi.Tool/Extract/Explore/Explorer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,15 +61,15 @@ private void VisitTranslationUnit(ExploreContext exploreContext, ParseContext pa
VisitFunctions(exploreContext, parseContext);
VisitVariables(exploreContext, parseContext);
VisitMacroObjects(exploreContext, parseContext);
VisitExplicitIncludedNames(exploreContext, parseContext);
VisitEnums(exploreContext, parseContext);

LogVisitedTranslationUnit(parseContext.FilePath);
}

private void VisitFunctions(ExploreContext exploreContext, ParseContext parseContext)
{
var functionCursors = parseContext.GetExternalFunctions(parseContext);
foreach (var cursor in functionCursors)
var cursors = parseContext.GetExternalFunctions(parseContext);
foreach (var cursor in cursors)
{
VisitFunction(exploreContext, cursor);
}
Expand All @@ -83,8 +83,8 @@ private void VisitFunction(ExploreContext context, clang.CXCursor clangCursor)

private void VisitVariables(ExploreContext context, ParseContext parseContext)
{
var variableCursors = parseContext.GetExternalVariables();
foreach (var cursor in variableCursors)
var cursors = parseContext.GetExternalVariables();
foreach (var cursor in cursors)
{
VisitVariable(context, cursor);
}
Expand All @@ -98,8 +98,8 @@ private void VisitVariable(ExploreContext context, clang.CXCursor clangCursor)

private void VisitMacroObjects(ExploreContext context, ParseContext parseContext)
{
var macroObjectCursors = parseContext.GetMacroObjects();
foreach (var cursor in macroObjectCursors)
var cursors = parseContext.GetMacroObjects();
foreach (var cursor in cursors)
{
VisitMacroObject(context, cursor);
}
Expand All @@ -111,32 +111,18 @@ private void VisitMacroObject(ExploreContext context, clang.CXCursor clangCursor
context.TryEnqueueNode(info);
}

private void VisitExplicitIncludedNames(ExploreContext exploreContext, ParseContext parseContext)
private void VisitEnums(ExploreContext context, ParseContext parseContext)
{
var cursors = parseContext.GetExplicitlyIncludedNamedCursors();
var cursors = parseContext.GetEnums();
foreach (var cursor in cursors)
{
VisitExplicitlyIncludedName(exploreContext, cursor);
VisitEnum(context, cursor);
}
}

private void VisitExplicitlyIncludedName(ExploreContext context, clang.CXCursor clangCursor)
private void VisitEnum(ExploreContext context, clang.CXCursor clangCursor)
{
#pragma warning disable IDE0072
var nodeKind = clangCursor.kind switch
#pragma warning restore IDE0072
{
clang.CXCursorKind.CXCursor_EnumDecl => CNodeKind.Enum,
_ => CNodeKind.Unknown
};

if (nodeKind == CNodeKind.Unknown)
{
// TODO: Add more allowed kinds to explicitly included names
return;
}

var info = context.CreateNodeInfoExplicitlyIncluded(nodeKind, clangCursor);
var info = context.CreateNodeInfo(clangCursor);
context.TryEnqueueNode(info);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ namespace c2ffi.Extract;

public sealed class InputSanitizedTargetPlatform
{
private readonly ImmutableArray<Regex> _allowedNameRegexRegexes;

private readonly ImmutableArray<Regex> _blockedNameRegexRegexes;

public string OutputFilePath { get; init; } = string.Empty;

public TargetPlatform TargetPlatform { get; init; } = TargetPlatform.Unknown;
Expand All @@ -25,12 +29,57 @@ public sealed class InputSanitizedTargetPlatform

public bool IsEnabledFindSystemHeaders { get; init; }

public ImmutableHashSet<string> IncludedNames { get; init; } = ImmutableHashSet<string>.Empty;

public ImmutableArray<Regex> IgnoreNameRegexes { get; init; } = ImmutableArray<Regex>.Empty;
public InputSanitizedTargetPlatform(
ImmutableArray<Regex> allowedNameRegexes,
ImmutableArray<Regex> blockedNameRegexes)
{
_allowedNameRegexRegexes = allowedNameRegexes;
_blockedNameRegexRegexes = blockedNameRegexes;
}

public override string ToString()
{
return $"{{ TargetPlatform: {TargetPlatform}, OutputFilePath: {OutputFilePath} }}";
}

public bool IsNameAllowed(string name)
{
bool isAllowed;
if (_allowedNameRegexRegexes.IsDefaultOrEmpty)
{
isAllowed = true;
}
else
{
isAllowed = false;
foreach (var regex in _allowedNameRegexRegexes)
{
if (regex.IsMatch(name))
{
isAllowed = true;
break;
}
}
}

bool isBlocked;
if (_blockedNameRegexRegexes.IsDefaultOrEmpty)
{
isBlocked = false;
}
else
{
isBlocked = false;
foreach (var regex in _blockedNameRegexRegexes)
{
if (regex.IsMatch(name))
{
isBlocked = true;
break;
}
}
}

return isAllowed && !isBlocked;
}
}
17 changes: 9 additions & 8 deletions src/cs/production/c2ffi.Tool/Extract/InputSanitizer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,10 @@ private InputSanitizedTargetPlatform SanitizeTargetPlatformInput(
string inputFilePath)
{
var targetPlatform = new TargetPlatform(targetPlatformString);
var options = new InputSanitizedTargetPlatform

var allowedNameRegexes = AllowedNameRegexes(input);
var blockedNamesRegexes = BlockedNameRegexes(input);
var options = new InputSanitizedTargetPlatform(allowedNameRegexes, blockedNamesRegexes)
{
TargetPlatform = targetPlatform,
OutputFilePath = OutputFilePath(input, targetPlatformString),
Expand All @@ -118,9 +121,7 @@ private InputSanitizedTargetPlatform SanitizeTargetPlatformInput(
IgnoredIncludeFiles = IgnoredIncludeFiles(input, targetPlatformInput),
MacroObjectDefines = ClangDefines(input, targetPlatformInput),
AdditionalArguments = ClangArguments(targetPlatformInput),
IsEnabledFindSystemHeaders = input.IsEnabledAutomaticallyFindSystemHeaders ?? true,
IncludedNames = IncludedNames(input),
IgnoreNameRegexes = IgnoredNames(input),
IsEnabledFindSystemHeaders = input.IsEnabledAutomaticallyFindSystemHeaders ?? true
};

return options;
Expand Down Expand Up @@ -171,14 +172,14 @@ private ImmutableArray<string> ClangArguments(InputUnsanitizedTargetPlatform tar
return SanitizeStrings(targetPlatformInput.ClangArguments);
}

private ImmutableArray<Regex> IgnoredNames(InputUnsanitized input)
private ImmutableArray<Regex> BlockedNameRegexes(InputUnsanitized input)
{
return SanitizeRegexes(input.IgnoredNames);
return SanitizeRegexes(input.BlockedNames);
}

private ImmutableHashSet<string> IncludedNames(InputUnsanitized input)
private ImmutableArray<Regex> AllowedNameRegexes(InputUnsanitized input)
{
return [.. SanitizeStrings(input.IncludedNames)];
return SanitizeRegexes(input.AllowedNames);
}

private string SanitizeOutputDirectoryPath(
Expand Down
14 changes: 8 additions & 6 deletions src/cs/production/c2ffi.Tool/Extract/InputUnsanitized.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,16 +75,18 @@ public sealed class InputUnsanitized : ToolUnsanitizedInput
public ImmutableArray<string>? OpaqueTypeNames { get; set; }

/// <summary>
/// Gets or sets the name of Clang cursors / Clang types that are not allowed.
/// Gets or sets the regular expressions to match the names of Clang cursors or Clang types that are blocked
/// from being explored.
/// </summary>
[JsonPropertyName("ignoredNames")]
public ImmutableArray<string>? IgnoredNames { get; set; }
[JsonPropertyName("blockedNames")]
public ImmutableArray<string>? BlockedNames { get; set; }

/// <summary>
/// Gets or sets the name of Clang cursors / Clang types that are explicitly allowed.
/// Gets or sets the regular expressions to match the names of Clang cursors or Clang types that are allowed
/// to be explored.
/// </summary>
[JsonPropertyName("includedNames")]
public ImmutableArray<string>? IncludedNames { get; set; }
[JsonPropertyName("allowedNames")]
public ImmutableArray<string>? AllowedNames { get; set; }

/// <summary>
/// Gets or sets the target platform configurations for extracting the FFIs per desktop host
Expand Down
Loading

0 comments on commit 0b8ec5a

Please sign in to comment.