Reference implementations of PQC
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

110 line
3.0 KiB

  1. """
  2. Checks that the implementation does not make use of boolean operations (==, <=, !, etc)
  3. in assignments or function calls.
  4. """
  5. import os
  6. import pytest
  7. import helpers
  8. import pqclean
  9. import pycparser
  10. def setup_module():
  11. if not(os.path.exists(os.path.join('pycparser', '.git'))):
  12. print("Please run `git submodule update --init`")
  13. class ForbiddenLineVisitor(pycparser.c_ast.NodeVisitor):
  14. def __init__(self):
  15. self.errors = []
  16. def visit_Assignment(self, node):
  17. v = ForbiddenOpVisitor();
  18. v.visit(node.rvalue)
  19. self.errors.extend(v.errors)
  20. def visit_Decl(self, node):
  21. if node.init:
  22. v = ForbiddenOpVisitor();
  23. v.visit(node.init)
  24. self.errors.extend(v.errors)
  25. def visit_FuncCall(self, node):
  26. if node.args:
  27. v = ForbiddenOpVisitor();
  28. v.visit(node.args)
  29. self.errors.extend(v.errors)
  30. class ForbiddenOpVisitor(pycparser.c_ast.NodeVisitor):
  31. def __init__(self):
  32. self.errors = []
  33. def visit_BinaryOp(self, node):
  34. v = ForbiddenOpVisitor();
  35. v.visit(node.left)
  36. self.errors.extend(v.errors)
  37. if node.op in ['<', '<=', '>', '>=', '==', '!=', '&&', '||']:
  38. err = "\n {} at {c.file}:{c.line}:{c.column}".format(node.op, c=node.coord)
  39. self.errors.append(err)
  40. v = ForbiddenOpVisitor();
  41. v.visit(node.right)
  42. self.errors.extend(v.errors)
  43. def visit_UnaryOp(self, node):
  44. if node.op == '!':
  45. err = "\n {} at {c.file}:{c.line}:{c.column}".format(node.op, c=node.coord)
  46. self.errors.append(err)
  47. v = ForbiddenOpVisitor();
  48. v.visit(node.expr)
  49. self.errors.extend(v.errors)
  50. def visit_TernaryOp(self, node):
  51. err = "\n ternary operator at {c.file}:{c.line}:{c.column}".format(c=node.coord)
  52. self.errors.append(err)
  53. @pytest.mark.parametrize(
  54. 'implementation',
  55. pqclean.Scheme.all_implementations(),
  56. ids=str,
  57. )
  58. @helpers.skip_windows()
  59. @helpers.filtered_test
  60. def test_boolean(implementation):
  61. errors = []
  62. for fname in os.listdir(implementation.path()):
  63. if not fname.endswith(".c"):
  64. continue
  65. tdir, _ = os.path.split(os.path.realpath(__file__))
  66. ast = pycparser.parse_file(
  67. os.path.join(implementation.path(), fname),
  68. use_cpp=True,
  69. cpp_path='cc', # not all platforms link cpp correctly; cc -E works
  70. cpp_args=[
  71. '-E',
  72. '-std=c99',
  73. '-nostdinc', # pycparser cannot deal with e.g. __attribute__
  74. '-I{}'.format(os.path.join(tdir, "../common")),
  75. # necessary to mock e.g. <stdint.h>
  76. '-I{}'.format(
  77. os.path.join(tdir, 'pycparser/utils/fake_libc_include')),
  78. ]
  79. )
  80. v = ForbiddenLineVisitor()
  81. v.visit(ast)
  82. errors.extend(v.errors)
  83. if errors:
  84. raise AssertionError(
  85. "Prohibited use of boolean operations in assignment or function call" +
  86. "".join(errors)
  87. )
  88. if __name__ == "__main__":
  89. import sys
  90. pytest.main(sys.argv)